Salome HOME
Merge from V6_main 13/12/2012
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESHGUI_MeshInfo.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24
25 #include "SMESHGUI_MeshInfo.h"
26
27 #include "SMESH_Actor.h"
28 #include "SMESHGUI.h"
29 #include "SMESHGUI_IdValidator.h"
30 #include "SMESHGUI_Utils.h"
31 #include "SMESHGUI_VTKUtils.h"
32 #include "SMDSAbs_ElementType.hxx"
33 #include "SMDS_Mesh.hxx"
34 #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         /*
1109         if( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1110           // separator
1111           myInfo->append( "" );
1112           //shapeID
1113           int shapeID = e->getshapeId();
1114           if ( shapeID > 0 ) {     
1115             QString shapeType;
1116             switch ( actor()->GetObject()->GetMesh()->FindElement( shapeID )->GetType() ) {
1117             case SMDS_TOP_EDGE:   shapeType = tr( "EDGE" ); break;
1118             case SMDS_TOP_FACE:   shapeType = tr( "FACE" ); break;
1119             case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break;
1120             default:              shapeType = tr( "SOLID" );
1121             }     
1122             myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( tr( "Position" ) ).arg( shapeType ).arg( shapeID ) );
1123           }
1124         }
1125         */
1126       }
1127       // separator
1128       if ( ids.count() > 1 ) {
1129         myInfo->append( "" );
1130         myInfo->append( "------" );
1131         myInfo->append( "" );
1132       }
1133     }
1134   }
1135 }
1136
1137 /*!
1138   \brief Internal clean-up (reset widget)
1139 */
1140 void SMESHGUI_SimpleElemInfo::clearInternal()
1141 {
1142   myInfo->clear();
1143 }
1144
1145 /*!
1146   \class SMESHGUI_TreeElemInfo::ItemDelegate
1147   \brief Item delegate for tree mesh info widget
1148   \internal
1149 */
1150 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1151 {
1152 public:
1153   ItemDelegate( QObject* );
1154   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1155 };
1156
1157 /*!
1158   \brief Constructor
1159   \internal
1160 */
1161 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1162 {
1163 }
1164
1165 /*!
1166   \brief Create item editor widget
1167   \internal
1168 */
1169 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1170 {
1171   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1172   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1173   return w;
1174 }
1175
1176 /*!
1177   \class SMESHGUI_TreeElemInfo
1178   \brief Represents mesh element information in the tree-like form.
1179 */
1180
1181 /*!
1182   \brief Constructor
1183   \param parent parent widget
1184 */
1185 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1186 : SMESHGUI_ElemInfo( parent )
1187 {
1188   myInfo = new QTreeWidget( frame() );
1189   myInfo->setColumnCount( 2 );
1190   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1191   myInfo->header()->setStretchLastSection( true );
1192   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1193   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1194   QVBoxLayout* l = new QVBoxLayout( frame() );
1195   l->setMargin( 0 );
1196   l->addWidget( myInfo );
1197 }
1198
1199 /*!
1200   \brief Show mesh element information
1201   \param ids mesh nodes / elements identifiers
1202 */
1203 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1204 {
1205   clearInternal();
1206
1207   if ( actor() ) {
1208     int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1209     int cprecision = -1;
1210     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1211       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1212     foreach ( long id, ids ) {
1213       if ( !isElements() ) {
1214         //
1215         // show node info
1216         //
1217         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1218         if ( !e ) return;
1219         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1220       
1221         // node ID
1222         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1223         nodeItem->setText( 0, tr( "NODE" ) );
1224         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1225         // coordinates
1226         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1227         coordItem->setText( 0, tr( "COORDINATES" ) );
1228         QTreeWidgetItem* xItem = createItem( coordItem );
1229         xItem->setText( 0, "X" );
1230         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1231         QTreeWidgetItem* yItem = createItem( coordItem );
1232         yItem->setText( 0, "Y" );
1233         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1234         QTreeWidgetItem* zItem = createItem( coordItem );
1235         zItem->setText( 0, "Z" );
1236         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1237         // connectivity
1238         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1239         conItem->setText( 0, tr( "CONNECTIVITY" ) );
1240         Connectivity connectivity = nodeConnectivity( node );
1241         if ( !connectivity.isEmpty() ) {
1242           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1243           if ( !con.isEmpty() ) {
1244             QTreeWidgetItem* i = createItem( conItem );
1245             i->setText( 0, tr( "0D_ELEMENTS" ) );
1246             i->setText( 1, con );
1247           }
1248           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1249           if ( !con.isEmpty() ) {
1250             QTreeWidgetItem* i = createItem( conItem );
1251             i->setText( 0, tr( "BALL_ELEMENTS" ) );
1252             i->setText( 1, con );
1253           }
1254           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1255           if ( !con.isEmpty() ) {
1256             QTreeWidgetItem* i = createItem( conItem );
1257             i->setText( 0, tr( "EDGES" ) );
1258             i->setText( 1, con );
1259           }
1260           con = formatConnectivity( connectivity, SMDSAbs_Face );
1261           if ( !con.isEmpty() ) {
1262             QTreeWidgetItem* i = createItem( conItem );
1263             i->setText( 0, tr( "FACES" ) );
1264             i->setText( 1, con );
1265           }
1266           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1267           if ( !con.isEmpty() ) {
1268             QTreeWidgetItem* i = createItem( conItem );
1269             i->setText( 0, tr( "VOLUMES" ) );
1270             i->setText( 1, con );
1271           }
1272         }
1273         else {
1274           conItem->setText( 1, tr( "FREE_NODE" ) );
1275         }
1276         // node position
1277         int shapeID = node->getshapeId();
1278         if ( shapeID > 0 )
1279         {
1280           SMDS_PositionPtr        pos = node->GetPosition();
1281           SMDS_TypeOfPosition posType = pos->GetTypeOfPosition();
1282           QString shapeType;
1283           double u,v;
1284           switch ( posType ) {
1285           case SMDS_TOP_EDGE:   shapeType = tr( "EDGE" );
1286             u = static_cast<SMDS_EdgePosition*>( pos )->GetUParameter();
1287             break;
1288           case SMDS_TOP_FACE:   shapeType = tr( "FACE" );
1289             u = static_cast<SMDS_FacePosition*>( pos )->GetUParameter();
1290             v = static_cast<SMDS_FacePosition*>( pos )->GetVParameter();
1291             break;
1292           case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break;
1293           default:              shapeType = tr( "SOLID" );
1294           }
1295           QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
1296           posItem->setText( 0, tr("NODE_POSITION") );
1297           posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
1298           if ( posType == SMDS_TOP_EDGE || posType == SMDS_TOP_FACE ) {
1299             QTreeWidgetItem* uItem = createItem( posItem );
1300             uItem->setText( 0, tr("U_POSITION") );
1301             uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
1302             if ( posType == SMDS_TOP_FACE ) {
1303               QTreeWidgetItem* vItem = createItem( posItem );
1304               vItem->setText( 0, tr("V_POSITION") );
1305               vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
1306             }
1307           }
1308         }
1309       }
1310       else {
1311         //
1312         // show element info
1313         // 
1314         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1315         SMESH::Controls::NumericalFunctorPtr afunctor;
1316         if ( !e ) return;
1317         
1318         // element ID && type
1319         QString stype;
1320         switch( e->GetType() ) {
1321         case SMDSAbs_0DElement:
1322           stype = tr( "0D ELEMENT" ); break;
1323         case SMDSAbs_Ball:
1324           stype = tr( "BALL" ); break;
1325         case SMDSAbs_Edge:
1326           stype = tr( "EDGE" ); break;
1327         case SMDSAbs_Face:
1328           stype = tr( "FACE" ); break;
1329         case SMDSAbs_Volume:
1330           stype = tr( "VOLUME" ); break;
1331         default: 
1332           break;
1333         }
1334         if ( stype.isEmpty() ) return;
1335         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1336         elemItem->setText( 0, stype );
1337         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1338         // geometry type
1339         QString gtype;
1340         switch( e->GetEntityType() ) {
1341         case SMDSEntity_Triangle:
1342         case SMDSEntity_Quad_Triangle:
1343           gtype = tr( "TRIANGLE" ); break;
1344         case SMDSEntity_Quadrangle:
1345         case SMDSEntity_Quad_Quadrangle:
1346         case SMDSEntity_BiQuad_Quadrangle:
1347           gtype = tr( "QUADRANGLE" ); break;
1348         case SMDSEntity_Polygon:
1349         case SMDSEntity_Quad_Polygon:
1350           gtype = tr( "POLYGON" ); break;
1351         case SMDSEntity_Tetra:
1352         case SMDSEntity_Quad_Tetra:
1353           gtype = tr( "TETRAHEDRON" ); break;
1354         case SMDSEntity_Pyramid:
1355         case SMDSEntity_Quad_Pyramid:
1356           gtype = tr( "PYRAMID" ); break;
1357         case SMDSEntity_Hexa:
1358         case SMDSEntity_Quad_Hexa:
1359         case SMDSEntity_TriQuad_Hexa:
1360           gtype = tr( "HEXAHEDRON" ); break;
1361         case SMDSEntity_Penta:
1362         case SMDSEntity_Quad_Penta:
1363           gtype = tr( "PRISM" ); break;
1364         case SMDSEntity_Hexagonal_Prism:
1365           gtype = tr( "HEX_PRISM" ); break;
1366         case SMDSEntity_Polyhedra:
1367         case SMDSEntity_Quad_Polyhedra:
1368           gtype = tr( "POLYHEDRON" ); break;
1369         default: 
1370           break;
1371         }
1372         if ( !gtype.isEmpty() ) {
1373           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1374           typeItem->setText( 0, tr( "TYPE" ) );
1375           typeItem->setText( 1, gtype );
1376         }
1377         // quadratic flag and gravity center (any element except 0D)
1378         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1379           // quadratic flag
1380           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1381           quadItem->setText( 0, tr( "QUADRATIC" ) );
1382           quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) );
1383           // gravity center
1384           XYZ gc = gravityCenter( e );
1385           QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
1386           gcItem->setText( 0, tr( "GRAVITY_CENTER" ) );
1387           QTreeWidgetItem* xItem = createItem( gcItem );
1388           xItem->setText( 0, "X" );
1389           xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1390           QTreeWidgetItem* yItem = createItem( gcItem );
1391           yItem->setText( 0, "Y" );
1392           yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1393           QTreeWidgetItem* zItem = createItem( gcItem );
1394           zItem->setText( 0, "Z" );
1395           zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1396         }
1397         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1398           // ball diameter
1399           QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
1400           diamItem->setText( 0, tr( "BALL_DIAMETER" ) );
1401           diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
1402         }
1403         // connectivity
1404         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1405         conItem->setText( 0, tr( "CONNECTIVITY" ) );
1406         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1407         for ( int idx = 1; nodeIt->more(); idx++ ) {
1408           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1409           // node number and ID
1410           QTreeWidgetItem* nodeItem = createItem( conItem, Bold );
1411           nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
1412           nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
1413           nodeItem->setExpanded( false );
1414           // node coordinates
1415           QTreeWidgetItem* coordItem = createItem( nodeItem );
1416           coordItem->setText( 0, tr( "COORDINATES" ) );
1417           QTreeWidgetItem* xItem = createItem( coordItem );
1418           xItem->setText( 0, "X" );
1419           xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1420           QTreeWidgetItem* yItem = createItem( coordItem );
1421           yItem->setText( 0, "Y" );
1422           yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1423           QTreeWidgetItem* zItem = createItem( coordItem );
1424           zItem->setText( 0, "Z" );
1425           zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1426           // node connectivity
1427           QTreeWidgetItem* nconItem = createItem( nodeItem );
1428           nconItem->setText( 0, tr( "CONNECTIVITY" ) );
1429           Connectivity connectivity = nodeConnectivity( node );
1430           if ( !connectivity.isEmpty() ) {
1431             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1432             if ( !con.isEmpty() ) {
1433               QTreeWidgetItem* i = createItem( nconItem );
1434               i->setText( 0, tr( "0D_ELEMENTS" ) );
1435               i->setText( 1, con );
1436             }
1437             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1438             if ( !con.isEmpty() ) {
1439               QTreeWidgetItem* i = createItem( nconItem );
1440               i->setText( 0, tr( "EDGES" ) );
1441               i->setText( 1, con );
1442             }
1443             con = formatConnectivity( connectivity, SMDSAbs_Ball );
1444             if ( !con.isEmpty() ) {
1445               QTreeWidgetItem* i = createItem( nconItem );
1446               i->setText( 0, tr( "BALL_ELEMENTS" ) );
1447               i->setText( 1, con );
1448             }
1449             con = formatConnectivity( connectivity, SMDSAbs_Face );
1450             if ( !con.isEmpty() ) {
1451               QTreeWidgetItem* i = createItem( nconItem );
1452               i->setText( 0, tr( "FACES" ) );
1453               i->setText( 1, con );
1454             }
1455             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1456             if ( !con.isEmpty() ) {
1457               QTreeWidgetItem* i = createItem( nconItem );
1458               i->setText( 0, tr( "VOLUMES" ) );
1459               i->setText( 1, con );
1460             }
1461           }
1462         }
1463         //Controls
1464         QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
1465         cntrItem->setText( 0, tr( "MEN_CTRL" ) );
1466         //Length
1467         if( e->GetType()==SMDSAbs_Edge){         
1468           afunctor.reset( new SMESH::Controls::Length() );
1469           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1470           afunctor->SetPrecision( cprecision );
1471           QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
1472           lenItem->setText( 0, tr( "LENGTH_EDGES" ) );
1473           lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );         
1474         }
1475         if( e->GetType() == SMDSAbs_Face ) {
1476           //Area         
1477           afunctor.reset( new SMESH::Controls::Area() );        
1478           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1479           afunctor->SetPrecision( cprecision );
1480           QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
1481           areaItem->setText( 0, tr( "AREA_ELEMENTS" ) );
1482           areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ) );         
1483           //Taper
1484           afunctor.reset( new SMESH::Controls::Taper() );
1485           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1486           afunctor->SetPrecision( cprecision );
1487           QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
1488           taperlItem->setText( 0, tr( "MEN_TAPER" ) );
1489           taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1490           //AspectRatio2D
1491           afunctor.reset( new SMESH::Controls::AspectRatio() );
1492           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1493           QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
1494           ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
1495           ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1496           //Minimum angle
1497           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1498           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1499           afunctor->SetPrecision( cprecision );
1500           QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
1501           minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ) );
1502           minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1503           //Wraping angle       
1504           afunctor.reset( new SMESH::Controls::Warping() );
1505           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1506           afunctor->SetPrecision( cprecision );
1507           QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
1508           warpItem->setText( 0, tr( "STB_WARP" ));
1509           warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );        
1510           //Skew          
1511           afunctor.reset( new SMESH::Controls::Skew() );
1512           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1513           afunctor->SetPrecision( cprecision );
1514           QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
1515           skewItem->setText( 0, tr( "TOP_SKEW" ) );
1516           skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1517           //ElemDiam2D    
1518           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1519           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1520           QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
1521           diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
1522           diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1523         }
1524         if( e->GetType() == SMDSAbs_Volume ) {
1525           //AspectRatio3D       
1526           afunctor.reset( new SMESH::Controls::AspectRatio3D() );
1527           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1528           QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
1529           ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
1530           ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1531           //Volume
1532           afunctor.reset( new SMESH::Controls::Volume() );
1533           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1534           QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
1535           volItem->setText( 0, tr( "MEN_VOLUME_3D" ) );
1536           volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1537           //ElementDiameter3D   
1538           afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
1539           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1540           QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
1541           diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) );
1542           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );     
1543         }
1544         /*
1545         if( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1546           //shapeID
1547           int shapeID = e->getshapeId();
1548           if ( shapeID > 0 ) {
1549             QTreeWidgetItem* shItem = createItem( elemItem, Bold );
1550             QString shapeType;
1551             switch ( actor()->GetObject()->GetMesh()->FindElement( shapeID )->GetType() ) {
1552             case SMDS_TOP_EDGE:   shapeType = tr( "EDGE" ); break;
1553             case SMDS_TOP_FACE:   shapeType = tr( "FACE" ); break;
1554             case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break;
1555             default:              shapeType = tr( "SOLID" );
1556             }
1557             shItem->setText( 0, tr( "Position" ) );
1558             shItem->setText( 1, QString( "%1 #%2" ).arg(shapeType).arg( shapeID ) );
1559           }
1560         }
1561         */
1562       }
1563     }
1564   }
1565 }
1566
1567 /*!
1568   \brief Internal clean-up (reset widget)
1569 */
1570 void SMESHGUI_TreeElemInfo::clearInternal()
1571 {
1572   myInfo->clear();
1573   myInfo->repaint();
1574 }
1575
1576 /*!
1577   \brief Create new tree item.
1578   \param parent parent tree widget item
1579   \param flags item flag
1580   \return new tree widget item
1581 */
1582 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
1583 {
1584   QTreeWidgetItem* item;
1585   if ( parent )
1586     item = new QTreeWidgetItem( parent );
1587   else
1588     item = new QTreeWidgetItem( myInfo );
1589
1590   item->setFlags( item->flags() | Qt::ItemIsEditable );
1591
1592   QFont f = item->font( 0 );
1593   f.setBold( true );
1594   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
1595     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
1596       item->setFont( i, f );
1597   }
1598
1599   item->setExpanded( true );
1600   return item;
1601 }
1602
1603 /*!
1604   \class GrpComputor
1605   \brief Mesh information computer
1606   \internal
1607   
1608   The class is created for different computation operation. Currently it is used
1609   to compute number of underlying nodes for the groups.
1610 */
1611
1612 /*!
1613   \brief Contructor
1614 */
1615 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
1616   : QObject( parent ), myItem( item )
1617 {
1618   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
1619 }
1620
1621 /*!
1622   \brief Compute function
1623 */
1624 void GrpComputor::compute()
1625 {
1626   if ( !CORBA::is_nil( myGroup ) && myItem ) {
1627     QTreeWidgetItem* item = myItem;
1628     myItem = 0;
1629     int nbNodes = myGroup->GetNumberOfNodes();
1630     item->treeWidget()->removeItemWidget( item, 1 );
1631     item->setText( 1, QString::number( nbNodes ));
1632   }
1633 }
1634
1635 /*!
1636   \class SMESHGUI_AddInfo
1637   \brief The wigdet shows additional information on the mesh object.
1638 */
1639
1640 /*!
1641   \brief Constructor
1642   \param parent parent widget
1643 */
1644 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
1645 : QTreeWidget( parent )
1646 {
1647   setColumnCount( 2 );
1648   header()->setStretchLastSection( true );
1649   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1650   header()->hide();
1651 }
1652
1653 /*!
1654   \brief Destructor
1655 */
1656 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
1657 {
1658 }
1659
1660 /*!
1661   \brief Show additional information on the selected object
1662   \param obj object being processed (mesh, sub-mesh, group, ID source)
1663 */
1664 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
1665 {
1666   setProperty( "group_index", 0 );
1667   setProperty( "submesh_index",  0 );
1668   myComputors.clear();
1669   clear();
1670
1671   if ( CORBA::is_nil( obj ) ) return;
1672
1673   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
1674   if ( !sobj ) return;
1675
1676   // name
1677   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
1678   nameItem->setText( 0, tr( "NAME" ) );
1679   nameItem->setText( 1, sobj->GetName().c_str() );
1680   
1681   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
1682   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
1683   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
1684   
1685   if ( !aMesh->_is_nil() )
1686     meshInfo( aMesh, nameItem );
1687   else if ( !aSubMesh->_is_nil() )
1688     subMeshInfo( aSubMesh, nameItem );
1689   else if ( !aGroup->_is_nil() )
1690     groupInfo( aGroup.in(), nameItem );
1691 }
1692
1693 /*!
1694   \brief Create new tree item.
1695   \param parent parent tree widget item
1696   \param flags item flag
1697   \return new tree widget item
1698 */
1699 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
1700 {
1701   QTreeWidgetItem* item;
1702
1703   if ( parent )
1704     item = new QTreeWidgetItem( parent );
1705   else
1706     item = new QTreeWidgetItem( this );
1707
1708   //item->setFlags( item->flags() | Qt::ItemIsEditable );
1709
1710   QFont f = item->font( 0 );
1711   f.setBold( true );
1712   for ( int i = 0; i < columnCount(); i++ ) {
1713     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
1714       item->setFont( i, f );
1715   }
1716
1717   item->setExpanded( true );
1718   return item;
1719 }
1720
1721 /*!
1722   \brief Show mesh info
1723   \param mesh mesh object
1724   \param parent parent tree item
1725 */
1726 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
1727 {
1728   // type
1729   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
1730   SALOME_MED::MedFileInfo* inf = mesh->GetMEDFileInfo();
1731   QTreeWidgetItem* typeItem = createItem( parent, Bold );
1732   typeItem->setText( 0, tr( "TYPE" ) );
1733   if ( !CORBA::is_nil( shape ) ) {
1734     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
1735     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
1736     if ( sobj ) {
1737       QTreeWidgetItem* gobjItem = createItem( typeItem );
1738       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1739       gobjItem->setText( 1, sobj->GetName().c_str() );
1740     }
1741   }
1742   else if ( strlen( (char*)inf->fileName ) > 0 ) {
1743     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
1744     QTreeWidgetItem* fileItem = createItem( typeItem );
1745     fileItem->setText( 0, tr( "FILE_NAME" ) );
1746     fileItem->setText( 1, (char*)inf->fileName );
1747   }
1748   else {
1749     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
1750   }
1751   
1752   // groups
1753   myGroups = mesh->GetGroups();
1754   showGroups();
1755
1756   // sub-meshes
1757   mySubMeshes = mesh->GetSubMeshes();
1758   showSubMeshes();
1759 }
1760
1761 /*!
1762   \brief Show sub-mesh info
1763   \param subMesh sub-mesh object
1764   \param parent parent tree item
1765 */
1766 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
1767 {
1768   bool isShort = parent->parent() != 0;
1769
1770   if ( !isShort ) {
1771     // parent mesh
1772     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
1773     if ( sobj ) {
1774       QTreeWidgetItem* nameItem = createItem( parent, Bold );
1775       nameItem->setText( 0, tr( "PARENT_MESH" ) );
1776       nameItem->setText( 1, sobj->GetName().c_str() );
1777     }
1778   }
1779   
1780   // shape
1781   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
1782   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1783   if ( sobj ) {
1784     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
1785     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1786     gobjItem->setText( 1, sobj->GetName().c_str() );
1787   }
1788 }
1789
1790 /*!
1791   \brief Show group info
1792   \param grp mesh group object
1793   \param parent parent tree item
1794 */
1795 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
1796 {
1797   bool isShort = parent->parent() != 0;
1798
1799   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
1800   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
1801   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
1802
1803   if ( !isShort ) {
1804     // parent mesh
1805     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
1806     if ( sobj ) {
1807       QTreeWidgetItem* nameItem = createItem( parent, Bold );
1808       nameItem->setText( 0, tr( "PARENT_MESH" ) );
1809       nameItem->setText( 1, sobj->GetName().c_str() );
1810     }
1811   }
1812
1813   // type : group on geometry, standalone group, group on filter
1814   QTreeWidgetItem* typeItem = createItem( parent, Bold );
1815   typeItem->setText( 0, tr( "TYPE" ) );
1816   if ( !CORBA::is_nil( aStdGroup ) ) {
1817     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
1818   }
1819   else if ( !CORBA::is_nil( aGeomGroup ) ) {
1820     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
1821     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1822     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1823     if ( sobj ) {
1824       QTreeWidgetItem* gobjItem = createItem( typeItem );
1825       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
1826       gobjItem->setText( 1, sobj->GetName().c_str() );
1827     }
1828   }
1829   else if ( !CORBA::is_nil( aFltGroup ) ) {
1830     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
1831   }
1832
1833   if ( !isShort ) {
1834     // entity type
1835     QString etype = tr( "UNKNOWN" );
1836     switch( grp->GetType() ) {
1837     case SMESH::NODE:
1838       etype = tr( "NODE" );
1839       break;
1840     case SMESH::EDGE:
1841       etype = tr( "EDGE" );
1842       break;
1843     case SMESH::FACE:
1844       etype = tr( "FACE" );
1845       break;
1846     case SMESH::VOLUME:
1847       etype = tr( "VOLUME" );
1848       break;
1849     case SMESH::ELEM0D:
1850       etype = tr( "0DELEM" );
1851       break;
1852     case SMESH::BALL:
1853       etype = tr( "BALL" );
1854       break;
1855     default:
1856       break;
1857     }
1858     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
1859     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
1860     etypeItem->setText( 1, etype );
1861   }
1862
1863   // size
1864   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
1865   sizeItem->setText( 0, tr( "SIZE" ) );
1866   sizeItem->setText( 1, QString::number( grp->Size() ) );
1867
1868   // color
1869   SALOMEDS::Color color = grp->GetColor();
1870   QTreeWidgetItem* colorItem = createItem( parent, Bold );
1871   colorItem->setText( 0, tr( "COLOR" ) );
1872   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1873
1874   // nb of underlying nodes
1875   if ( grp->GetType() != SMESH::NODE) {
1876     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
1877     nodesItem->setText( 0, tr( "NB_NODES" ) );
1878     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
1879     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
1880     bool meshLoaded = mesh->IsLoaded();
1881     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
1882     if ( toShowNodes && meshLoaded ) {
1883       // already calculated and up-to-date
1884       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
1885     }
1886     else {
1887       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
1888       setItemWidget( nodesItem, 1, btn );
1889       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
1890       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
1891       myComputors.append( comp );
1892       if ( !meshLoaded )
1893         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
1894     }
1895   }
1896 }
1897
1898 void SMESHGUI_AddInfo::showGroups()
1899 {
1900   myComputors.clear();
1901
1902   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
1903   if ( !parent ) return;
1904
1905   int idx = property( "group_index" ).toInt();
1906
1907   QTreeWidgetItem* itemGroups = 0;
1908   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
1909     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
1910       itemGroups = parent->child( i );
1911       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
1912       if ( extra )
1913         extra->updateControls( myGroups->length(), idx );
1914       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
1915     }
1916   }
1917
1918   QMap<int, QTreeWidgetItem*> grpItems;
1919   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
1920     SMESH::SMESH_GroupBase_var grp = myGroups[i];
1921     if ( CORBA::is_nil( grp ) ) continue;
1922     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
1923     if ( !grpSObj ) continue;
1924
1925     int grpType = grp->GetType();
1926
1927     if ( !itemGroups ) {
1928       // create top-level groups container item
1929       itemGroups = createItem( parent, Bold | All );
1930       itemGroups->setText( 0, tr( "GROUPS" ) );
1931       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
1932
1933       // total number of groups > 10, show extra widgets for info browsing
1934       if ( myGroups->length() > MAXITEMS ) {
1935         ExtraWidget* extra = new ExtraWidget( this, true );
1936         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
1937         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
1938         setItemWidget( itemGroups, 1, extra );
1939         extra->updateControls( myGroups->length(), idx );
1940       }
1941     }
1942
1943     if ( grpItems.find( grpType ) == grpItems.end() ) {
1944       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
1945       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
1946       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
1947     }
1948   
1949     // group name
1950     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
1951     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
1952
1953     // group info
1954     groupInfo( grp.in(), grpNameItem );
1955   }
1956 }
1957
1958 void SMESHGUI_AddInfo::showSubMeshes()
1959 {
1960   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
1961   if ( !parent ) return;
1962
1963   int idx = property( "submesh_index" ).toInt();
1964
1965   QTreeWidgetItem* itemSubMeshes = 0;
1966   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
1967     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
1968       itemSubMeshes = parent->child( i );
1969       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
1970       if ( extra )
1971         extra->updateControls( mySubMeshes->length(), idx );
1972       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
1973     }
1974   }
1975
1976   QMap<int, QTreeWidgetItem*> smItems;
1977   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
1978     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
1979     if ( CORBA::is_nil( sm ) ) continue;
1980     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
1981     if ( !smSObj ) continue;
1982     
1983     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
1984     if ( CORBA::is_nil(gobj ) ) continue;
1985     
1986     int smType = gobj->GetShapeType();
1987     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
1988
1989     if ( !itemSubMeshes ) {
1990       itemSubMeshes = createItem( parent, Bold | All );
1991       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
1992       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
1993
1994       // total number of sub-meshes > 10, show extra widgets for info browsing
1995       if ( mySubMeshes->length() > MAXITEMS ) {
1996         ExtraWidget* extra = new ExtraWidget( this, true );
1997         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
1998         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
1999         setItemWidget( itemSubMeshes, 1, extra );
2000         extra->updateControls( mySubMeshes->length(), idx );
2001       }
2002     }
2003          
2004     if ( smItems.find( smType ) == smItems.end() ) {
2005       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2006       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2007       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2008     }
2009     
2010     // submesh name
2011     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2012     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2013     
2014     // submesh info
2015     subMeshInfo( sm.in(), smNameItem );
2016   }
2017 }
2018
2019 /*!
2020  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2021  */
2022 void SMESHGUI_AddInfo::changeLoadToCompute()
2023 {
2024   for ( int i = 0; i < myComputors.count(); ++i )
2025   {
2026     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2027     {
2028       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2029         btn->setText( tr("COMPUTE") );
2030     }
2031   }
2032 }
2033
2034 void SMESHGUI_AddInfo::showPreviousGroups()
2035 {
2036   int idx = property( "group_index" ).toInt();
2037   setProperty( "group_index", idx-1 );
2038   showGroups();
2039 }
2040
2041 void SMESHGUI_AddInfo::showNextGroups()
2042 {
2043   int idx = property( "group_index" ).toInt();
2044   setProperty( "group_index", idx+1 );
2045   showGroups();
2046 }
2047
2048 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2049 {
2050   int idx = property( "submesh_index" ).toInt();
2051   setProperty( "submesh_index", idx-1 );
2052   showSubMeshes();
2053 }
2054
2055 void SMESHGUI_AddInfo::showNextSubMeshes()
2056 {
2057   int idx = property( "submesh_index" ).toInt();
2058   setProperty( "submesh_index", idx+1 );
2059   showSubMeshes();
2060 }
2061
2062 /*!
2063   \class SMESHGUI_MeshInfoDlg
2064   \brief Mesh information dialog box
2065 */
2066
2067 /*!
2068   \brief Constructor
2069   \param parent parent widget
2070   \param page specifies the dialog page to be shown at the start-up
2071 */
2072 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2073 : QDialog( parent ), myActor( 0 )
2074 {
2075   setModal( false );
2076   setAttribute( Qt::WA_DeleteOnClose, true );
2077   setWindowTitle( tr( "MESH_INFO" ) );
2078   setSizeGripEnabled( true );
2079
2080   myTabWidget = new QTabWidget( this );
2081
2082   // base info 
2083
2084   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2085   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2086
2087   // elem info 
2088   
2089   QWidget* w = new QWidget( myTabWidget );
2090
2091   myMode = new QButtonGroup( this );
2092   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2093   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2094   myMode->button( NodeMode )->setChecked( true );
2095   myID = new QLineEdit( w );
2096   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2097
2098   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2099   mode = qMin( 1, qMax( 0, mode ) );
2100   
2101   if ( mode == 0 ) 
2102     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2103   else
2104     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2105
2106   QGridLayout* elemLayout = new QGridLayout( w );
2107   elemLayout->setMargin( MARGIN );
2108   elemLayout->setSpacing( SPACING );
2109   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2110   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2111   elemLayout->addWidget( myID, 0, 2 );
2112   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2113   
2114   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2115
2116   // additional info
2117
2118   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2119   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2120
2121   // buttons
2122
2123   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2124   okBtn->setAutoDefault( true );
2125   okBtn->setDefault( true );
2126   okBtn->setFocus();
2127   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2128   helpBtn->setAutoDefault( true );
2129
2130   QHBoxLayout* btnLayout = new QHBoxLayout;
2131   btnLayout->setSpacing( SPACING );
2132   btnLayout->setMargin( 0 );
2133
2134   btnLayout->addWidget( okBtn );
2135   btnLayout->addStretch( 10 );
2136   btnLayout->addWidget( helpBtn );
2137
2138   QVBoxLayout* l = new QVBoxLayout ( this );
2139   l->setMargin( MARGIN );
2140   l->setSpacing( SPACING );
2141   l->addWidget( myTabWidget );
2142   l->addLayout( btnLayout );
2143
2144   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2145
2146   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2147   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2148   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2149   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2150   connect( myID,        SIGNAL( textEdited( QString  ) ), this, SLOT( idChanged() ) );
2151   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2152   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2153
2154   updateSelection();
2155 }
2156
2157 /*!
2158   \brief Destructor
2159 */
2160 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2161 {
2162 }
2163
2164 /*!
2165   \brief Show mesh information
2166   \param IO interactive object
2167 */
2168 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2169 {
2170   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2171   if ( !CORBA::is_nil( obj ) ) {
2172     myBaseInfo->showInfo( obj );
2173     myAddInfo->showInfo( obj );
2174
2175     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2176     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2177     QString ID;
2178     int nb = 0;
2179     if ( myActor && selector ) {
2180       nb = myMode->checkedId() == NodeMode ? 
2181         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2182         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2183     }
2184     myElemInfo->setSource( myActor ) ;
2185     if ( nb > 0 ) {
2186       myID->setText( ID.trimmed() );
2187       QSet<long> ids;
2188       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2189       foreach ( ID, idTxt )
2190         ids << ID.trimmed().toLong();
2191       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2192     }
2193     else {
2194       myID->clear();
2195       myElemInfo->clear();
2196     }
2197   }
2198 }
2199
2200 /*!
2201   \brief Perform clean-up actions on the dialog box closing.
2202 */
2203 void SMESHGUI_MeshInfoDlg::reject()
2204 {
2205   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2206   selMgr->clearFilters();
2207   SMESH::SetPointRepresentation( false );
2208   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2209     aViewWindow->SetSelectionMode( ActorSelection );
2210   QDialog::reject();
2211 }
2212
2213 /*!
2214   \brief Process keyboard event
2215   \param e key press event
2216 */
2217 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2218 {
2219   QDialog::keyPressEvent( e );
2220   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2221     e->accept();
2222     help();
2223   }
2224 }
2225
2226 /*!
2227   \brief Reactivate dialog box, when mouse pointer goes into it.
2228 */
2229 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2230 {
2231   //activate();
2232 }
2233
2234 /*!
2235   \brief Setup selection mode depending on the current dialog box state.
2236 */
2237 void SMESHGUI_MeshInfoDlg::updateSelection()
2238 {
2239   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2240
2241   disconnect( selMgr, 0, this, 0 );
2242   selMgr->clearFilters();
2243
2244   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) {
2245     SMESH::SetPointRepresentation( false );
2246     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2247       aViewWindow->SetSelectionMode( ActorSelection );
2248   }
2249   else {
2250     if ( myMode->checkedId() == NodeMode ) {
2251       SMESH::SetPointRepresentation( true );
2252       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2253         aViewWindow->SetSelectionMode( NodeSelection );
2254     }
2255     else {
2256       SMESH::SetPointRepresentation( false );
2257       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2258         aViewWindow->SetSelectionMode( CellSelection );
2259     }
2260   }
2261
2262   QString oldID = myID->text().trimmed();
2263   SMESH_Actor* oldActor = myActor;
2264   myID->clear();
2265   
2266   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2267   updateInfo();
2268   
2269   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
2270     myID->setText( oldID );
2271     idChanged();
2272   }
2273 }
2274
2275 /*!
2276   \brief Show help page
2277 */
2278 void SMESHGUI_MeshInfoDlg::help()
2279 {
2280   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
2281                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
2282                        "mesh_infos_page.html#mesh_element_info_anchor" );
2283 }
2284
2285 /*!
2286   \brief Show mesh information
2287 */
2288 void SMESHGUI_MeshInfoDlg::updateInfo()
2289 {
2290   SUIT_OverrideCursor wc;
2291
2292   SALOME_ListIO selected;
2293   SMESHGUI::selectionMgr()->selectedObjects( selected );
2294
2295   if ( selected.Extent() == 1 ) {
2296     Handle(SALOME_InteractiveObject) IO = selected.First();
2297     showInfo( IO );
2298   }
2299 //   else {
2300 //     myBaseInfo->clear();
2301 //     myElemInfo->clear();
2302 //     myAddInfo->clear();
2303 //   }
2304 }
2305
2306 /*!
2307   \brief Activate dialog box
2308 */
2309 void SMESHGUI_MeshInfoDlg::activate()
2310 {
2311   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
2312   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
2313   myTabWidget->setEnabled( true );
2314   updateSelection();
2315 }
2316
2317 /*!
2318   \brief Deactivate dialog box
2319 */
2320 void SMESHGUI_MeshInfoDlg::deactivate()
2321 {
2322   myTabWidget->setEnabled( false );
2323   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2324 }
2325
2326 /*!
2327   \brief Called when users switches between node / element modes.
2328 */
2329 void SMESHGUI_MeshInfoDlg::modeChanged()
2330 {
2331   myID->clear();
2332   updateSelection();
2333 }
2334
2335 /*!
2336   \brief Caled when users prints mesh element ID in the corresponding field.
2337 */
2338 void SMESHGUI_MeshInfoDlg::idChanged()
2339 {
2340   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2341   if ( myActor && selector ) {
2342     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
2343     TColStd_MapOfInteger ID;
2344     QSet<long> ids;
2345     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
2346     foreach ( QString tid, idTxt ) {
2347       long id = tid.trimmed().toLong();
2348       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
2349         myActor->GetObject()->GetMesh()->FindElement( id ) :
2350         myActor->GetObject()->GetMesh()->FindNode( id );
2351       if ( e ) {
2352         ID.Add( id );
2353         ids << id;
2354       }
2355     }
2356     selector->AddOrRemoveIndex( IO, ID, false );
2357     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2358       aViewWindow->highlight( IO, true, true );
2359     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2360   }
2361 }