Salome HOME
Merge from V6_5_BR 05/06/2012
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESHGUI_MeshInfo.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24
25 #include "SMESHGUI_MeshInfo.h"
26
27 #include "SMESH_Actor.h"
28 #include "SMESHGUI.h"
29 #include "SMESHGUI_IdValidator.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include "SMDSAbs_ElementType.hxx"
33 #include "SMDS_Mesh.hxx"
34
35 #include <LightApp_SelectionMgr.h>
36 #include <SUIT_OverrideCursor.h>
37 #include <SUIT_ResourceMgr.h>
38 #include <SVTK_ViewWindow.h>
39
40 #include <SALOMEDSClient_Study.hxx>
41
42 #include <QApplication>
43 #include <QButtonGroup>
44 #include <QGridLayout>
45 #include <QHBoxLayout>
46 #include <QHeaderView>
47 #include <QItemDelegate>
48 #include <QKeyEvent>
49 #include <QLabel>
50 #include <QLineEdit>
51 #include <QPushButton>
52 #include <QRadioButton>
53 #include <QTabWidget>
54 #include <QTextBrowser>
55 #include <QVBoxLayout>
56
57 #include "utilities.h"
58
59 #include <SALOMEconfig.h>
60 #include CORBA_SERVER_HEADER(GEOM_Gen)
61
62 const int SPACING  = 6;
63 const int MARGIN   = 9;
64 const int MAXITEMS = 10;
65
66 /*!
67   \class SMESHGUI_MeshInfo
68   \brief Base mesh information widget
69   
70   Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
71 */
72
73 /*!
74   \brief Constructor.
75   \param parent parent widget
76 */
77 SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
78   : QFrame( parent ), myWidgets( iElementsEnd )
79 {
80   setFrameStyle( StyledPanel | Sunken );
81
82   QGridLayout* l = new QGridLayout( this );
83   l->setMargin( MARGIN );
84   l->setSpacing( SPACING );
85
86   // object
87   QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
88   QLabel* aName        = createField();
89   aName->setMinimumWidth( 150 );
90   QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
91   QLabel* aObj         = createField();
92   aObj->setMinimumWidth( 150 );
93   myWidgets[0] << aNameLab << aName;
94   myWidgets[1] << aObjLab  << aObj;
95
96   // nodes
97   QWidget* aNodesLine  = createLine();
98   QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
99   QLabel*  aNodes      = createField();
100   myWidgets[2] << aNodesLine;
101   myWidgets[3] << aNodesLab << aNodes;
102
103   // elements
104   QWidget* aElemLine   = createLine();
105   QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),  this );
106   QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),     this );
107   QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),    this );
108   QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ), this );
109   myWidgets[4] << aElemLine;
110   myWidgets[5] << aElemLab << aElemTotal << aElemLin << aElemQuad;
111
112   // ... 0D elements
113   QWidget* a0DLine     = createLine();
114   QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
115   QLabel*  a0DTotal    = createField();
116   myWidgets[6] << a0DLine;
117   myWidgets[7] << a0DLab << a0DTotal;
118
119   // ... 1D elements
120   QWidget* a1DLine     = createLine();
121   QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
122   QLabel*  a1DTotal    = createField();
123   QLabel*  a1DLin      = createField();
124   QLabel*  a1DQuad     = createField();
125   myWidgets[8] << a1DLine;
126   myWidgets[9] << a1DLab << a1DTotal << a1DLin << a1DQuad;
127
128   // ... 2D elements
129   QWidget* a2DLine     = createLine();
130   QLabel*  a2DLab      = new QLabel( tr( "2D_LAB" ), this );
131   QLabel*  a2DTotal    = createField();
132   QLabel*  a2DLin      = createField();
133   QLabel*  a2DQuad     = createField();
134   QLabel*  a2DTriLab   = new QLabel( tr( "TRIANGLES_LAB" ), this );
135   QLabel*  a2DTriTotal = createField();
136   QLabel*  a2DTriLin   = createField();
137   QLabel*  a2DTriQuad  = createField();
138   QLabel*  a2DQuaLab   = new QLabel( tr( "QUADRANGLES_LAB" ), this );
139   QLabel*  a2DQuaTotal = createField();
140   QLabel*  a2DQuaLin   = createField();
141   QLabel*  a2DQuaQuad  = createField();
142   QLabel*  a2DPolLab   = new QLabel( tr( "POLYGONS_LAB" ), this );
143   QLabel*  a2DPolTotal = createField();
144   myWidgets[10] << a2DLine;
145   myWidgets[11] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad;
146   myWidgets[12] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad;
147   myWidgets[13] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad;
148   myWidgets[14] << a2DPolLab << a2DPolTotal;
149
150   // ... 3D elements
151   QWidget* a3DLine     = createLine();
152   QLabel*  a3DLab      = new QLabel( tr( "3D_LAB" ), this );
153   QLabel*  a3DTotal    = createField();
154   QLabel*  a3DLin      = createField();
155   QLabel*  a3DQuad     = createField();
156   QLabel*  a3DTetLab   = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
157   QLabel*  a3DTetTotal = createField();
158   QLabel*  a3DTetLin   = createField();
159   QLabel*  a3DTetQuad  = createField();
160   QLabel*  a3DHexLab   = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
161   QLabel*  a3DHexTotal = createField();
162   QLabel*  a3DHexLin   = createField();
163   QLabel*  a3DHexQuad  = createField();
164   QLabel*  a3DPyrLab   = new QLabel( tr( "PYRAMIDS_LAB" ), this );
165   QLabel*  a3DPyrTotal = createField();
166   QLabel*  a3DPyrLin   = createField();
167   QLabel*  a3DPyrQuad  = createField();
168   QLabel*  a3DPriLab   = new QLabel( tr( "PRISMS_LAB" ), this );
169   QLabel*  a3DPriTotal = createField();
170   QLabel*  a3DPriLin   = createField();
171   QLabel*  a3DPriQuad  = createField();
172   QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
173   QLabel*  a3DHexPriTotal = createField();
174   QLabel*  a3DPolLab   = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
175   QLabel*  a3DPolTotal = createField();
176   myWidgets[15] << a3DLine;
177   myWidgets[16] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad;
178   myWidgets[17] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
179   myWidgets[18] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad;
180   myWidgets[19] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
181   myWidgets[20] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
182   myWidgets[21] << a3DHexPriLab << a3DHexPriTotal;
183   myWidgets[22] << a3DPolLab << a3DPolTotal;
184
185   myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
186   myLoadBtn->setAutoDefault( true );
187   connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
188   
189   setFontAttributes( aNameLab,   Bold );
190   setFontAttributes( aObjLab,    Bold );
191   setFontAttributes( aNodesLab,  Bold );
192   setFontAttributes( aElemLab,   Bold );
193   setFontAttributes( aElemTotal, Italic );
194   setFontAttributes( aElemLin,   Italic );
195   setFontAttributes( aElemQuad,  Italic );
196   setFontAttributes( a0DLab,     Bold );
197   setFontAttributes( a1DLab,     Bold );
198   setFontAttributes( a2DLab,     Bold );
199   setFontAttributes( a3DLab,     Bold );
200
201   l->addWidget( aNameLab,     0, 0 );
202   l->addWidget( aName,        0, 1, 1, 3 );
203   l->addWidget( aObjLab,      1, 0 );
204   l->addWidget( aObj,         1, 1, 1, 3 );
205   l->addWidget( aNodesLine,   2, 0, 1, 4 );
206   l->addWidget( aNodesLab,    3, 0 );
207   l->addWidget( aNodes,       3, 1 );
208   l->addWidget( aElemLine,    4, 0, 1, 4 );
209   l->addWidget( aElemLab,     5, 0 );
210   l->addWidget( aElemTotal,   5, 1 );
211   l->addWidget( aElemLin,     5, 2 );
212   l->addWidget( aElemQuad,    5, 3 );
213   l->addWidget( a0DLine,      6, 1, 1, 3 );
214   l->addWidget( a0DLab,       7, 0 );
215   l->addWidget( a0DTotal,     7, 1 );
216   l->addWidget( a1DLine,      8, 1, 1, 3 );
217   l->addWidget( a1DLab,       9, 0 );
218   l->addWidget( a1DTotal,     9, 1 );
219   l->addWidget( a1DLin,       9, 2 );
220   l->addWidget( a1DQuad,      9, 3 );
221   l->addWidget( a2DLine,     10, 1, 1, 3 );
222   l->addWidget( a2DLab,      11, 0 );
223   l->addWidget( a2DTotal,    11, 1 );
224   l->addWidget( a2DLin,      11, 2 );
225   l->addWidget( a2DQuad,     11, 3 );
226   l->addWidget( a2DTriLab,   12, 0 );
227   l->addWidget( a2DTriTotal, 12, 1 );
228   l->addWidget( a2DTriLin,   12, 2 );
229   l->addWidget( a2DTriQuad,  12, 3 );
230   l->addWidget( a2DQuaLab,   13, 0 );
231   l->addWidget( a2DQuaTotal, 13, 1 );
232   l->addWidget( a2DQuaLin,   13, 2 );
233   l->addWidget( a2DQuaQuad,  13, 3 );
234   l->addWidget( a2DPolLab,   14, 0 );
235   l->addWidget( a2DPolTotal, 14, 1 );
236   l->addWidget( a3DLine,     15, 1, 1, 3 );
237   l->addWidget( a3DLab,      16, 0 );
238   l->addWidget( a3DTotal,    16, 1 );
239   l->addWidget( a3DLin,      16, 2 );
240   l->addWidget( a3DQuad,     16, 3 );
241   l->addWidget( a3DTetLab,   17, 0 );
242   l->addWidget( a3DTetTotal, 17, 1 );
243   l->addWidget( a3DTetLin,   17, 2 );
244   l->addWidget( a3DTetQuad,  17, 3 );
245   l->addWidget( a3DHexLab,   18, 0 );
246   l->addWidget( a3DHexTotal, 18, 1 );
247   l->addWidget( a3DHexLin,   18, 2 );
248   l->addWidget( a3DHexQuad,  18, 3 );
249   l->addWidget( a3DPyrLab,   19, 0 );
250   l->addWidget( a3DPyrTotal, 19, 1 );
251   l->addWidget( a3DPyrLin,   19, 2 );
252   l->addWidget( a3DPyrQuad,  19, 3 );
253   l->addWidget( a3DPriLab,   20, 0 );
254   l->addWidget( a3DPriTotal, 20, 1 );
255   l->addWidget( a3DPriLin,   20, 2 );
256   l->addWidget( a3DPriQuad,  20, 3 );
257   l->addWidget( a3DHexPriLab,   21, 0 );
258   l->addWidget( a3DHexPriTotal, 21, 1 );
259   l->addWidget( a3DPolLab,   22, 0 );
260   l->addWidget( a3DPolTotal, 22, 1 );
261   l->addWidget( myLoadBtn,   23, 1, 1, 3 );
262   l->setColumnStretch( 0, 0 );
263   l->setColumnStretch( 1, 5 );
264   l->setColumnStretch( 2, 5 );
265   l->setColumnStretch( 3, 5 );
266   l->setRowStretch( 23, 5 );
267
268   clear();
269 }
270
271 /*!
272   \brief Destructor
273 */
274 SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
275 {
276 }
277
278 /*!
279   \brief Show information on the mesh object.
280   \param obj object being processed (mesh, sub-mesh, group, ID source)
281 */
282 void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
283 {
284   clear();
285   if ( !CORBA::is_nil( obj ) ) {
286     _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
287     if ( sobj ) 
288       myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
289     SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
290     SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
291     SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
292     if ( !aMesh->_is_nil() ) {
293       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) );
294     }
295     else if ( !aSubMesh->_is_nil() ) {
296       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) );
297     }
298     else if ( !aGroup->_is_nil() ) {
299       QString objType;
300       switch( aGroup->GetType() ) {
301       case SMESH::NODE:
302         objType = tr( "OBJECT_GROUP_NODES" );
303         break;
304       case SMESH::EDGE:
305         objType = tr( "OBJECT_GROUP_EDGES" );
306         break;
307       case SMESH::FACE:
308         objType = tr( "OBJECT_GROUP_FACES" );
309         break;
310       case SMESH::VOLUME:
311         objType = tr( "OBJECT_GROUP_VOLUMES" );
312         break;
313       case SMESH::ELEM0D:
314         objType = tr( "OBJECT_GROUP_0DELEMS" );
315         break;
316       default:
317         objType = tr( "OBJECT_GROUP" );
318         break;
319       }
320       myWidgets[iObject][iSingle]->setProperty( "text", objType );
321     }
322     SMESH::long_array_var info = obj->GetMeshInfo();
323     myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
324     myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
325     long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
326     myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ) );
327     myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) );
328     myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) );
329     long nbTriangles   = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle];
330     long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
331     long nb2DLinear    = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
332     long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
333     myWidgets[i2D][iTotal]               ->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) );
334     myWidgets[i2D][iLinear]              ->setProperty( "text", QString::number( nb2DLinear ) );
335     myWidgets[i2D][iQuadratic]           ->setProperty( "text", QString::number( nb2DQuadratic ) );
336     myWidgets[i2DTriangles][iTotal]      ->setProperty( "text", QString::number( nbTriangles ) );
337     myWidgets[i2DTriangles][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) );
338     myWidgets[i2DTriangles][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) );
339     myWidgets[i2DQuadrangles][iTotal]    ->setProperty( "text", QString::number( nbQuadrangles ) );
340     myWidgets[i2DQuadrangles][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) );
341     myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle] ));
342     myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
343     long nbTetrahedrons = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
344     long nbHexahedrons  = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
345     long nbPyramids     = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
346     long nbPrisms       = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta];
347     long nb3DLinear     = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
348     long nb3DQuadratic  = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
349     myWidgets[i3D][iTotal]                ->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) );
350     myWidgets[i3D][iLinear]               ->setProperty( "text", QString::number( nb3DLinear ) );
351     myWidgets[i3D][iQuadratic]            ->setProperty( "text", QString::number( nb3DQuadratic ) );
352     myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", QString::number( nbTetrahedrons ) );
353     myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
354     myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) );
355     myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", QString::number( nbHexahedrons ) );
356     myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) );
357     myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] ) );
358     myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", QString::number( nbPyramids ) );
359     myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) );
360     myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) );
361     myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", QString::number( nbPrisms ) );
362     myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) );
363     myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) );
364     myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
365     myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
366
367     // before full loading from study file, type of elements in a sub-mesh can't be defined
368     // in some cases
369     bool infoOK = obj->IsMeshInfoCorrect();
370     myLoadBtn->setVisible( !infoOK );
371     if ( !infoOK )
372     {
373       // two options:
374       // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
375       // 2. No info at all (for a group on geom or filter)
376       bool hasAnyInfo = false;
377       for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
378         hasAnyInfo = info[i];
379       if ( hasAnyInfo ) // believe it is a sub-mesh
380       {
381         if ( nb2DLinear + nb2DQuadratic > 0 )
382         {
383           myWidgets[i2D][iLinear]              ->setProperty( "text", "?" );
384           myWidgets[i2D][iQuadratic]           ->setProperty( "text", "?" );
385           myWidgets[i2DTriangles][iTotal]      ->setProperty( "text", "?" );
386           myWidgets[i2DTriangles][iLinear]     ->setProperty( "text", "?" );
387           myWidgets[i2DTriangles][iQuadratic]  ->setProperty( "text", "?" );
388           myWidgets[i2DQuadrangles][iTotal]    ->setProperty( "text", "?" );
389           myWidgets[i2DQuadrangles][iLinear]   ->setProperty( "text", "?" );
390           myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", "?" );
391           myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", "?" );
392         }
393         else if ( nb3DLinear + nb3DQuadratic > 0 )
394         {
395           myWidgets[i3D][iLinear]               ->setProperty( "text", "?" );
396           myWidgets[i3D][iQuadratic]            ->setProperty( "text", "?" );
397           myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", "?" );
398           myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", "?" );
399           myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" );
400           myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", "?" );
401           myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", "?" );
402           myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" );
403           myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", "?" );
404           myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", "?" );
405           myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", "?" );
406           myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", "?" );
407           myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", "?" );
408           myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", "?" );
409           myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", "?" );
410           myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", "?" );
411         }
412       }
413       else
414       {
415         myWidgets[iNodes][iTotal]             ->setProperty( "text", "?" );
416         myWidgets[i0D][iTotal]                ->setProperty( "text", "?" );
417         myWidgets[i1D][iTotal]                ->setProperty( "text", "?" );
418         myWidgets[i1D][iLinear]               ->setProperty( "text", "?" );
419         myWidgets[i1D][iQuadratic]            ->setProperty( "text", "?" );
420         myWidgets[i2D][iTotal]                ->setProperty( "text", "?" );
421         myWidgets[i2D][iLinear]               ->setProperty( "text", "?" );
422         myWidgets[i2D][iQuadratic]            ->setProperty( "text", "?" );
423         myWidgets[i2DTriangles][iTotal]       ->setProperty( "text", "?" );
424         myWidgets[i2DTriangles][iLinear]      ->setProperty( "text", "?" );
425         myWidgets[i2DTriangles][iQuadratic]   ->setProperty( "text", "?" );
426         myWidgets[i2DQuadrangles][iTotal]     ->setProperty( "text", "?" );
427         myWidgets[i2DQuadrangles][iLinear]    ->setProperty( "text", "?" );
428         myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", "?" );
429         myWidgets[i2DPolygons][iTotal]        ->setProperty( "text", "?" );
430         myWidgets[i3D][iTotal]                ->setProperty( "text", "?" );
431         myWidgets[i3D][iLinear]               ->setProperty( "text", "?" );
432         myWidgets[i3D][iQuadratic]            ->setProperty( "text", "?" );
433         myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", "?" );
434         myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", "?" );
435         myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" );
436         myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", "?" );
437         myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", "?" );
438         myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" );
439         myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", "?" );
440         myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", "?" );
441         myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", "?" );
442         myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", "?" );
443         myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", "?" );
444         myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", "?" );
445         myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", "?" );
446         myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", "?" );
447       }
448     }
449   }
450 }
451
452 /*!
453   \brief Load mesh from a study file
454 */
455 void SMESHGUI_MeshInfo::loadMesh()
456 {
457   SUIT_OverrideCursor wc;
458
459   SALOME_ListIO selected;
460   SMESHGUI::selectionMgr()->selectedObjects( selected );
461
462   if ( selected.Extent() == 1 ) {
463     Handle(SALOME_InteractiveObject) IO = selected.First();
464     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
465     if ( !CORBA::is_nil( obj ) ) {
466       SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
467       if ( !mesh->_is_nil() )
468       {
469         mesh->Load();
470         showInfo( obj );
471       }
472     }
473   }
474 }
475
476 /*!
477   \brief Reset the widget to the initial state (nullify all fields).
478 */
479 void SMESHGUI_MeshInfo::clear()
480 {
481   myWidgets[iName][iSingle]->setProperty( "text", QString() );
482   myWidgets[iObject][iSingle]->setProperty( "text", QString() );
483   myWidgets[iNodes][iTotal]->setProperty( "text", QString::number( 0 ) );
484   myWidgets[i0D][iTotal]->setProperty( "text", QString::number( 0 ) );
485   myWidgets[i1D][iTotal]->setProperty( "text", QString::number( 0 ) );
486   myWidgets[i1D][iLinear]->setProperty( "text", QString::number( 0 ) );
487   myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( 0 ) );
488   myWidgets[i2D][iTotal]->setProperty( "text", QString::number( 0 ) );
489   myWidgets[i2D][iLinear]->setProperty( "text", QString::number( 0 ) );
490   myWidgets[i2D][iQuadratic]->setProperty( "text", QString::number( 0 ) );
491   myWidgets[i2DTriangles][iTotal]->setProperty( "text", QString::number( 0 ) );
492   myWidgets[i2DTriangles][iLinear]->setProperty( "text", QString::number( 0 ) );
493   myWidgets[i2DTriangles][iQuadratic]->setProperty( "text", QString::number( 0 ) );
494   myWidgets[i2DQuadrangles][iTotal]->setProperty( "text", QString::number( 0 ) );
495   myWidgets[i2DQuadrangles][iLinear]->setProperty( "text", QString::number( 0 ) );
496   myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( 0 ) );
497   myWidgets[i2DPolygons][iTotal]->setProperty( "text", QString::number( 0 ) );
498   myWidgets[i3D][iTotal]->setProperty( "text", QString::number( 0 ) );
499   myWidgets[i3D][iLinear]->setProperty( "text", QString::number( 0 ) );
500   myWidgets[i3D][iQuadratic]->setProperty( "text", QString::number( 0 ) );
501   myWidgets[i3DTetrahedrons][iTotal]->setProperty( "text", QString::number( 0 ) );
502   myWidgets[i3DTetrahedrons][iLinear]->setProperty( "text", QString::number( 0 ) );
503   myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) );
504   myWidgets[i3DHexahedrons][iTotal]->setProperty( "text", QString::number( 0 ) );
505   myWidgets[i3DHexahedrons][iLinear]->setProperty( "text", QString::number( 0 ) );
506   myWidgets[i3DHexahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) );
507   myWidgets[i3DPyramids][iTotal]->setProperty( "text", QString::number( 0 ) );
508   myWidgets[i3DPyramids][iLinear]->setProperty( "text", QString::number( 0 ) );
509   myWidgets[i3DPyramids][iQuadratic]->setProperty( "text", QString::number( 0 ) );
510   myWidgets[i3DPrisms][iTotal]->setProperty( "text", QString::number( 0 ) );
511   myWidgets[i3DPrisms][iLinear]->setProperty( "text", QString::number( 0 ) );
512   myWidgets[i3DPrisms][iQuadratic]->setProperty( "text", QString::number( 0 ) );
513   myWidgets[i3DHexaPrisms][iTotal]->setProperty( "text", QString::number( 0 ) );
514   myWidgets[i3DPolyhedrons][iTotal]->setProperty( "text", QString::number( 0 ) );
515 }
516
517 /*!
518   \brief Create info field
519   \return new info field
520 */
521 QLabel* SMESHGUI_MeshInfo::createField()
522 {
523   QLabel* lab = new QLabel( this );
524   lab->setFrameStyle( StyledPanel | Sunken );
525   lab->setAlignment( Qt::AlignCenter );
526   lab->setAutoFillBackground( true );
527   QPalette pal = lab->palette();
528   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
529   lab->setPalette( pal );
530   lab->setMinimumWidth( 70 );
531   return lab;
532 }
533
534 /*!
535   \brief Create horizontal rule.
536   \return new line object
537 */
538 QWidget* SMESHGUI_MeshInfo::createLine()
539 {
540   QFrame* line = new QFrame( this );
541   line->setFrameStyle( HLine | Sunken );
542   return line;
543 }
544
545 /*!
546   \brief Change widget font attributes (bold, italic, ...).
547   \param w widget
548   \param attr font attributes (XORed flags)
549   \param val value to be set to attributes
550 */
551 void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
552 {
553   if ( w && attr ) {
554     QFont f = w->font();
555     if ( attr & Bold   ) f.setBold( val );
556     if ( attr & Italic ) f.setItalic( val );
557     w->setFont( f );
558   }
559 }
560
561 /*!
562   \brief Show/hide group(s) of fields.
563   \param start beginning of the block
564   \param end end of the block
565   \param on visibility flag
566 */
567 void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
568 {
569   start = qMax( 0, start );
570   end   = qMin( end, (int)iElementsEnd );
571   for ( int i = start; i < end; i++ ) {
572     wlist wl = myWidgets[i];
573     foreach ( QWidget* w, wl ) w->setVisible( on );
574   }
575 }
576
577 /*!
578   \class SMESHGUI_ElemInfo
579   \brief Base class for the mesh element information widget.
580 */
581
582 /*!
583   \brief Constructor
584   \param parent parent widget
585 */
586 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
587 : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
588 {
589   myFrame = new QWidget( this );
590   myExtra = new QWidget( this );
591   myCurrent = new QLabel( "10/43 items shown", myExtra );
592   myCurrent->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
593   myPrev = new QPushButton( tr( "<<" ), myExtra );
594   myNext = new QPushButton( tr( ">>" ), myExtra );
595   QHBoxLayout* hbl = new QHBoxLayout( myExtra );
596   hbl->setContentsMargins( 0, SPACING, 0, 0 );
597   hbl->setSpacing( SPACING );
598   hbl->addStretch();
599   hbl->addWidget( myCurrent );
600   hbl->addWidget( myPrev );
601   hbl->addWidget( myNext );
602   QVBoxLayout* vbl = new QVBoxLayout( this );
603   vbl->setMargin( 0 );
604   vbl->setSpacing( 0 );
605   vbl->addWidget( myFrame );
606   vbl->addWidget( myExtra );
607   connect( myPrev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
608   connect( myNext, SIGNAL( clicked() ), this, SLOT( showNext() ) );
609   clear();
610 }
611
612 /*!
613   \brief Destructor
614 */
615 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
616 {
617 }
618
619 /*!
620   \brief Set mesh data source (actor)
621   \param actor mesh object actor
622 */
623 void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
624 {
625   if ( myActor != actor ) {
626     myActor = actor;
627     myIsElement = -1;
628     clear();
629   }
630 }
631
632 /*!
633   \brief Show mesh element information
634   \param id mesh node / element ID
635   \param isElem show mesh element information if \c true or mesh node information if \c false
636 */
637 void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
638 {
639   QSet<long> ids;
640   ids << id;
641   showInfo( ids, isElem );
642 }
643
644 /*!
645   \brief Show mesh element information
646   \param ids mesh nodes / elements identifiers
647   \param isElem show mesh element information if \c true or mesh node information if \c false
648 */
649 void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
650 {
651   QList<long> newIds = ids.toList();
652   qSort( newIds );
653   if ( myIDs == newIds && myIsElement == isElem ) return;
654
655   myIDs = newIds;
656   myIsElement = isElem;
657   myIndex = 0;
658   updateControls();
659   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
660 }
661
662 /*!
663   \brief Clear mesh element information widget
664 */
665 void SMESHGUI_ElemInfo::clear()
666 {
667   myIDs.clear();
668   myIndex = 0;
669   clearInternal();
670   updateControls();
671 }
672
673 /*!
674   \brief Get central area widget
675   \return central widget
676 */
677 QWidget* SMESHGUI_ElemInfo::frame() const
678 {
679   return myFrame;
680 }
681
682 /*!
683   \brief Get actor
684   \return actor being used
685 */
686 SMESH_Actor* SMESHGUI_ElemInfo::actor() const
687 {
688   return myActor;
689 }
690
691 /*!
692   \brief Get current info mode.
693   \return \c true if mesh element information is shown or \c false if node information is shown
694 */
695 bool SMESHGUI_ElemInfo::isElements() const
696 {
697   return myIsElement;
698 }
699
700 /*!
701   \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
702   \brief Show information on the specified nodes / elements
703
704   This function is to be redefined in sub-classes.
705
706   \param ids nodes / elements identifiers information is to be shown on
707 */
708
709 /*!
710   \brief Internal clean-up (reset widget)
711 */
712 void SMESHGUI_ElemInfo::clearInternal()
713 {
714 }
715
716 /*!
717   \brief Get node connectivity
718   \param node mesh node
719   \return node connectivity map
720 */
721 SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
722 {
723   Connectivity elmap;
724   if ( node ) {
725     SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
726     while ( it && it->more() ) {
727       const SMDS_MeshElement* ne = it->next();
728       elmap[ ne->GetType() ] << ne->GetID();
729     }
730   }
731   return elmap;
732 }
733
734 /*!
735   \brief Format connectivity data to string representation
736   \param connectivity connetivity map
737   \param type element type
738   \return string representation of the connectivity
739 */
740 QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
741 {
742   QStringList str;
743   if ( connectivity.contains( type ) ) {
744     QList<int> elements = connectivity[ type ];
745     qSort( elements );
746     foreach( int id, elements )
747       str << QString::number( id );
748   }
749   return str.join( " " );
750 }
751
752 /*!
753   \brief Calculate gravity center of the mesh element
754   \param element mesh element
755 */
756 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
757 {
758   XYZ xyz;
759   if ( element ) {
760     SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
761     while ( nodeIt->more() ) {
762       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
763       xyz.add( node->X(), node->Y(), node->Z() );
764     }
765     xyz.divide( element->NbNodes() );
766   }
767   return xyz;
768 }
769
770 /*!
771   \brief This slot is called from "Show Previous" button click.
772   Shows information on the previous group of the items.
773 */
774 void SMESHGUI_ElemInfo::showPrevious()
775 {
776   myIndex = qMax( 0, myIndex-1 );
777   updateControls();
778   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
779 }
780
781 /*!
782   \brief This slot is called from "Show Next" button click.
783   Shows information on the next group of the items.
784 */
785 void SMESHGUI_ElemInfo::showNext()
786 {
787   myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
788   updateControls();
789   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
790 }
791
792 /*!
793   \brief Update widgets state
794 */
795 void SMESHGUI_ElemInfo::updateControls()
796 {
797   myExtra->setVisible( myIDs.count() > MAXITEMS );
798   myCurrent->setText( tr( "X_FROM_Y_ITEMS_SHOWN" ).arg( myIndex*MAXITEMS+1 ).arg(qMin(myIndex*MAXITEMS+MAXITEMS, myIDs.count())).arg( myIDs.count() ) );
799   myPrev->setEnabled( myIndex > 0 );
800   myNext->setEnabled( (myIndex+1)*MAXITEMS < myIDs.count() );
801 }
802
803 /*!
804   \class SMESHGUI_SimpleElemInfo
805   \brief Represents mesh element information in the simple text area.
806 */
807
808 /*!
809   \brief Constructor
810   \param parent parent widget
811 */
812 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
813 : SMESHGUI_ElemInfo( parent )
814 {
815   myInfo = new QTextBrowser( frame() );
816   QVBoxLayout* l = new QVBoxLayout( frame() );
817   l->setMargin( 0 );
818   l->addWidget( myInfo );
819 }
820
821 /*!
822   \brief Show mesh element information
823   \param ids mesh nodes / elements identifiers
824 */
825 void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
826 {
827   clearInternal();
828   
829   if ( actor() ) {
830     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
831     foreach ( long id, ids ) {
832       if ( !isElements() ) {
833         //
834         // show node info
835         //
836         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
837         if ( !e ) return;
838         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
839         
840         // node ID
841         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( tr( "NODE" ) ).arg( id ) );
842         // separator
843         myInfo->append( "" );
844         // coordinates
845         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ).
846                         arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
847                         arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
848                         arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
849         // separator
850         myInfo->append( "" );
851         // connectivity
852         Connectivity connectivity = nodeConnectivity( node );
853         if ( !connectivity.isEmpty() ) {
854           myInfo->append( QString( "<b>%1:</b>" ).arg( tr( "CONNECTIVITY" ) ) );
855           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
856           if ( !con.isEmpty() )
857             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
858           con = formatConnectivity( connectivity, SMDSAbs_Edge );
859           if ( !con.isEmpty() )
860             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
861           con = formatConnectivity( connectivity, SMDSAbs_Face );
862           if ( !con.isEmpty() )
863             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
864           con = formatConnectivity( connectivity, SMDSAbs_Volume );
865           if ( !con.isEmpty() )
866             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
867         }
868         else {
869           myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
870         }
871       }
872       else {
873         //
874         // show element info
875         // 
876         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
877         if ( !e ) return;
878         
879         // element ID && type
880         QString stype;
881         switch( e->GetType() ) {
882         case SMDSAbs_0DElement:
883           stype = tr( "0D ELEMENT" ); break;
884         case SMDSAbs_Edge:
885           stype = tr( "EDGE" ); break;
886         case SMDSAbs_Face:
887           stype = tr( "FACE" ); break;
888         case SMDSAbs_Volume:
889           stype = tr( "VOLUME" ); break;
890         default: 
891           break;
892         }
893         if ( stype.isEmpty() ) return;
894         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( stype ).arg( id ) );
895         // separator
896         myInfo->append( "" );
897         // geometry type
898         QString gtype;
899         switch( e->GetEntityType() ) {
900         case SMDSEntity_Triangle:
901         case SMDSEntity_Quad_Triangle:
902           gtype = tr( "TRIANGLE" ); break;
903         case SMDSEntity_Quadrangle:
904         case SMDSEntity_Quad_Quadrangle:
905         case SMDSEntity_BiQuad_Quadrangle:
906           gtype = tr( "QUADRANGLE" ); break;
907         case SMDSEntity_Polygon:
908         case SMDSEntity_Quad_Polygon:
909           gtype = tr( "POLYGON" ); break;
910         case SMDSEntity_Tetra:
911         case SMDSEntity_Quad_Tetra:
912           gtype = tr( "TETRAHEDRON" ); break;
913         case SMDSEntity_Pyramid:
914         case SMDSEntity_Quad_Pyramid:
915           gtype = tr( "PYRAMID" ); break;
916         case SMDSEntity_Hexa:
917         case SMDSEntity_Quad_Hexa:
918         case SMDSEntity_TriQuad_Hexa:
919           gtype = tr( "HEXAHEDRON" ); break;
920         case SMDSEntity_Penta:
921         case SMDSEntity_Quad_Penta:
922           gtype = tr( "PRISM" ); break;
923         case SMDSEntity_Hexagonal_Prism:
924           gtype = tr( "HEX_PRISM" ); break;
925         case SMDSEntity_Polyhedra:
926         case SMDSEntity_Quad_Polyhedra:
927           gtype = tr( "POLYHEDRON" ); break;
928         default: 
929           break;
930         }
931         if ( !gtype.isEmpty() )
932           myInfo->append( QString( "<b>%1:</b> %2" ).arg( tr( "TYPE" ) ).arg( gtype ) );
933         // quadratic flag and gravity center (any element except 0D)
934         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
935           // quadratic flag
936           myInfo->append( QString( "<b>%1?</b> %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) );
937           // separator
938           myInfo->append( "" );
939           // gravity center
940           XYZ gc = gravityCenter( e );
941           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
942         }
943         // separator
944         myInfo->append( "" );
945         // connectivity
946         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
947         for ( int idx = 1; nodeIt->more(); idx++ ) {
948           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
949           // node number and ID
950           myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
951           // node coordinates
952           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ).
953                           arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
954                           arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
955                           arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
956           // node connectivity
957           Connectivity connectivity = nodeConnectivity( node );
958           if ( !connectivity.isEmpty() ) {
959             myInfo->append( QString( "<b>%1:</b>" ).arg( tr( "CONNECTIVITY" ) ) );
960             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
961             if ( !con.isEmpty() )
962               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) );
963             con = formatConnectivity( connectivity, SMDSAbs_Edge );
964             if ( !con.isEmpty() )
965               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "EDGES" ) ).arg( con ) );
966             con = formatConnectivity( connectivity, SMDSAbs_Face );
967             if ( !con.isEmpty() )
968               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "FACES" ) ).arg( con ) );
969             con = formatConnectivity( connectivity, SMDSAbs_Volume );
970             if ( !con.isEmpty() )
971               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUMES" ) ).arg( con ) );
972           }
973           else {
974             myInfo->append( QString( "<b>%1</b>" ).arg( tr( "FREE_NODE" ) ).arg( id ) );
975           }
976         }
977       }
978       // separator
979       if ( ids.count() > 1 ) {
980         myInfo->append( "" );
981         myInfo->append( "------" );
982         myInfo->append( "" );
983       }
984     }
985   }
986 }
987
988 /*!
989   \brief Internal clean-up (reset widget)
990 */
991 void SMESHGUI_SimpleElemInfo::clearInternal()
992 {
993   myInfo->clear();
994 }
995
996 /*!
997   \class SMESHGUI_TreeElemInfo::ItemDelegate
998   \brief Item delegate for tree mesh info widget
999   \internal
1000 */
1001 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1002 {
1003 public:
1004   ItemDelegate( QObject* );
1005   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1006 };
1007
1008 /*!
1009   \brief Constructor
1010   \internal
1011 */
1012 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1013 {
1014 }
1015
1016 /*!
1017   \brief Create item editor widget
1018   \internal
1019 */
1020 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1021 {
1022   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1023   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1024   return w;
1025 }
1026
1027 /*!
1028   \class SMESHGUI_TreeElemInfo
1029   \brief Represents mesh element information in the tree-like form.
1030 */
1031
1032 /*!
1033   \brief Constructor
1034   \param parent parent widget
1035 */
1036 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1037 : SMESHGUI_ElemInfo( parent )
1038 {
1039   myInfo = new QTreeWidget( frame() );
1040   myInfo->setColumnCount( 2 );
1041   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1042   myInfo->header()->setStretchLastSection( true );
1043   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1044   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1045   QVBoxLayout* l = new QVBoxLayout( frame() );
1046   l->setMargin( 0 );
1047   l->addWidget( myInfo );
1048 }
1049
1050 /*!
1051   \brief Show mesh element information
1052   \param ids mesh nodes / elements identifiers
1053 */
1054 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1055 {
1056   clearInternal();
1057
1058   if ( actor() ) {
1059     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1060     foreach ( long id, ids ) {
1061       if ( !isElements() ) {
1062         //
1063         // show node info
1064         //
1065         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1066         if ( !e ) return;
1067         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1068       
1069         // node ID
1070         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1071         nodeItem->setText( 0, tr( "NODE" ) );
1072         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1073         // coordinates
1074         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1075         coordItem->setText( 0, tr( "COORDINATES" ) );
1076         QTreeWidgetItem* xItem = createItem( coordItem );
1077         xItem->setText( 0, "X" );
1078         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1079         QTreeWidgetItem* yItem = createItem( coordItem );
1080         yItem->setText( 0, "Y" );
1081         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1082         QTreeWidgetItem* zItem = createItem( coordItem );
1083         zItem->setText( 0, "Z" );
1084         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1085         // connectivity
1086         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1087         conItem->setText( 0, tr( "CONNECTIVITY" ) );
1088         Connectivity connectivity = nodeConnectivity( node );
1089         if ( !connectivity.isEmpty() ) {
1090           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1091           if ( !con.isEmpty() ) {
1092             QTreeWidgetItem* i = createItem( conItem );
1093             i->setText( 0, tr( "0D_ELEMENTS" ) );
1094             i->setText( 1, con );
1095           }
1096           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1097           if ( !con.isEmpty() ) {
1098             QTreeWidgetItem* i = createItem( conItem );
1099             i->setText( 0, tr( "EDGES" ) );
1100             i->setText( 1, con );
1101           }
1102           con = formatConnectivity( connectivity, SMDSAbs_Face );
1103           if ( !con.isEmpty() ) {
1104             QTreeWidgetItem* i = createItem( conItem );
1105             i->setText( 0, tr( "FACES" ) );
1106             i->setText( 1, con );
1107           }
1108           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1109           if ( !con.isEmpty() ) {
1110             QTreeWidgetItem* i = createItem( conItem );
1111             i->setText( 0, tr( "VOLUMES" ) );
1112             i->setText( 1, con );
1113           }
1114         }
1115         else {
1116           conItem->setText( 1, tr( "FREE_NODE" ) );
1117         }
1118       }
1119       else {
1120         //
1121         // show element info
1122         // 
1123         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1124         if ( !e ) return;
1125         
1126         // element ID && type
1127         QString stype;
1128         switch( e->GetType() ) {
1129         case SMDSAbs_0DElement:
1130           stype = tr( "0D ELEMENT" ); break;
1131         case SMDSAbs_Edge:
1132           stype = tr( "EDGE" ); break;
1133         case SMDSAbs_Face:
1134           stype = tr( "FACE" ); break;
1135         case SMDSAbs_Volume:
1136           stype = tr( "VOLUME" ); break;
1137         default: 
1138           break;
1139         }
1140         if ( stype.isEmpty() ) return;
1141         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1142         elemItem->setText( 0, stype );
1143         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1144         // geometry type
1145         QString gtype;
1146         switch( e->GetEntityType() ) {
1147         case SMDSEntity_Triangle:
1148         case SMDSEntity_Quad_Triangle:
1149           gtype = tr( "TRIANGLE" ); break;
1150         case SMDSEntity_Quadrangle:
1151         case SMDSEntity_Quad_Quadrangle:
1152         case SMDSEntity_BiQuad_Quadrangle:
1153           gtype = tr( "QUADRANGLE" ); break;
1154         case SMDSEntity_Polygon:
1155         case SMDSEntity_Quad_Polygon:
1156           gtype = tr( "POLYGON" ); break;
1157         case SMDSEntity_Tetra:
1158         case SMDSEntity_Quad_Tetra:
1159           gtype = tr( "TETRAHEDRON" ); break;
1160         case SMDSEntity_Pyramid:
1161         case SMDSEntity_Quad_Pyramid:
1162           gtype = tr( "PYRAMID" ); break;
1163         case SMDSEntity_Hexa:
1164         case SMDSEntity_Quad_Hexa:
1165         case SMDSEntity_TriQuad_Hexa:
1166           gtype = tr( "HEXAHEDRON" ); break;
1167         case SMDSEntity_Penta:
1168         case SMDSEntity_Quad_Penta:
1169           gtype = tr( "PRISM" ); break;
1170         case SMDSEntity_Hexagonal_Prism:
1171           gtype = tr( "HEX_PRISM" ); break;
1172         case SMDSEntity_Polyhedra:
1173         case SMDSEntity_Quad_Polyhedra:
1174           gtype = tr( "POLYHEDRON" ); break;
1175         default: 
1176           break;
1177         }
1178         if ( !gtype.isEmpty() ) {
1179           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1180           typeItem->setText( 0, tr( "TYPE" ) );
1181           typeItem->setText( 1, gtype );
1182         }
1183         // quadratic flag and gravity center (any element except 0D)
1184         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Last ) {
1185           // quadratic flag
1186           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1187           quadItem->setText( 0, tr( "QUADRATIC" ) );
1188           quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) );
1189           // gravity center
1190           XYZ gc = gravityCenter( e );
1191           QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
1192           gcItem->setText( 0, tr( "GRAVITY_CENTER" ) );
1193           QTreeWidgetItem* xItem = createItem( gcItem );
1194           xItem->setText( 0, "X" );
1195           xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1196           QTreeWidgetItem* yItem = createItem( gcItem );
1197           yItem->setText( 0, "Y" );
1198           yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1199           QTreeWidgetItem* zItem = createItem( gcItem );
1200           zItem->setText( 0, "Z" );
1201           zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1202         }
1203         // connectivity
1204         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1205         conItem->setText( 0, tr( "CONNECTIVITY" ) );
1206         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1207         for ( int idx = 1; nodeIt->more(); idx++ ) {
1208           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1209           // node number and ID
1210           QTreeWidgetItem* nodeItem = createItem( conItem, Bold );
1211           nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
1212           nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
1213           nodeItem->setExpanded( false );
1214           // node coordinates
1215           QTreeWidgetItem* coordItem = createItem( nodeItem );
1216           coordItem->setText( 0, tr( "COORDINATES" ) );
1217           QTreeWidgetItem* xItem = createItem( coordItem );
1218           xItem->setText( 0, "X" );
1219           xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1220           QTreeWidgetItem* yItem = createItem( coordItem );
1221           yItem->setText( 0, "Y" );
1222           yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1223           QTreeWidgetItem* zItem = createItem( coordItem );
1224           zItem->setText( 0, "Z" );
1225           zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1226           // node connectivity
1227           QTreeWidgetItem* nconItem = createItem( nodeItem );
1228           nconItem->setText( 0, tr( "CONNECTIVITY" ) );
1229           Connectivity connectivity = nodeConnectivity( node );
1230           if ( !connectivity.isEmpty() ) {
1231             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1232             if ( !con.isEmpty() ) {
1233               QTreeWidgetItem* i = createItem( nconItem );
1234               i->setText( 0, tr( "0D_ELEMENTS" ) );
1235               i->setText( 1, con );
1236             }
1237             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1238             if ( !con.isEmpty() ) {
1239               QTreeWidgetItem* i = createItem( nconItem );
1240               i->setText( 0, tr( "EDGES" ) );
1241               i->setText( 1, con );
1242             }
1243             con = formatConnectivity( connectivity, SMDSAbs_Face );
1244             if ( !con.isEmpty() ) {
1245               QTreeWidgetItem* i = createItem( nconItem );
1246               i->setText( 0, tr( "FACES" ) );
1247               i->setText( 1, con );
1248             }
1249             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1250             if ( !con.isEmpty() ) {
1251               QTreeWidgetItem* i = createItem( nconItem );
1252               i->setText( 0, tr( "VOLUMES" ) );
1253               i->setText( 1, con );
1254             }
1255           }
1256         }
1257       }
1258     }
1259   }
1260 }
1261
1262 /*!
1263   \brief Internal clean-up (reset widget)
1264 */
1265 void SMESHGUI_TreeElemInfo::clearInternal()
1266 {
1267   myInfo->clear();
1268   myInfo->repaint();
1269 }
1270
1271 /*!
1272   \brief Create new tree item.
1273   \param parent parent tree widget item
1274   \param flags item flag
1275   \return new tree widget item
1276 */
1277 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
1278 {
1279   QTreeWidgetItem* item;
1280   if ( parent )
1281     item = new QTreeWidgetItem( parent );
1282   else
1283     item = new QTreeWidgetItem( myInfo );
1284
1285   item->setFlags( item->flags() | Qt::ItemIsEditable );
1286
1287   QFont f = item->font( 0 );
1288   f.setBold( true );
1289   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
1290     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
1291       item->setFont( i, f );
1292   }
1293
1294   item->setExpanded( true );
1295   return item;
1296 }
1297
1298 /*!
1299   \class GrpComputor
1300   \brief Mesh information computer
1301   \internal
1302   
1303   The class is created for different computation operation. Currently it is used
1304   to compute number of underlying nodes for the groups.
1305 */
1306
1307 /*!
1308   \brief Contructor
1309 */
1310 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
1311   : QObject( parent ), myItem( item )
1312 {
1313   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
1314 }
1315
1316 /*!
1317   \brief Compute function
1318 */
1319 void GrpComputor::compute()
1320 {
1321   if ( !CORBA::is_nil( myGroup ) && myItem ) {
1322     QTreeWidgetItem* item = myItem;
1323     myItem = 0;
1324     int nbNodes = myGroup->GetNumberOfNodes();
1325     item->treeWidget()->removeItemWidget( item, 1 );
1326     item->setText( 1, QString::number( nbNodes ));
1327   }
1328 }
1329
1330 /*!
1331   \class SMESHGUI_AddInfo
1332   \brief The wigdet shows additional information on the mesh object.
1333 */
1334
1335 /*!
1336   \brief Constructor
1337   \param parent parent widget
1338 */
1339 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
1340 : QTreeWidget( parent )
1341 {
1342   setColumnCount( 2 );
1343   header()->setStretchLastSection( true );
1344   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1345   header()->hide();
1346 }
1347
1348 /*!
1349   \brief Destructor
1350 */
1351 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
1352 {
1353 }
1354
1355 /*!
1356   \brief Show additional information on the selected object
1357   \param obj object being processed (mesh, sub-mesh, group, ID source)
1358 */
1359 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
1360 {
1361   myComputors.clear();
1362
1363   clear();
1364
1365   if ( CORBA::is_nil( obj ) ) return;
1366
1367   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
1368   if ( !sobj ) return;
1369
1370   // name
1371   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
1372   nameItem->setText( 0, tr( "NAME" ) );
1373   nameItem->setText( 1, sobj->GetName().c_str() );
1374   
1375   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
1376   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
1377   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
1378   
1379   if ( !aMesh->_is_nil() )
1380     meshInfo( aMesh, nameItem );
1381   else if ( !aSubMesh->_is_nil() )
1382     subMeshInfo( aSubMesh, nameItem );
1383   else if ( !aGroup->_is_nil() )
1384     groupInfo( aGroup.in(), nameItem );
1385 }
1386
1387 /*!
1388   \brief Create new tree item.
1389   \param parent parent tree widget item
1390   \param flags item flag
1391   \return new tree widget item
1392 */
1393 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
1394 {
1395   QTreeWidgetItem* item;
1396
1397   if ( parent )
1398     item = new QTreeWidgetItem( parent );
1399   else
1400     item = new QTreeWidgetItem( this );
1401
1402   //item->setFlags( item->flags() | Qt::ItemIsEditable );
1403
1404   QFont f = item->font( 0 );
1405   f.setBold( true );
1406   for ( int i = 0; i < columnCount(); i++ ) {
1407     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
1408       item->setFont( i, f );
1409   }
1410
1411   item->setExpanded( true );
1412   return item;
1413 }
1414
1415 /*!
1416   \brief Show mesh info
1417   \param mesh mesh object
1418   \param parent parent tree item
1419 */
1420 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
1421 {
1422   // type
1423   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
1424   SALOME_MED::MedFileInfo* inf = mesh->GetMEDFileInfo();
1425   QTreeWidgetItem* typeItem = createItem( parent, Bold );
1426   typeItem->setText( 0, tr( "TYPE" ) );
1427   if ( !CORBA::is_nil( shape ) ) {
1428     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
1429     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
1430     if ( sobj ) {
1431       QTreeWidgetItem* gobjItem = createItem( typeItem );
1432       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1433       gobjItem->setText( 1, sobj->GetName().c_str() );
1434     }
1435   }
1436   else if ( strlen( (char*)inf->fileName ) > 0 ) {
1437     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
1438     QTreeWidgetItem* fileItem = createItem( typeItem );
1439     fileItem->setText( 0, tr( "FILE_NAME" ) );
1440     fileItem->setText( 1, (char*)inf->fileName );
1441   }
1442   else {
1443     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
1444   }
1445   
1446   // groups
1447   SMESH::ListOfGroups_var groups = mesh->GetGroups();
1448   QTreeWidgetItem* itemGroups  = 0;
1449   QMap<int, QTreeWidgetItem*> grpItems;
1450   for ( int i = 0; i < groups->length(); i++ ) {
1451     SMESH::SMESH_GroupBase_var grp = groups[i];
1452     if ( CORBA::is_nil( grp ) ) continue;
1453     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
1454     if ( !grpSObj ) continue;
1455
1456     int grpType = grp->GetType();
1457
1458     if ( !itemGroups ) {
1459       itemGroups = createItem( parent, Bold | All );
1460       itemGroups->setText( 0, tr( "GROUPS" ) );
1461     }
1462
1463     if ( grpItems.find( grpType ) == grpItems.end() ) {
1464       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
1465       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
1466       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
1467     }
1468   
1469     // group name
1470     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
1471     grpNameItem->setText( 0, grpSObj->GetName().c_str() );
1472
1473     // group info
1474     groupInfo( grp.in(), grpNameItem );
1475   }
1476
1477   // sub-meshes
1478   SMESH::submesh_array_var subMeshes = mesh->GetSubMeshes();
1479   QTreeWidgetItem* itemSubMeshes = 0;
1480   QMap<int, QTreeWidgetItem*> smItems;
1481   for ( int i = 0; i < subMeshes->length(); i++ ) {
1482     SMESH::SMESH_subMesh_var sm = subMeshes[i];
1483     if ( CORBA::is_nil( sm ) ) continue;
1484     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
1485     if ( !smSObj ) continue;
1486     
1487     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
1488     if ( CORBA::is_nil(gobj ) ) continue;
1489     
1490     int smType = gobj->GetShapeType();
1491     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
1492
1493     if ( !itemSubMeshes ) {
1494       itemSubMeshes = createItem( parent, Bold | All );
1495       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
1496     }
1497          
1498     if ( smItems.find( smType ) == smItems.end() ) {
1499       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
1500       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
1501       itemSubMeshes->insertChild( smType, smItems[ smType ] );
1502     }
1503     
1504     // submesh name
1505     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
1506     smNameItem->setText( 0, smSObj->GetName().c_str() );
1507     
1508     // submesh info
1509     subMeshInfo( sm.in(), smNameItem );
1510   }
1511 }
1512
1513 /*!
1514   \brief Show sub-mesh info
1515   \param subMesh sub-mesh object
1516   \param parent parent tree item
1517 */
1518 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
1519 {
1520   bool isShort = parent->parent() != 0;
1521
1522   if ( !isShort ) {
1523     // parent mesh
1524     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
1525     if ( sobj ) {
1526       QTreeWidgetItem* nameItem = createItem( parent, Bold );
1527       nameItem->setText( 0, tr( "PARENT_MESH" ) );
1528       nameItem->setText( 1, sobj->GetName().c_str() );
1529     }
1530   }
1531   
1532   // shape
1533   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
1534   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1535   if ( sobj ) {
1536     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
1537     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1538     gobjItem->setText( 1, sobj->GetName().c_str() );
1539   }
1540 }
1541
1542 /*!
1543   \brief Show group info
1544   \param grp mesh group object
1545   \param parent parent tree item
1546 */
1547 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
1548 {
1549   bool isShort = parent->parent() != 0;
1550
1551   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
1552   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
1553   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
1554
1555   if ( !isShort ) {
1556     // parent mesh
1557     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
1558     if ( sobj ) {
1559       QTreeWidgetItem* nameItem = createItem( parent, Bold );
1560       nameItem->setText( 0, tr( "PARENT_MESH" ) );
1561       nameItem->setText( 1, sobj->GetName().c_str() );
1562     }
1563   }
1564
1565   // type : group on geometry, standalone group, group on filter
1566   QTreeWidgetItem* typeItem = createItem( parent, Bold );
1567   typeItem->setText( 0, tr( "TYPE" ) );
1568   if ( !CORBA::is_nil( aStdGroup ) ) {
1569     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
1570   }
1571   else if ( !CORBA::is_nil( aGeomGroup ) ) {
1572     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
1573     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1574     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1575     if ( sobj ) {
1576       QTreeWidgetItem* gobjItem = createItem( typeItem );
1577       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1578       gobjItem->setText( 1, sobj->GetName().c_str() );
1579     }
1580   }
1581   else if ( !CORBA::is_nil( aFltGroup ) ) {
1582     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
1583   }
1584
1585   if ( !isShort ) {
1586     // entity type
1587     QString etype = tr( "UNKNOWN" );
1588     switch( grp->GetType() ) {
1589     case SMESH::NODE:
1590       etype = tr( "NODE" );
1591       break;
1592     case SMESH::EDGE:
1593       etype = tr( "EDGE" );
1594       break;
1595     case SMESH::FACE:
1596       etype = tr( "FACE" );
1597       break;
1598     case SMESH::VOLUME:
1599       etype = tr( "VOLUME" );
1600       break;
1601     case SMESH::ELEM0D:
1602       etype = tr( "0DELEM" );
1603       break;
1604     default:
1605       break;
1606     }
1607     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
1608     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
1609     etypeItem->setText( 1, etype );
1610   }
1611
1612   // size
1613   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
1614   sizeItem->setText( 0, tr( "SIZE" ) );
1615   sizeItem->setText( 1, QString::number( grp->Size() ) );
1616
1617   // color
1618   SALOMEDS::Color color = grp->GetColor();
1619   QTreeWidgetItem* colorItem = createItem( parent, Bold );
1620   colorItem->setText( 0, tr( "COLOR" ) );
1621   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1622
1623   // nb of underlying nodes
1624   if ( grp->GetType() != SMESH::NODE) {
1625     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
1626     nodesItem->setText( 0, tr( "NB_NODES" ) );
1627     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
1628     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
1629     bool meshLoaded = mesh->IsLoaded();
1630     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
1631     if ( toShowNodes && meshLoaded ) {
1632       // already calculated and up-to-date
1633       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
1634     }
1635     else {
1636       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
1637       setItemWidget( nodesItem, 1, btn );
1638       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
1639       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
1640       myComputors.append( comp );
1641       if ( !meshLoaded )
1642         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
1643     }
1644   }
1645 }
1646
1647 /*!
1648  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
1649  */
1650 void SMESHGUI_AddInfo::changeLoadToCompute()
1651 {
1652   for ( int i = 0; i < myComputors.count(); ++i )
1653   {
1654     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
1655     {
1656       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 )))
1657         btn->setText( tr("COMPUTE"));
1658     }
1659   }
1660 }
1661
1662 /*!
1663   \class SMESHGUI_MeshInfoDlg
1664   \brief Mesh information dialog box
1665 */
1666
1667 /*!
1668   \brief Constructor
1669   \param parent parent widget
1670   \param page specifies the dialog page to be shown at the start-up
1671 */
1672 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
1673 : QDialog( parent ), myActor( 0 )
1674 {
1675   setModal( false );
1676   setAttribute( Qt::WA_DeleteOnClose, true );
1677   setWindowTitle( tr( "MESH_INFO" ) );
1678   setSizeGripEnabled( true );
1679
1680   myTabWidget = new QTabWidget( this );
1681
1682   // base info 
1683
1684   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
1685   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
1686
1687   // elem info 
1688   
1689   QWidget* w = new QWidget( myTabWidget );
1690
1691   myMode = new QButtonGroup( this );
1692   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
1693   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
1694   myMode->button( NodeMode )->setChecked( true );
1695   myID = new QLineEdit( w );
1696   myID->setValidator( new SMESHGUI_IdValidator( this ) );
1697
1698   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
1699   mode = qMin( 1, qMax( 0, mode ) );
1700   
1701   if ( mode == 0 ) 
1702     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
1703   else
1704     myElemInfo = new SMESHGUI_TreeElemInfo( w );
1705
1706   QGridLayout* elemLayout = new QGridLayout( w );
1707   elemLayout->setMargin( MARGIN );
1708   elemLayout->setSpacing( SPACING );
1709   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
1710   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
1711   elemLayout->addWidget( myID, 0, 2 );
1712   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
1713   
1714   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
1715
1716   // additional info
1717
1718   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
1719   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
1720
1721   // buttons
1722
1723   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
1724   okBtn->setAutoDefault( true );
1725   okBtn->setDefault( true );
1726   okBtn->setFocus();
1727   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
1728   helpBtn->setAutoDefault( true );
1729
1730   QHBoxLayout* btnLayout = new QHBoxLayout;
1731   btnLayout->setSpacing( SPACING );
1732   btnLayout->setMargin( 0 );
1733
1734   btnLayout->addWidget( okBtn );
1735   btnLayout->addStretch( 10 );
1736   btnLayout->addWidget( helpBtn );
1737
1738   QVBoxLayout* l = new QVBoxLayout ( this );
1739   l->setMargin( MARGIN );
1740   l->setSpacing( SPACING );
1741   l->addWidget( myTabWidget );
1742   l->addLayout( btnLayout );
1743
1744   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
1745
1746   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
1747   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
1748   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
1749   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
1750   connect( myID,        SIGNAL( textEdited( QString  ) ), this, SLOT( idChanged() ) );
1751   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
1752   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
1753
1754   updateSelection();
1755 }
1756
1757 /*!
1758   \brief Destructor
1759 */
1760 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
1761 {
1762 }
1763
1764 /*!
1765   \brief Show mesh information
1766   \param IO interactive object
1767 */
1768 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
1769 {
1770   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
1771   if ( !CORBA::is_nil( obj ) ) {
1772     myBaseInfo->showInfo( obj );
1773     myAddInfo->showInfo( obj );
1774
1775     myActor = SMESH::FindActorByEntry( IO->getEntry() );
1776     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1777     QString ID;
1778     int nb = 0;
1779     if ( myActor && selector ) {
1780       nb = myMode->checkedId() == NodeMode ? 
1781         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
1782         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
1783     }
1784     myElemInfo->setSource( myActor ) ;
1785     if ( nb > 0 ) {
1786       myID->setText( ID.trimmed() );
1787       QSet<long> ids;
1788       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
1789       foreach ( ID, idTxt )
1790         ids << ID.trimmed().toLong();
1791       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
1792     }
1793     else {
1794       myID->clear();
1795       myElemInfo->clear();
1796     }
1797   }
1798 }
1799
1800 /*!
1801   \brief Perform clean-up actions on the dialog box closing.
1802 */
1803 void SMESHGUI_MeshInfoDlg::reject()
1804 {
1805   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1806   selMgr->clearFilters();
1807   SMESH::SetPointRepresentation( false );
1808   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1809     aViewWindow->SetSelectionMode( ActorSelection );
1810   QDialog::reject();
1811 }
1812
1813 /*!
1814   \brief Process keyboard event
1815   \param e key press event
1816 */
1817 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
1818 {
1819   QDialog::keyPressEvent( e );
1820   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
1821     e->accept();
1822     help();
1823   }
1824 }
1825
1826 /*!
1827   \brief Reactivate dialog box, when mouse pointer goes into it.
1828 */
1829 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
1830 {
1831   activate();
1832 }
1833
1834 /*!
1835   \brief Setup selection mode depending on the current dialog box state.
1836 */
1837 void SMESHGUI_MeshInfoDlg::updateSelection()
1838 {
1839   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
1840
1841   disconnect( selMgr, 0, this, 0 );
1842   selMgr->clearFilters();
1843
1844   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) {
1845     SMESH::SetPointRepresentation( false );
1846     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1847       aViewWindow->SetSelectionMode( ActorSelection );
1848   }
1849   else {
1850     if ( myMode->checkedId() == NodeMode ) {
1851       SMESH::SetPointRepresentation( true );
1852       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1853         aViewWindow->SetSelectionMode( NodeSelection );
1854     }
1855     else {
1856       SMESH::SetPointRepresentation( false );
1857       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1858         aViewWindow->SetSelectionMode( CellSelection );
1859     }
1860   }
1861
1862   QString oldID = myID->text().trimmed();
1863   SMESH_Actor* oldActor = myActor;
1864   myID->clear();
1865   
1866   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1867   updateInfo();
1868   
1869   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
1870     myID->setText( oldID );
1871     idChanged();
1872   }
1873 }
1874
1875 /*!
1876   \brief Show help page
1877 */
1878 void SMESHGUI_MeshInfoDlg::help()
1879 {
1880   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
1881                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
1882                        "mesh_infos_page.html#mesh_element_info_anchor" );
1883 }
1884
1885 /*!
1886   \brief Show mesh information
1887 */
1888 void SMESHGUI_MeshInfoDlg::updateInfo()
1889 {
1890   SUIT_OverrideCursor wc;
1891
1892   SALOME_ListIO selected;
1893   SMESHGUI::selectionMgr()->selectedObjects( selected );
1894
1895   if ( selected.Extent() == 1 ) {
1896     Handle(SALOME_InteractiveObject) IO = selected.First();
1897     showInfo( IO );
1898   }
1899 //   else {
1900 //     myBaseInfo->clear();
1901 //     myElemInfo->clear();
1902 //     myAddInfo->clear();
1903 //   }
1904 }
1905
1906 /*!
1907   \brief Activate dialog box
1908 */
1909 void SMESHGUI_MeshInfoDlg::activate()
1910 {
1911   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
1912   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
1913   myTabWidget->setEnabled( true );
1914   updateSelection();
1915 }
1916
1917 /*!
1918   \brief Deactivate dialog box
1919 */
1920 void SMESHGUI_MeshInfoDlg::deactivate()
1921 {
1922   myTabWidget->setEnabled( false );
1923   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
1924 }
1925
1926 /*!
1927   \brief Called when users switches between node / element modes.
1928 */
1929 void SMESHGUI_MeshInfoDlg::modeChanged()
1930 {
1931   myID->clear();
1932   updateSelection();
1933 }
1934
1935 /*!
1936   \brief Caled when users prints mesh element ID in the corresponding field.
1937 */
1938 void SMESHGUI_MeshInfoDlg::idChanged()
1939 {
1940   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
1941   if ( myActor && selector ) {
1942     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
1943     TColStd_MapOfInteger ID;
1944     QSet<long> ids;
1945     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
1946     foreach ( QString tid, idTxt ) {
1947       long id = tid.trimmed().toLong();
1948       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
1949         myActor->GetObject()->GetMesh()->FindElement( id ) :
1950         myActor->GetObject()->GetMesh()->FindNode( id );
1951       if ( e ) {
1952         ID.Add( id );
1953         ids << id;
1954       }
1955     }
1956     selector->AddOrRemoveIndex( IO, ID, false );
1957     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
1958       aViewWindow->highlight( IO, true, true );
1959     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
1960   }
1961 }