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