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