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