Salome HOME
Update copyrights 2014.
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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 "SMDSAbs_ElementType.hxx"
28 #include "SMDS_BallElement.hxx"
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_Mesh.hxx"
32 #include "SMESHDS_Mesh.hxx"
33 #include "SMESHGUI.h"
34 #include "SMESHGUI_FilterUtils.h"
35 #include "SMESHGUI_IdValidator.h"
36 #include "SMESHGUI_SpinBox.h"
37 #include "SMESHGUI_Utils.h"
38 #include "SMESHGUI_VTKUtils.h"
39 #include "SMESH_Actor.h"
40
41 #include <LightApp_SelectionMgr.h>
42 #include <SUIT_FileDlg.h>
43 #include <SUIT_OverrideCursor.h>
44 #include <SUIT_ResourceMgr.h>
45 #include <SUIT_Session.h>
46 #include <SVTK_ViewWindow.h>
47
48 #include <SALOMEDSClient_Study.hxx>
49 #include <SalomeApp_Study.h>
50
51 #include <QApplication>
52 #include <QButtonGroup>
53 #include <QCheckBox>
54 #include <QContextMenuEvent>
55 #include <QGridLayout>
56 #include <QHBoxLayout>
57 #include <QHeaderView>
58 #include <QItemDelegate>
59 #include <QKeyEvent>
60 #include <QLabel>
61 #include <QLineEdit>
62 #include <QMenu>
63 #include <QPushButton>
64 #include <QToolButton>
65 #include <QRadioButton>
66 #include <QTextStream>
67 #include <QTabWidget>
68 #include <QTextBrowser>
69 #include <QVBoxLayout>
70
71 #include "utilities.h"
72
73 #include <SALOMEconfig.h>
74 #include CORBA_SERVER_HEADER(GEOM_Gen)
75
76 namespace {
77
78 const int SPACING      = 6;
79 const int MARGIN       = 9;
80 const int MAXITEMS     = 10;
81 const int GROUPS_ID    = 100;
82 const int SUBMESHES_ID = 200;
83 const int SPACING_INFO = 2;
84
85 enum InfoRole {
86   TypeRole = Qt::UserRole + 10,
87   IdRole,
88 };
89
90 enum InfoType {
91   NodeConnectivity = 100,
92   ElemConnectivity,
93 };
94 } // namesapce
95
96 /*!
97   \class ExtraWidget
98   \internal
99 */
100 class ExtraWidget : public QWidget
101 {
102 public:
103   ExtraWidget( QWidget*, bool = false );
104   ~ExtraWidget();
105
106   void updateControls( int, int, int = MAXITEMS );
107
108 public:
109   QLabel*      current;
110   QPushButton* prev;
111   QPushButton* next;
112   bool         brief;
113 };
114
115 ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b )
116 {
117   current = new QLabel( this );
118   current->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
119   prev = new QPushButton( tr( "<<" ), this );
120   next = new QPushButton( tr( ">>" ), this );
121   QHBoxLayout* hbl = new QHBoxLayout( this );
122   hbl->setContentsMargins( 0, SPACING, 0, 0 );
123   hbl->setSpacing( SPACING );
124   hbl->addStretch();
125   hbl->addWidget( current );
126   hbl->addWidget( prev );
127   hbl->addWidget( next );
128 }
129
130 ExtraWidget::~ExtraWidget()
131 {
132 }
133
134 void ExtraWidget::updateControls( int total, int index, int blockSize )
135 {
136   setVisible( total > blockSize );
137   QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" );
138   current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total ) ).arg( total ) );
139   prev->setEnabled( index > 0 );
140   next->setEnabled( (index+1)*blockSize < total );
141 }
142
143 /*!
144   \class DumpFileDlg
145   \brief Customization of standard "Save file" dialog box for dump info operation
146   \internal
147 */
148
149 class DumpFileDlg : public SUIT_FileDlg
150 {
151 public:
152   DumpFileDlg( QWidget* parent );
153
154   QCheckBox* myBaseChk;
155   QCheckBox* myElemChk;
156   QCheckBox* myAddChk;
157   QCheckBox* myCtrlChk;
158 };
159
160 /*!
161   \brief Constructor
162   \internal
163 */
164 DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
165 {
166   QGridLayout* grid = ::qobject_cast<QGridLayout *>( layout() );
167   if ( grid ) {
168     QWidget* hB = new QWidget( this );
169     myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
170     myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
171     myAddChk  = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
172     myCtrlChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
173
174     QGridLayout* layout = new QGridLayout( hB );
175     layout->addWidget( myBaseChk, 0, 0 );
176     layout->addWidget( myElemChk, 0, 1 );
177     layout->addWidget( myAddChk, 1, 0 );
178     layout->addWidget( myCtrlChk, 1, 1 );
179
180     QPushButton* pb = new QPushButton( this );
181
182     int row = grid->rowCount();
183     grid->addWidget( new QLabel( "", this ), row, 0 );
184     grid->addWidget( hB, row, 1, 1, 3 );
185     grid->addWidget( pb, row, 5 );
186
187     pb->hide();
188   }
189 }
190
191 /*!
192   \brief Get depth of the tree item
193   \internal
194   \param theItem tree widget item
195   \return item's depth in tree widget (where top-level items have zero depth)
196 */
197 static int itemDepth( QTreeWidgetItem* item )
198 {
199   int d = 0;
200   QTreeWidgetItem* p = item->parent();
201   while ( p ) {
202     d++;
203     p = p->parent();
204   }
205   return d;
206 }
207
208 /*!
209   \class SMESHGUI_MeshInfo
210   \brief Base mesh information widget
211   
212   Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
213 */
214
215 /*!
216   \brief Constructor.
217   \param parent parent widget
218 */
219 SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
220   : QFrame( parent ), myWidgets( iElementsEnd )
221 {
222   setFrameStyle( StyledPanel | Sunken );
223
224   QGridLayout* l = new QGridLayout( this );
225   l->setMargin( MARGIN );
226   l->setSpacing( SPACING );
227
228   int index = 0;
229
230   // object
231   QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
232   QLabel* aName        = createField();
233   aName->setMinimumWidth( 150 );
234   QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
235   QLabel* aObj         = createField();
236   aObj->setMinimumWidth( 150 );
237   myWidgets[ index++ ] << aNameLab << aName;
238   myWidgets[ index++ ] << aObjLab  << aObj;
239
240   // nodes
241   QWidget* aNodesLine  = createLine();
242   QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
243   QLabel*  aNodes      = createField();
244   myWidgets[ index++ ] << aNodesLine;
245   myWidgets[ index++ ] << aNodesLab << aNodes;
246
247   // elements
248   QWidget* aElemLine   = createLine();
249   QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),  this );
250   QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),     this );
251   QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),    this );
252   QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ), this );
253   myWidgets[ index++ ] << aElemLine;
254   myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad;
255
256   // ... Number elements
257   QWidget* aNbLine     = createLine(); 
258   QLabel*  aNbTotal    = createField();
259   QLabel*  aNbLin      = createField();
260   QLabel*  aNbQuad     = createField();
261   myWidgets[ index++ ] << aNbLine;
262   myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad;
263
264   // ... 0D elements
265   QWidget* a0DLine     = createLine();
266   QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
267   QLabel*  a0DTotal    = createField();
268   myWidgets[ index++ ] << a0DLine;
269   myWidgets[ index++ ] << a0DLab << a0DTotal;
270
271   // ... Ball elements
272   QWidget* aBallLine     = createLine();
273   QLabel*  aBallLab      = new QLabel( tr( "BALL_LAB" ), this );
274   QLabel*  aBallTotal    = createField();
275   myWidgets[ index++ ] << aBallLine;
276   myWidgets[ index++ ] << aBallLab << aBallTotal;
277
278   // ... 1D elements
279   QWidget* a1DLine     = createLine();
280   QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
281   QLabel*  a1DTotal    = createField();
282   QLabel*  a1DLin      = createField();
283   QLabel*  a1DQuad     = createField();
284   myWidgets[ index++ ] << a1DLine;
285   myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad;
286
287   // ... 2D elements
288   QWidget* a2DLine     = createLine();
289   QLabel*  a2DLab      = new QLabel( tr( "2D_LAB" ), this );
290   QLabel*  a2DTotal    = createField();
291   QLabel*  a2DLin      = createField();
292   QLabel*  a2DQuad     = createField();
293   QLabel*  a2DTriLab   = new QLabel( tr( "TRIANGLES_LAB" ), this );
294   QLabel*  a2DTriTotal = createField();
295   QLabel*  a2DTriLin   = createField();
296   QLabel*  a2DTriQuad  = createField();
297   QLabel*  a2DQuaLab   = new QLabel( tr( "QUADRANGLES_LAB" ), this );
298   QLabel*  a2DQuaTotal = createField();
299   QLabel*  a2DQuaLin   = createField();
300   QLabel*  a2DQuaQuad  = createField();
301   QLabel*  a2DPolLab   = new QLabel( tr( "POLYGONS_LAB" ), this );
302   QLabel*  a2DPolTotal = createField();
303   myWidgets[ index++ ] << a2DLine;
304   myWidgets[ index++ ] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad;
305   myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad;
306   myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad;
307   myWidgets[ index++ ] << a2DPolLab << a2DPolTotal;
308
309   // ... 3D elements
310   QWidget* a3DLine     = createLine();
311   QLabel*  a3DLab      = new QLabel( tr( "3D_LAB" ), this );
312   QLabel*  a3DTotal    = createField();
313   QLabel*  a3DLin      = createField();
314   QLabel*  a3DQuad     = createField();
315   QLabel*  a3DTetLab   = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
316   QLabel*  a3DTetTotal = createField();
317   QLabel*  a3DTetLin   = createField();
318   QLabel*  a3DTetQuad  = createField();
319   QLabel*  a3DHexLab   = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
320   QLabel*  a3DHexTotal = createField();
321   QLabel*  a3DHexLin   = createField();
322   QLabel*  a3DHexQuad  = createField();
323   QLabel*  a3DPyrLab   = new QLabel( tr( "PYRAMIDS_LAB" ), this );
324   QLabel*  a3DPyrTotal = createField();
325   QLabel*  a3DPyrLin   = createField();
326   QLabel*  a3DPyrQuad  = createField();
327   QLabel*  a3DPriLab   = new QLabel( tr( "PRISMS_LAB" ), this );
328   QLabel*  a3DPriTotal = createField();
329   QLabel*  a3DPriLin   = createField();
330   QLabel*  a3DPriQuad  = createField();
331   QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
332   QLabel*  a3DHexPriTotal = createField();
333   QLabel*  a3DPolLab   = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
334   QLabel*  a3DPolTotal = createField();
335   myWidgets[ index++ ] << a3DLine;
336   myWidgets[ index++ ] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad;
337   myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
338   myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad;
339   myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
340   myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
341   myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal;
342   myWidgets[ index++ ] << a3DPolLab << a3DPolTotal;
343
344   myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
345   myLoadBtn->setAutoDefault( true );
346   connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
347   
348   setFontAttributes( aNameLab,   Bold );
349   setFontAttributes( aObjLab,    Bold );
350   setFontAttributes( aNodesLab,  Bold );
351   setFontAttributes( aElemLab,   Bold );
352   setFontAttributes( aElemTotal, Italic );
353   setFontAttributes( aElemLin,   Italic );
354   setFontAttributes( aElemQuad,  Italic );
355   setFontAttributes( a0DLab,     Bold );
356   setFontAttributes( aBallLab,     Bold );
357   setFontAttributes( a1DLab,     Bold );
358   setFontAttributes( a2DLab,     Bold );
359   setFontAttributes( a3DLab,     Bold );
360
361   l->addWidget( aNameLab,     0, 0 );
362   l->addWidget( aName,        0, 1, 1, 3 );
363   l->addWidget( aObjLab,      1, 0 );
364   l->addWidget( aObj,         1, 1, 1, 3 );
365   l->addWidget( aNodesLine,   2, 0, 1, 4 );
366   l->addWidget( aNodesLab,    3, 0 );
367   l->addWidget( aNodes,       3, 1 );
368   l->addWidget( aElemLine,    4, 0, 1, 4 );
369   l->addWidget( aElemLab,     5, 0 );
370   l->addWidget( aElemTotal,   5, 1 );
371   l->addWidget( aElemLin,     5, 2 );
372   l->addWidget( aElemQuad,    5, 3 );
373   l->addWidget( aNbLine,      6, 1, 1, 3 );
374   l->addWidget( aNbTotal,     7, 1 );
375   l->addWidget( aNbLin,       7, 2 );
376   l->addWidget( aNbQuad,      7, 3 );
377   l->addWidget( a0DLine,      8, 1, 1, 3 );
378   l->addWidget( a0DLab,       9, 0 );
379   l->addWidget( a0DTotal,     9, 1 );
380   l->addWidget( aBallLine,    10, 1, 1, 3 );
381   l->addWidget( aBallLab,     11, 0 );
382   l->addWidget( aBallTotal,   11, 1 );
383   l->addWidget( a1DLine,      12, 1, 1, 3 );
384   l->addWidget( a1DLab,       13, 0 );
385   l->addWidget( a1DTotal,     13, 1 );
386   l->addWidget( a1DLin,       13, 2 );
387   l->addWidget( a1DQuad,      13, 3 );
388   l->addWidget( a2DLine,     14, 1, 1, 3 );
389   l->addWidget( a2DLab,      15, 0 );
390   l->addWidget( a2DTotal,    15, 1 );
391   l->addWidget( a2DLin,      15, 2 );
392   l->addWidget( a2DQuad,     15, 3 );
393   l->addWidget( a2DTriLab,   16, 0 );
394   l->addWidget( a2DTriTotal, 16, 1 );
395   l->addWidget( a2DTriLin,   16, 2 );
396   l->addWidget( a2DTriQuad,  16, 3 );
397   l->addWidget( a2DQuaLab,   17, 0 );
398   l->addWidget( a2DQuaTotal, 17, 1 );
399   l->addWidget( a2DQuaLin,   17, 2 );
400   l->addWidget( a2DQuaQuad,  17, 3 );
401   l->addWidget( a2DPolLab,   18, 0 );
402   l->addWidget( a2DPolTotal, 18, 1 );
403   l->addWidget( a3DLine,     19, 1, 1, 3 );
404   l->addWidget( a3DLab,      20, 0 );
405   l->addWidget( a3DTotal,    20, 1 );
406   l->addWidget( a3DLin,      20, 2 );
407   l->addWidget( a3DQuad,     20, 3 );
408   l->addWidget( a3DTetLab,   21, 0 );
409   l->addWidget( a3DTetTotal, 21, 1 );
410   l->addWidget( a3DTetLin,   21, 2 );
411   l->addWidget( a3DTetQuad,  21, 3 );
412   l->addWidget( a3DHexLab,   22, 0 );
413   l->addWidget( a3DHexTotal, 22, 1 );
414   l->addWidget( a3DHexLin,   22, 2 );
415   l->addWidget( a3DHexQuad,  22, 3 );
416   l->addWidget( a3DPyrLab,   23, 0 );
417   l->addWidget( a3DPyrTotal, 23, 1 );
418   l->addWidget( a3DPyrLin,   23, 2 );
419   l->addWidget( a3DPyrQuad,  23, 3 );
420   l->addWidget( a3DPriLab,   24, 0 );
421   l->addWidget( a3DPriTotal, 24, 1 );
422   l->addWidget( a3DPriLin,   24, 2 );
423   l->addWidget( a3DPriQuad,  24, 3 );
424   l->addWidget( a3DHexPriLab,   25, 0 );
425   l->addWidget( a3DHexPriTotal, 25, 1 );
426   l->addWidget( a3DPolLab,   26, 0 );
427   l->addWidget( a3DPolTotal, 26, 1 ); 
428   l->addWidget( myLoadBtn,   28, 1, 1, 3 );
429
430   l->setColumnStretch( 0, 0 );
431   l->setColumnStretch( 1, 5 );
432   l->setColumnStretch( 2, 5 );
433   l->setColumnStretch( 3, 5 );
434   l->setRowStretch( 27, 5 );
435
436   clear();
437 }
438
439 /*!
440   \brief Destructor
441 */
442 SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
443 {
444 }
445
446 /*!
447   \brief Show information on the mesh object.
448   \param obj object being processed (mesh, sub-mesh, group, ID source)
449 */
450 void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
451 {
452   clear();
453   if ( !CORBA::is_nil( obj ) ) {
454     _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
455     if ( sobj ) 
456       myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
457     SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
458     SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
459     SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
460     if ( !aMesh->_is_nil() ) {
461       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) );
462     }
463     else if ( !aSubMesh->_is_nil() ) {
464       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) );
465     }
466     else if ( !aGroup->_is_nil() ) {
467       QString objType;
468       switch( aGroup->GetType() ) {
469       case SMESH::NODE:  objType = tr( "OBJECT_GROUP_NODES"   );break;
470       case SMESH::EDGE:  objType = tr( "OBJECT_GROUP_EDGES"   );break;
471       case SMESH::FACE:  objType = tr( "OBJECT_GROUP_FACES"   );break;
472       case SMESH::VOLUME:objType = tr( "OBJECT_GROUP_VOLUMES" );break;
473       case SMESH::ELEM0D:objType = tr( "OBJECT_GROUP_0DELEMS" );break;
474       case SMESH::BALL:  objType = tr( "OBJECT_GROUP_BALLS"   );break;
475       default:           objType = tr( "OBJECT_GROUP"         );break;
476       }
477       myWidgets[iObject][iSingle]->setProperty( "text", objType );
478     }
479     SMESH::long_array_var info = obj->GetMeshInfo();
480     myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
481     myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
482     myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ) );
483     long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
484     myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ) );
485     myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) );
486     myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) );
487     long nbTriangles   = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_BiQuad_Triangle];
488     long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
489     long nb2DLinear    = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
490     long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
491     myWidgets[i2D][iTotal]               ->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ));
492     myWidgets[i2D][iLinear]              ->setProperty( "text", QString::number( nb2DLinear ) );
493     myWidgets[i2D][iQuadratic]           ->setProperty( "text", QString::number( nb2DQuadratic ) );
494     myWidgets[i2DTriangles][iTotal]      ->setProperty( "text", QString::number( nbTriangles ) );
495     myWidgets[i2DTriangles][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) );
496     myWidgets[i2DTriangles][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_BiQuad_Triangle]) );
497     myWidgets[i2DQuadrangles][iTotal]    ->setProperty( "text", QString::number( nbQuadrangles ) );
498     myWidgets[i2DQuadrangles][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) );
499     myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle] ));
500     myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
501     long nbTetrahedrons = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
502     long nbHexahedrons  = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
503     long nbPyramids     = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
504     long nbPrisms       = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta];
505     long nb3DLinear     = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
506     long nb3DQuadratic  = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
507     myWidgets[i3D][iTotal]                ->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) );
508     myWidgets[i3D][iLinear]               ->setProperty( "text", QString::number( nb3DLinear ) );
509     myWidgets[i3D][iQuadratic]            ->setProperty( "text", QString::number( nb3DQuadratic ) );
510     myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", QString::number( nbTetrahedrons ) );
511     myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
512     myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) );
513     myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", QString::number( nbHexahedrons ) );
514     myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) );
515     myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] ) );
516     myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", QString::number( nbPyramids ) );
517     myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) );
518     myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) );
519     myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", QString::number( nbPrisms ) );
520     myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) );
521     myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) );
522     myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
523     myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
524     long nbElemTotal     = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DLinear + nb2DQuadratic + nb3DLinear + nb3DQuadratic;
525     long nbElemLinerial  = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear;
526     long nbElemQuadratic = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic;
527     myWidgets[iNb][iTotal]    ->setProperty( "text", QString::number( nbElemTotal ) );
528     myWidgets[iNb][iLinear]   ->setProperty( "text", QString::number( nbElemLinerial ) );
529     myWidgets[iNb][iQuadratic]->setProperty( "text", QString::number( nbElemQuadratic ) );
530     // before full loading from study file, type of elements in a sub-mesh can't be defined
531     // in some cases
532     bool infoOK = obj->IsMeshInfoCorrect();
533     myLoadBtn->setVisible( !infoOK );
534     if ( !infoOK )
535     {
536       // two options:
537       // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
538       // 2. No info at all (for a group on geom or filter)
539       bool hasAnyInfo = false;
540       for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
541         hasAnyInfo = info[i];
542       if ( hasAnyInfo ) // believe it is a sub-mesh
543       {
544         if ( nb2DLinear + nb2DQuadratic > 0 )
545         {
546           myWidgets[i2D][iLinear]              ->setProperty( "text", "?" );
547           myWidgets[i2D][iQuadratic]           ->setProperty( "text", "?" );
548           myWidgets[i2DTriangles][iTotal]      ->setProperty( "text", "?" );
549           myWidgets[i2DTriangles][iLinear]     ->setProperty( "text", "?" );
550           myWidgets[i2DTriangles][iQuadratic]  ->setProperty( "text", "?" );
551           myWidgets[i2DQuadrangles][iTotal]    ->setProperty( "text", "?" );
552           myWidgets[i2DQuadrangles][iLinear]   ->setProperty( "text", "?" );
553           myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", "?" );
554           myWidgets[i2DPolygons][iTotal]       ->setProperty( "text", "?" );
555           myWidgets[iNb][iTotal]               ->setProperty( "text", "?" );
556           myWidgets[iNb][iLinear]              ->setProperty( "text", "?" );
557           myWidgets[iNb][iQuadratic]           ->setProperty( "text", "?" );
558         }
559         else if ( nb3DLinear + nb3DQuadratic > 0 )
560         {
561           myWidgets[i3D][iLinear]               ->setProperty( "text", "?" );
562           myWidgets[i3D][iQuadratic]            ->setProperty( "text", "?" );
563           myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", "?" );
564           myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", "?" );
565           myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" );
566           myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", "?" );
567           myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", "?" );
568           myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" );
569           myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", "?" );
570           myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", "?" );
571           myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", "?" );
572           myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", "?" );
573           myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", "?" );
574           myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", "?" );
575           myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", "?" );
576           myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", "?" );
577           myWidgets[iNb][iTotal]                ->setProperty( "text", "?" );
578           myWidgets[iNb][iLinear]               ->setProperty( "text", "?" );
579           myWidgets[iNb][iQuadratic]            ->setProperty( "text", "?" );
580         }
581       }
582       else
583       {
584         myWidgets[iNodes][iTotal]             ->setProperty( "text", "?" );
585         myWidgets[i0D][iTotal]                ->setProperty( "text", "?" );
586         myWidgets[iBalls][iTotal]             ->setProperty( "text", "?" );
587         myWidgets[i1D][iTotal]                ->setProperty( "text", "?" );
588         myWidgets[i1D][iLinear]               ->setProperty( "text", "?" );
589         myWidgets[i1D][iQuadratic]            ->setProperty( "text", "?" );
590         myWidgets[i2D][iTotal]                ->setProperty( "text", "?" );
591         myWidgets[i2D][iLinear]               ->setProperty( "text", "?" );
592         myWidgets[i2D][iQuadratic]            ->setProperty( "text", "?" );
593         myWidgets[i2DTriangles][iTotal]       ->setProperty( "text", "?" );
594         myWidgets[i2DTriangles][iLinear]      ->setProperty( "text", "?" );
595         myWidgets[i2DTriangles][iQuadratic]   ->setProperty( "text", "?" );
596         myWidgets[i2DQuadrangles][iTotal]     ->setProperty( "text", "?" );
597         myWidgets[i2DQuadrangles][iLinear]    ->setProperty( "text", "?" );
598         myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", "?" );
599         myWidgets[i2DPolygons][iTotal]        ->setProperty( "text", "?" );
600         myWidgets[i3D][iTotal]                ->setProperty( "text", "?" );
601         myWidgets[i3D][iLinear]               ->setProperty( "text", "?" );
602         myWidgets[i3D][iQuadratic]            ->setProperty( "text", "?" );
603         myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", "?" );
604         myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", "?" );
605         myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" );
606         myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", "?" );
607         myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", "?" );
608         myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" );
609         myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", "?" );
610         myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", "?" );
611         myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", "?" );
612         myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", "?" );
613         myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", "?" );
614         myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", "?" );
615         myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", "?" );
616         myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", "?" );
617         myWidgets[iNb][iTotal]                ->setProperty( "text", "?" );
618         myWidgets[iNb][iLinear]               ->setProperty( "text", "?" );
619         myWidgets[iNb][iQuadratic]            ->setProperty( "text", "?" );
620       }
621     }
622   }
623 }
624
625 /*!
626   \brief Load mesh from a study file
627 */
628 void SMESHGUI_MeshInfo::loadMesh()
629 {
630   SUIT_OverrideCursor wc;
631
632   SALOME_ListIO selected;
633   SMESHGUI::selectionMgr()->selectedObjects( selected );
634
635   if ( selected.Extent() == 1 ) {
636     Handle(SALOME_InteractiveObject) IO = selected.First();
637     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
638     if ( !CORBA::is_nil( obj ) ) {
639       SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
640       if ( !mesh->_is_nil() )
641       {
642         mesh->Load();
643         showInfo( obj );
644       }
645     }
646   }
647 }
648
649 /*!
650   \brief Reset the widget to the initial state (nullify all fields).
651 */
652 void SMESHGUI_MeshInfo::clear()
653 {
654   myWidgets[iName][iSingle]             ->setProperty( "text", QString() );
655   myWidgets[iObject][iSingle]           ->setProperty( "text", QString() );
656   myWidgets[iNodes][iTotal]             ->setProperty( "text", QString::number( 0 ) );
657   myWidgets[i0D][iTotal]                ->setProperty( "text", QString::number( 0 ) );
658   myWidgets[iBalls][iTotal]             ->setProperty( "text", QString::number( 0 ) );
659   myWidgets[i1D][iTotal]                ->setProperty( "text", QString::number( 0 ) );
660   myWidgets[i1D][iLinear]               ->setProperty( "text", QString::number( 0 ) );
661   myWidgets[i1D][iQuadratic]            ->setProperty( "text", QString::number( 0 ) );
662   myWidgets[i2D][iTotal]                ->setProperty( "text", QString::number( 0 ) );
663   myWidgets[i2D][iLinear]               ->setProperty( "text", QString::number( 0 ) );
664   myWidgets[i2D][iQuadratic]            ->setProperty( "text", QString::number( 0 ) );
665   myWidgets[i2DTriangles][iTotal]       ->setProperty( "text", QString::number( 0 ) );
666   myWidgets[i2DTriangles][iLinear]      ->setProperty( "text", QString::number( 0 ) );
667   myWidgets[i2DTriangles][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
668   myWidgets[i2DQuadrangles][iTotal]     ->setProperty( "text", QString::number( 0 ) );
669   myWidgets[i2DQuadrangles][iLinear]    ->setProperty( "text", QString::number( 0 ) );
670   myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", QString::number( 0 ) );
671   myWidgets[i2DPolygons][iTotal]        ->setProperty( "text", QString::number( 0 ) );
672   myWidgets[i3D][iTotal]                ->setProperty( "text", QString::number( 0 ) );
673   myWidgets[i3D][iLinear]               ->setProperty( "text", QString::number( 0 ) );
674   myWidgets[i3D][iQuadratic]            ->setProperty( "text", QString::number( 0 ) );
675   myWidgets[i3DTetrahedrons][iTotal]    ->setProperty( "text", QString::number( 0 ) );
676   myWidgets[i3DTetrahedrons][iLinear]   ->setProperty( "text", QString::number( 0 ) );
677   myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) );
678   myWidgets[i3DHexahedrons][iTotal]     ->setProperty( "text", QString::number( 0 ) );
679   myWidgets[i3DHexahedrons][iLinear]    ->setProperty( "text", QString::number( 0 ) );
680   myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", QString::number( 0 ) );
681   myWidgets[i3DPyramids][iTotal]        ->setProperty( "text", QString::number( 0 ) );
682   myWidgets[i3DPyramids][iLinear]       ->setProperty( "text", QString::number( 0 ) );
683   myWidgets[i3DPyramids][iQuadratic]    ->setProperty( "text", QString::number( 0 ) );
684   myWidgets[i3DPrisms][iTotal]          ->setProperty( "text", QString::number( 0 ) );
685   myWidgets[i3DPrisms][iLinear]         ->setProperty( "text", QString::number( 0 ) );
686   myWidgets[i3DPrisms][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
687   myWidgets[i3DHexaPrisms][iTotal]      ->setProperty( "text", QString::number( 0 ) );
688   myWidgets[i3DPolyhedrons][iTotal]     ->setProperty( "text", QString::number( 0 ) );
689   myWidgets[iNb][iTotal]                ->setProperty( "text", QString::number( 0 ) );
690   myWidgets[iNb][iLinear]               ->setProperty( "text", QString::number( 0 ) );
691   myWidgets[iNb][iQuadratic]            ->setProperty( "text", QString::number( 0 ) );
692 }
693
694 /*!
695   \brief Create info field
696   \return new info field
697 */
698 QLabel* SMESHGUI_MeshInfo::createField()
699 {
700   QLabel* lab = new QLabel( this );
701   lab->setFrameStyle( StyledPanel | Sunken );
702   lab->setAlignment( Qt::AlignCenter );
703   lab->setAutoFillBackground( true );
704   QPalette pal = lab->palette();
705   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
706   lab->setPalette( pal );
707   lab->setMinimumWidth( 70 );
708   return lab;
709 }
710
711 /*!
712   \brief Create horizontal rule.
713   \return new line object
714 */
715 QWidget* SMESHGUI_MeshInfo::createLine()
716 {
717   QFrame* line = new QFrame( this );
718   line->setFrameStyle( HLine | Sunken );
719   return line;
720 }
721
722 /*!
723   \brief Change widget font attributes (bold, italic, ...).
724   \param w widget
725   \param attr font attributes (XORed flags)
726   \param val value to be set to attributes
727 */
728 void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
729 {
730   if ( w && attr ) {
731     QFont f = w->font();
732     if ( attr & Bold   ) f.setBold( val );
733     if ( attr & Italic ) f.setItalic( val );
734     w->setFont( f );
735   }
736 }
737
738 /*!
739   \brief Show/hide group(s) of fields.
740   \param start beginning of the block
741   \param end end of the block
742   \param on visibility flag
743 */
744 void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
745 {
746   start = qMax( 0, start );
747   end   = qMin( end, (int)iElementsEnd );
748   for ( int i = start; i < end; i++ ) {
749     wlist wl = myWidgets[i];
750     foreach ( QWidget* w, wl ) w->setVisible( on );
751   }
752 }
753
754 void SMESHGUI_MeshInfo::saveInfo( QTextStream &out )
755 {
756   out << QString( 9, '-' ) << "\n";
757   out << tr( "BASE_INFO" ) << "\n";
758   out << QString( 9, '-' ) << "\n";
759   out <<                                   tr( "NAME_LAB" )         << "  " << ( myWidgets[iName][iSingle]->property( "text" ) ).toString() << "\n";
760   out <<                                   tr( "OBJECT_LAB" )       << "  " << ( myWidgets[iObject][iSingle]->property( "text" ) ).toString() << "\n";
761   out <<                                   tr( "NODES_LAB" )        << "  " << ( myWidgets[iNodes][iTotal]->property( "text" ) ).toString() << "\n";
762   out <<                                   tr( "ELEMENTS_LAB" )     << "\n";
763   out << QString( SPACING_INFO,   ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iNb][iTotal]->property( "text" ) ).toString() << "\n";
764   out << QString( SPACING_INFO,   ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[iNb][iLinear]->property( "text" ) ).toString() << "\n";
765   out << QString( SPACING_INFO,   ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" ) ).toString() << "\n";
766   out << QString( SPACING_INFO,   ' ' ) << tr( "0D_LAB" )           << "\n";
767   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i0D][iTotal]->property( "text" ) ).toString() << "\n";
768   out << QString( SPACING_INFO,   ' ' ) << tr( "BALL_LAB" )         << "\n";
769   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iBalls][iTotal]->property( "text" ) ).toString() << "\n";
770   out << QString( SPACING_INFO,   ' ' ) << tr( "1D_LAB" )           << "\n";
771   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i1D][iTotal]->property( "text" ) ).toString() << "\n";
772   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i1D][iLinear]->property( "text" ) ).toString() << "\n";
773   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" ) ).toString() << "\n";
774   out << QString( SPACING_INFO,   ' ' ) << tr( "2D_LAB" )           << "\n";
775   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2D][iTotal]->property( "text" ) ).toString() << "\n";
776   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2D][iLinear]->property( "text" ) ).toString() << "\n";
777   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" ) ).toString() << "\n";
778   out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" )    << "\n";
779   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" ) ).toString() << "\n";
780   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" ) ).toString() << "\n";
781   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" ) ).toString() << "\n";
782   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" )  << "\n";
783   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" ) ).toString() << "\n";
784   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" ) ).toString() << "\n";
785   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" ) ).toString() << "\n";
786   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" )     << "\n";
787   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n";
788   out << QString( SPACING_INFO,   ' ' ) << tr( "3D_LAB" )           << "\n";
789   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n";
790   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n";
791   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" ) ).toString() << "\n";
792   out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n";
793   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" ) ).toString() << "\n";
794   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" ) ).toString() << "\n";
795   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
796   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" )  << "\n";
797   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" ) ).toString() << "\n";
798   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" ) ).toString() << "\n";
799   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
800   out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" )     << "\n";
801   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" ) ).toString() << "\n";
802   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" ) ).toString() << "\n";
803   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" ) ).toString() << "\n";
804   out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" )       << "\n";
805   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" ) ).toString() << "\n";
806   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" ) ).toString() << "\n";
807   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" ) ).toString() << "\n";
808   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" )   << "\n";
809   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" ) ).toString() << "\n";
810   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" )  << "\n";
811   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" ) ).toString() << "\n" << "\n";
812 }
813
814 /*!
815   \class SMESHGUI_ElemInfo
816   \brief Base class for the mesh element information widget.
817 */
818
819 /*!
820   \brief Constructor
821   \param parent parent widget
822 */
823 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
824 : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
825 {
826   myFrame = new QWidget( this );
827   myExtra = new ExtraWidget( this );
828   QVBoxLayout* vbl = new QVBoxLayout( this );
829   vbl->setMargin( 0 );
830   vbl->setSpacing( 0 );
831   vbl->addWidget( myFrame );
832   vbl->addWidget( myExtra );
833   connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
834   connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
835   clear();
836 }
837
838 /*!
839   \brief Destructor
840 */
841 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
842 {
843 }
844
845 /*!
846   \brief Set mesh data source (actor)
847   \param actor mesh object actor
848 */
849 void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
850 {
851   if ( myActor != actor ) {
852     myActor = actor;
853     myIsElement = -1;
854     clear();
855   }
856 }
857
858 /*!
859   \brief Show mesh element information
860   \param id mesh node / element ID
861   \param isElem show mesh element information if \c true or mesh node information if \c false
862 */
863 void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
864 {
865   QSet<long> ids;
866   ids << id;
867   showInfo( ids, isElem );
868 }
869
870 /*!
871   \brief Show mesh element information
872   \param ids mesh nodes / elements identifiers
873   \param isElem show mesh element information if \c true or mesh node information if \c false
874 */
875 void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
876 {
877   QList<long> newIds = ids.toList();
878   qSort( newIds );
879   if ( myIDs == newIds && myIsElement == isElem ) return;
880
881   myIDs = newIds;
882   myIsElement = isElem;
883   myIndex = 0;
884   updateControls();
885   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
886 }
887
888 /*!
889   \brief Clear mesh element information widget
890 */
891 void SMESHGUI_ElemInfo::clear()
892 {
893   myIDs.clear();
894   myIndex = 0;
895   clearInternal();
896   updateControls();
897 }
898
899 /*!
900   \brief Get central area widget
901   \return central widget
902 */
903 QWidget* SMESHGUI_ElemInfo::frame() const
904 {
905   return myFrame;
906 }
907
908 /*!
909   \brief Get actor
910   \return actor being used
911 */
912 SMESH_Actor* SMESHGUI_ElemInfo::actor() const
913 {
914   return myActor;
915 }
916
917 /*!
918   \brief Get current info mode.
919   \return \c true if mesh element information is shown or \c false if node information is shown
920 */
921 bool SMESHGUI_ElemInfo::isElements() const
922 {
923   return myIsElement;
924 }
925
926 /*!
927   \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
928   \brief Show information on the specified nodes / elements
929
930   This function is to be redefined in sub-classes.
931
932   \param ids nodes / elements identifiers information is to be shown on
933 */
934
935 /*!
936   \brief Internal clean-up (reset widget)
937 */
938 void SMESHGUI_ElemInfo::clearInternal()
939 {
940 }
941
942 /*!
943   \brief Get node connectivity
944   \param node mesh node
945   \return node connectivity map
946 */
947 SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
948 {
949   Connectivity elmap;
950   if ( node ) {
951     SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
952     while ( it && it->more() ) {
953       const SMDS_MeshElement* ne = it->next();
954       elmap[ ne->GetType() ] << ne->GetID();
955     }
956   }
957   return elmap;
958 }
959
960 /*!
961   \brief Format connectivity data to string representation
962   \param connectivity connetivity map
963   \param type element type
964   \return string representation of the connectivity
965 */
966 QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
967 {
968   QStringList str;
969   if ( connectivity.contains( type ) ) {
970     QList<int> elements = connectivity[ type ];
971     qSort( elements );
972     foreach( int id, elements )
973       str << QString::number( id );
974   }
975   return str.join( " " );
976 }
977
978 /*!
979   \brief Calculate gravity center of the mesh element
980   \param element mesh element
981 */
982 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
983 {
984   XYZ xyz;
985   if ( element ) {
986     SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
987     while ( nodeIt->more() ) {
988       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
989       xyz.add( node->X(), node->Y(), node->Z() );
990     }
991     xyz.divide( element->NbNodes() );
992   }
993   return xyz;
994 }
995
996 /*!
997   \brief This slot is called from "Show Previous" button click.
998   Shows information on the previous group of the items.
999 */
1000 void SMESHGUI_ElemInfo::showPrevious()
1001 {
1002   myIndex = qMax( 0, myIndex-1 );
1003   updateControls();
1004   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1005 }
1006
1007 /*!
1008   \brief This slot is called from "Show Next" button click.
1009   Shows information on the next group of the items.
1010 */
1011 void SMESHGUI_ElemInfo::showNext()
1012 {
1013   myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
1014   updateControls();
1015   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1016 }
1017
1018 /*!
1019   \brief Update widgets state
1020 */
1021 void SMESHGUI_ElemInfo::updateControls()
1022 {
1023   myExtra->updateControls( myIDs.count(), myIndex );
1024 }
1025
1026 /*!
1027   \class SMESHGUI_SimpleElemInfo
1028   \brief Represents mesh element information in the simple text area.
1029 */
1030
1031 /*!
1032   \brief Constructor
1033   \param parent parent widget
1034 */
1035 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
1036 : SMESHGUI_ElemInfo( parent )
1037 {
1038   myInfo = new QTextBrowser( frame() );
1039   QVBoxLayout* l = new QVBoxLayout( frame() );
1040   l->setMargin( 0 );
1041   l->addWidget( myInfo );
1042 }
1043
1044 /*!
1045   \brief Show mesh element information
1046   \param ids mesh nodes / elements identifiers
1047 */
1048 void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
1049 {
1050   clearInternal();
1051   
1052   if ( actor() ) {
1053     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1054     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1055     int cprecision = -1;
1056     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1057       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1058     foreach ( long id, ids ) {
1059       if ( !isElements() ) {
1060         //
1061         // show node info
1062         //
1063         const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
1064         if ( !node ) return;
1065
1066         // node ID
1067         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( id ) );
1068         // separator
1069         myInfo->append( "" );
1070         // coordinates
1071         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1072                         arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1073                         arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1074                         arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1075         // separator
1076         myInfo->append( "" );
1077         // connectivity
1078         Connectivity connectivity = nodeConnectivity( node );
1079         if ( !connectivity.isEmpty() ) {
1080           myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1081           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1082           if ( !con.isEmpty() )
1083             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1084           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1085           if ( !con.isEmpty() )
1086             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1087           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1088           if ( !con.isEmpty() )
1089             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ).arg( con ) );
1090           con = formatConnectivity( connectivity, SMDSAbs_Face );
1091           if ( !con.isEmpty() )
1092             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1093           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1094           if ( !con.isEmpty() )
1095             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1096         }
1097         else {
1098           myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1099         }
1100         // node position
1101         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1102         if ( !CORBA::is_nil( aMeshPtr ) ) {
1103           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1104           int shapeID = pos->shapeID;
1105           if ( shapeID > 0 ) {
1106             QString shapeType;
1107             double u, v;
1108             switch ( pos->shapeType ) {
1109             case GEOM::EDGE:
1110               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1111               if ( pos->params.length() == 1 )
1112                 u = pos->params[0];
1113               break;
1114             case GEOM::FACE:
1115               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1116               if ( pos->params.length() == 2 ) {
1117                u = pos->params[0];
1118                v = pos->params[1];
1119               }
1120               break;
1121             case GEOM::VERTEX:
1122               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1123               break;
1124             default:
1125               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1126               break;
1127             }
1128             // separator
1129             myInfo->append( "" );
1130             myInfo->append( QString( "<b>%1:" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ) );
1131             myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( shapeType ).arg( shapeID ) );
1132             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1133               myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "U_POSITION" ) ).
1134                               arg( QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1135               if ( pos->shapeType == GEOM::FACE ) {
1136                 myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "V_POSITION" ) ).
1137                                 arg( QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1138               }
1139             }
1140           }
1141         }
1142         // groups node belongs to
1143         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1144         if ( !CORBA::is_nil( aMesh ) ) {
1145           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1146           myInfo->append( "" ); // separator
1147           bool top_created = false;
1148           for ( int i = 0; i < groups->length(); i++ ) {
1149             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1150             if ( CORBA::is_nil( aGrp ) ) continue;
1151             QString aName = aGrp->GetName();
1152             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1153               if ( !top_created ) {
1154                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1155                 top_created = true;
1156               }
1157               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1158               if ( grp_details ) {
1159                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1160                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1161                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1162                 
1163                 // type : group on geometry, standalone group, group on filter
1164                 if ( !CORBA::is_nil( aStdGroup ) ) {
1165                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1166                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1167                 }
1168                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1169                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1170                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1171                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1172                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1173                   if ( sobj ) {
1174                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1175                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1176                   }
1177                 }
1178                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1179                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1180                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1181                 }
1182                 
1183                 // size
1184                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1185                                 arg( QString::number( aGrp->Size() ) ) );
1186                 
1187                 // color
1188                 SALOMEDS::Color color = aGrp->GetColor();
1189                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1190                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1191               }
1192             }
1193           }
1194         }
1195       }
1196       else {
1197         //
1198         // show element info
1199         // 
1200         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1201         SMESH::Controls::NumericalFunctorPtr afunctor;
1202         if ( !e ) return;
1203         
1204         // Element ID && Type
1205         QString stype;
1206         switch( e->GetType() ) {
1207         case SMDSAbs_0DElement:
1208           stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1209         case SMDSAbs_Ball:
1210           stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1211         case SMDSAbs_Edge:
1212           stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1213         case SMDSAbs_Face:
1214           stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1215         case SMDSAbs_Volume:
1216           stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1217         default: 
1218           break;
1219         }
1220         if ( stype.isEmpty() ) return;
1221         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( stype ).arg( id ) );
1222         // separator
1223         myInfo->append( "" );
1224
1225         // Geometry type
1226         QString gtype;
1227         switch( e->GetEntityType() ) {
1228         case SMDSEntity_Triangle:
1229         case SMDSEntity_Quad_Triangle:
1230         case SMDSEntity_BiQuad_Triangle:
1231           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1232         case SMDSEntity_Quadrangle:
1233         case SMDSEntity_Quad_Quadrangle:
1234         case SMDSEntity_BiQuad_Quadrangle:
1235           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1236         case SMDSEntity_Polygon:
1237         case SMDSEntity_Quad_Polygon:
1238           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1239         case SMDSEntity_Tetra:
1240         case SMDSEntity_Quad_Tetra:
1241           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1242         case SMDSEntity_Pyramid:
1243         case SMDSEntity_Quad_Pyramid:
1244           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1245         case SMDSEntity_Hexa:
1246         case SMDSEntity_Quad_Hexa:
1247         case SMDSEntity_TriQuad_Hexa:
1248           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1249         case SMDSEntity_Penta:
1250         case SMDSEntity_Quad_Penta:
1251           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1252         case SMDSEntity_Hexagonal_Prism:
1253           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1254         case SMDSEntity_Polyhedra:
1255         case SMDSEntity_Quad_Polyhedra:
1256           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1257         default: 
1258           break;
1259         }
1260         if ( !gtype.isEmpty() )
1261           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" ) ).arg( gtype ) );
1262
1263         // Quadratic flag (any element except 0D)
1264         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1265           myInfo->append( QString( "<b>%1?</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ) );
1266         }
1267         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1268           // Ball diameter
1269           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() ));
1270         }
1271         // separator
1272         myInfo->append( "" );
1273
1274         // Connectivity
1275         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1276         for ( int idx = 1; nodeIt->more(); idx++ ) {
1277           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1278           // node number and ID
1279           myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
1280           // node coordinates
1281           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1282                           arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1283                           arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1284                           arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1285           // node connectivity
1286           Connectivity connectivity = nodeConnectivity( node );
1287           if ( !connectivity.isEmpty() ) {
1288             myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1289             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1290             if ( !con.isEmpty() )
1291               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1292             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1293             if ( !con.isEmpty() )
1294               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1295             con = formatConnectivity( connectivity, SMDSAbs_Face );
1296             if ( !con.isEmpty() )
1297               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1298             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1299             if ( !con.isEmpty() )
1300               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1301           }
1302           else {
1303             myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1304           }
1305         }
1306         // separator
1307         myInfo->append( "" );
1308
1309         // Controls
1310         myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" ) ) );
1311         //Length
1312         if ( e->GetType() == SMDSAbs_Edge ) {
1313           afunctor.reset( new SMESH::Controls::Length() );
1314           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1315           afunctor->SetPrecision( cprecision );
1316           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "LENGTH_EDGES" ) ).arg( afunctor->GetValue( id ) ) );  
1317         }
1318         if( e->GetType() == SMDSAbs_Face ) {
1319           //Area
1320           afunctor.reset(  new SMESH::Controls::Area() );
1321           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1322           afunctor->SetPrecision( cprecision );  
1323           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "AREA_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1324           //Taper
1325           afunctor.reset( new SMESH::Controls::Taper() );
1326           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1327           afunctor->SetPrecision( cprecision );
1328           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "TAPER_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1329           //AspectRatio2D
1330           afunctor.reset( new SMESH::Controls::AspectRatio() );
1331           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1332           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1333           //Minimum angle         
1334           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1335           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1336           afunctor->SetPrecision( cprecision );
1337           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1338           //Wraping angle        
1339           afunctor.reset( new SMESH::Controls::Warping() );
1340           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1341           afunctor->SetPrecision( cprecision );
1342           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1343           //Skew         
1344           afunctor.reset( new SMESH::Controls::Skew() );
1345           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1346           afunctor->SetPrecision( cprecision );
1347           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1348           //ElemDiam2D   
1349           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1350           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1351           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
1352         }
1353         if( e->GetType() == SMDSAbs_Volume ) {
1354           //AspectRatio3D
1355           afunctor.reset(  new SMESH::Controls::AspectRatio3D() );
1356           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1357           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1358           //Volume      
1359           afunctor.reset(  new SMESH::Controls::Volume() );
1360           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1361           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUME_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1362           //ElementDiameter3D    
1363           afunctor.reset(  new SMESH::Controls::Volume() );
1364           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1365           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" ) ).arg( afunctor->GetValue( id ) ) );
1366         }
1367         // separator
1368         myInfo->append( "" );
1369
1370         // Gravity center
1371         XYZ gc = gravityCenter( e );
1372         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1373
1374         // Element position
1375         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1376           SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();    
1377           if ( !CORBA::is_nil( aMesh ) ) {
1378             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1379             int shapeID = pos.shapeID;
1380             if ( shapeID > 0 ) {
1381               myInfo->append( "" ); // separator
1382               QString shapeType;
1383               switch ( pos.shapeType ) {
1384               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1385               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1386               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1387               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1388               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1389               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1390               }
1391               myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ).arg( shapeType ).arg( shapeID ) );
1392             }
1393           }
1394         }
1395
1396         // Groups the element belongs to
1397         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1398         if ( !CORBA::is_nil( aMesh ) ) {
1399           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1400           myInfo->append( "" ); // separator
1401           bool top_created = false;
1402           for ( int i = 0; i < groups->length(); i++ ) {
1403             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1404             if ( CORBA::is_nil( aGrp ) ) continue;
1405             QString aName = aGrp->GetName();
1406             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1407               if ( !top_created ) {
1408                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1409                 top_created = true;
1410               }
1411               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1412               if ( grp_details ) {
1413                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1414                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1415                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1416                 
1417                 // type : group on geometry, standalone group, group on filter
1418                 if ( !CORBA::is_nil( aStdGroup ) ) {
1419                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1420                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1421                 }
1422                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1423                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1424                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1425                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1426                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1427                   if ( sobj ) {
1428                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1429                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1430                   }
1431                 }
1432                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1433                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1434                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1435                 }
1436                 
1437                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1438                                 arg( QString::number( aGrp->Size() ) ) );
1439                 
1440                 // color
1441                 SALOMEDS::Color color = aGrp->GetColor();
1442                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1443                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1444               }
1445             }
1446           }
1447         }
1448       }
1449       // separator
1450       if ( ids.count() > 1 ) {
1451         myInfo->append( "" );
1452         myInfo->append( "------" );
1453         myInfo->append( "" );
1454       }
1455     }
1456   }
1457 }
1458
1459 /*!
1460   \brief Internal clean-up (reset widget)
1461 */
1462 void SMESHGUI_SimpleElemInfo::clearInternal()
1463 {
1464   myInfo->clear();
1465 }
1466
1467 void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out )
1468 {
1469   out << QString( 12, '-' ) << "\n";
1470   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
1471   out << QString( 12, '-' ) << "\n";
1472   out << myInfo->toPlainText();
1473   out << "\n";
1474 }
1475
1476
1477 /*!
1478   \class SMESHGUI_TreeElemInfo::ItemDelegate
1479   \brief Item delegate for tree mesh info widget
1480   \internal
1481 */
1482 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1483 {
1484 public:
1485   ItemDelegate( QObject* );
1486   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1487 };
1488
1489 /*!
1490   \brief Constructor
1491   \internal
1492 */
1493 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1494 {
1495 }
1496
1497 /*!
1498   \brief Create item editor widget
1499   \internal
1500 */
1501 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1502 {
1503   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1504   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1505   return w;
1506 }
1507
1508 /*!
1509   \class SMESHGUI_TreeElemInfo
1510   \brief Represents mesh element information in the tree-like form.
1511 */
1512
1513 /*!
1514   \brief Constructor
1515   \param parent parent widget
1516 */
1517 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1518 : SMESHGUI_ElemInfo( parent )
1519 {
1520   myInfo = new QTreeWidget( frame() );
1521   myInfo->setColumnCount( 2 );
1522   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1523   myInfo->header()->setStretchLastSection( true );
1524   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1525   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1526   QVBoxLayout* l = new QVBoxLayout( frame() );
1527   l->setMargin( 0 );
1528   l->addWidget( myInfo );
1529   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
1530 }
1531
1532 /*!
1533   \brief Show mesh element information
1534   \param ids mesh nodes / elements identifiers
1535 */
1536 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1537 {
1538   clearInternal();
1539
1540   if ( actor() ) {
1541     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1542     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1543     int cprecision = -1;
1544     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1545       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1546     foreach ( long id, ids ) {
1547       if ( !isElements() ) {
1548         //
1549         // show node info
1550         //
1551         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1552         if ( !e ) return;
1553         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1554       
1555         // node ID
1556         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1557         nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ) );
1558         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1559         // coordinates
1560         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1561         coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1562         QTreeWidgetItem* xItem = createItem( coordItem );
1563         xItem->setText( 0, "X" );
1564         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1565         QTreeWidgetItem* yItem = createItem( coordItem );
1566         yItem->setText( 0, "Y" );
1567         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1568         QTreeWidgetItem* zItem = createItem( coordItem );
1569         zItem->setText( 0, "Z" );
1570         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1571         // connectivity
1572         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1573         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1574         Connectivity connectivity = nodeConnectivity( node );
1575         if ( !connectivity.isEmpty() ) {
1576           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1577           if ( !con.isEmpty() ) {
1578             QTreeWidgetItem* i = createItem( conItem );
1579             i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1580             i->setText( 1, con );
1581           }
1582           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1583           if ( !con.isEmpty() ) {
1584             QTreeWidgetItem* i = createItem( conItem );
1585             i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1586             i->setText( 1, con );
1587             i->setData( 1, TypeRole, NodeConnectivity );
1588           }
1589           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1590           if ( !con.isEmpty() ) {
1591             QTreeWidgetItem* i = createItem( conItem );
1592             i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1593             i->setText( 1, con );
1594             i->setData( 1, TypeRole, NodeConnectivity );
1595           }
1596           con = formatConnectivity( connectivity, SMDSAbs_Face );
1597           if ( !con.isEmpty() ) {
1598             QTreeWidgetItem* i = createItem( conItem );
1599             i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1600             i->setText( 1, con );
1601             i->setData( 1, TypeRole, NodeConnectivity );
1602           }
1603           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1604           if ( !con.isEmpty() ) {
1605             QTreeWidgetItem* i = createItem( conItem );
1606             i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1607             i->setText( 1, con );
1608             i->setData( 1, TypeRole, NodeConnectivity );
1609           }
1610         }
1611         else {
1612           conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ) );
1613         }
1614         // node position
1615         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1616         if ( !CORBA::is_nil( aMeshPtr ) ) {
1617           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1618           int shapeID = pos->shapeID;
1619           if ( shapeID > 0 ) {
1620             QString shapeType;
1621             double u, v;
1622             switch ( pos->shapeType ) {
1623             case GEOM::EDGE:
1624               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1625               if ( pos->params.length() == 1 )
1626                 u = pos->params[0];
1627               break;
1628             case GEOM::FACE:
1629               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1630               if ( pos->params.length() == 2 ) {
1631                 u = pos->params[0];
1632                 v = pos->params[1];
1633               }
1634               break;
1635             case GEOM::VERTEX:
1636               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1637               break;
1638             default:
1639               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1640               break;
1641             }
1642             QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
1643             posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") );
1644             posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
1645             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1646               QTreeWidgetItem* uItem = createItem( posItem );
1647               uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") );
1648               uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
1649               if ( pos->shapeType == GEOM::FACE ) {
1650                 QTreeWidgetItem* vItem = createItem( posItem );
1651                 vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") );
1652                 vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
1653               }
1654             }
1655           }
1656         }
1657         // groups node belongs to
1658         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1659         if ( !CORBA::is_nil( aMesh ) ) {
1660           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1661           QTreeWidgetItem* groupsItem = 0;
1662           for ( int i = 0; i < groups->length(); i++ ) {
1663             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1664             if ( CORBA::is_nil( aGrp ) ) continue;
1665             QString aName = aGrp->GetName();
1666             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1667               if ( !groupsItem ) {
1668                 groupsItem = createItem( nodeItem, Bold );
1669                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1670               }
1671               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1672               it->setText( 0, aName.trimmed() );
1673               if ( grp_details ) {
1674                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1675                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1676                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1677                 
1678                 // type : group on geometry, standalone group, group on filter
1679                 QTreeWidgetItem* typeItem = createItem( it );
1680                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1681                 if ( !CORBA::is_nil( aStdGroup ) ) {
1682                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1683                 }
1684                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1685                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1686                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1687                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1688                   if ( sobj ) {
1689                     QTreeWidgetItem* gobjItem = createItem( typeItem );
1690                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
1691                     gobjItem->setText( 1, sobj->GetName().c_str() );
1692                   }
1693                 }
1694                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1695                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1696                 }
1697                 
1698                 // size
1699                 QTreeWidgetItem* sizeItem = createItem( it );
1700                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
1701                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
1702                 
1703                 // color
1704                 SALOMEDS::Color color = aGrp->GetColor();
1705                 QTreeWidgetItem* colorItem = createItem( it );
1706                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
1707                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1708               }
1709             }
1710           }
1711         }
1712       }
1713       else {
1714         //
1715         // show element info
1716         // 
1717         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1718         SMESH::Controls::NumericalFunctorPtr afunctor;
1719         if ( !e ) return;
1720         
1721         // element ID && type
1722         QString stype;
1723         switch( e->GetType() ) {
1724         case SMDSAbs_0DElement: stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1725         case SMDSAbs_Ball:      stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1726         case SMDSAbs_Edge:      stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1727         case SMDSAbs_Face:      stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1728         case SMDSAbs_Volume:    stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1729         default:;
1730         }
1731         if ( stype.isEmpty() ) return;
1732         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1733         elemItem->setText( 0, stype );
1734         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1735         // geometry type
1736         QString gtype;
1737         switch( e->GetEntityType() ) {
1738         case SMDSEntity_Triangle:
1739         case SMDSEntity_Quad_Triangle:
1740         case SMDSEntity_BiQuad_Triangle:
1741           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1742         case SMDSEntity_Quadrangle:
1743         case SMDSEntity_Quad_Quadrangle:
1744         case SMDSEntity_BiQuad_Quadrangle:
1745           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1746         case SMDSEntity_Polygon:
1747         case SMDSEntity_Quad_Polygon:
1748           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1749         case SMDSEntity_Tetra:
1750         case SMDSEntity_Quad_Tetra:
1751           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1752         case SMDSEntity_Pyramid:
1753         case SMDSEntity_Quad_Pyramid:
1754           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1755         case SMDSEntity_Hexa:
1756         case SMDSEntity_Quad_Hexa:
1757         case SMDSEntity_TriQuad_Hexa:
1758           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1759         case SMDSEntity_Penta:
1760         case SMDSEntity_Quad_Penta:
1761           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1762         case SMDSEntity_Hexagonal_Prism:
1763           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1764         case SMDSEntity_Polyhedra:
1765         case SMDSEntity_Quad_Polyhedra:
1766           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1767         default: 
1768           break;
1769         }
1770         if ( !gtype.isEmpty() ) {
1771           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1772           typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ) );
1773           typeItem->setText( 1, gtype );
1774         }
1775         // quadratic flag (for edges, faces and volumes)
1776         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1777           // quadratic flag
1778           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1779           quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ) );
1780           quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) );
1781         }
1782         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1783           // ball diameter
1784           QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
1785           diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) );
1786           diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
1787         }
1788         // connectivity
1789         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1790         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1791         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1792         for ( int idx = 1; nodeIt->more(); idx++ ) {
1793           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1794           // node number and ID
1795           QTreeWidgetItem* nodeItem = createItem( conItem, Bold );
1796           nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
1797           nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
1798           nodeItem->setData( 1, TypeRole, ElemConnectivity );
1799           nodeItem->setData( 1, IdRole, node->GetID() );
1800           nodeItem->setExpanded( false );
1801           // node coordinates
1802           QTreeWidgetItem* coordItem = createItem( nodeItem );
1803           coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1804           QTreeWidgetItem* xItem = createItem( coordItem );
1805           xItem->setText( 0, "X" );
1806           xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1807           QTreeWidgetItem* yItem = createItem( coordItem );
1808           yItem->setText( 0, "Y" );
1809           yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1810           QTreeWidgetItem* zItem = createItem( coordItem );
1811           zItem->setText( 0, "Z" );
1812           zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1813           // node connectivity
1814           QTreeWidgetItem* nconItem = createItem( nodeItem );
1815           nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1816           Connectivity connectivity = nodeConnectivity( node );
1817           if ( !connectivity.isEmpty() ) {
1818             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1819             if ( !con.isEmpty() ) {
1820               QTreeWidgetItem* i = createItem( nconItem );
1821               i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1822               i->setText( 1, con );
1823             }
1824             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1825             if ( !con.isEmpty() ) {
1826               QTreeWidgetItem* i = createItem( nconItem );
1827               i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1828               i->setText( 1, con );
1829               i->setData( 1, TypeRole, NodeConnectivity );
1830             }
1831             con = formatConnectivity( connectivity, SMDSAbs_Ball );
1832             if ( !con.isEmpty() ) {
1833               QTreeWidgetItem* i = createItem( nconItem );
1834               i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1835               i->setText( 1, con );
1836               i->setData( 1, TypeRole, NodeConnectivity );
1837             }
1838             con = formatConnectivity( connectivity, SMDSAbs_Face );
1839             if ( !con.isEmpty() ) {
1840               QTreeWidgetItem* i = createItem( nconItem );
1841               i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1842               i->setText( 1, con );
1843               i->setData( 1, TypeRole, NodeConnectivity );
1844             }
1845             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1846             if ( !con.isEmpty() ) {
1847               QTreeWidgetItem* i = createItem( nconItem );
1848               i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1849               i->setText( 1, con );
1850               i->setData( 1, TypeRole, NodeConnectivity );
1851             }
1852           }
1853         }
1854         //Controls
1855         QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
1856         cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ) );
1857         //Length
1858         if( e->GetType()==SMDSAbs_Edge){         
1859           afunctor.reset( new SMESH::Controls::Length() );
1860           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1861           afunctor->SetPrecision( cprecision );
1862           QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
1863           lenItem->setText( 0, tr( "LENGTH_EDGES" ) );
1864           lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );         
1865         }
1866         if( e->GetType() == SMDSAbs_Face ) {
1867           //Area         
1868           afunctor.reset( new SMESH::Controls::Area() );        
1869           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1870           afunctor->SetPrecision( cprecision );
1871           QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
1872           areaItem->setText( 0, tr( "AREA_ELEMENTS" ) );
1873           areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ) );         
1874           //Taper
1875           afunctor.reset( new SMESH::Controls::Taper() );
1876           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1877           afunctor->SetPrecision( cprecision );
1878           QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
1879           taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ) );
1880           taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1881           //AspectRatio2D
1882           afunctor.reset( new SMESH::Controls::AspectRatio() );
1883           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1884           QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
1885           ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
1886           ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1887           //Minimum angle
1888           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1889           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1890           afunctor->SetPrecision( cprecision );
1891           QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
1892           minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ) );
1893           minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1894           //Wraping angle       
1895           afunctor.reset( new SMESH::Controls::Warping() );
1896           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1897           afunctor->SetPrecision( cprecision );
1898           QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
1899           warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
1900           warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );        
1901           //Skew          
1902           afunctor.reset( new SMESH::Controls::Skew() );
1903           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1904           afunctor->SetPrecision( cprecision );
1905           QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
1906           skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
1907           skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1908           //ElemDiam2D    
1909           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1910           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1911           QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
1912           diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
1913           diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1914         }
1915         if( e->GetType() == SMDSAbs_Volume ) {
1916           //AspectRatio3D
1917           afunctor.reset( new SMESH::Controls::AspectRatio3D() );
1918           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1919           QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
1920           ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
1921           ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1922           //Volume
1923           afunctor.reset( new SMESH::Controls::Volume() );
1924           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1925           QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
1926           volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ) );
1927           volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1928           //ElementDiameter3D
1929           afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
1930           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1931           QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
1932           diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) );
1933           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );     
1934         }
1935
1936         // gravity center
1937         XYZ gc = gravityCenter( e );
1938         QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
1939         gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) );
1940         QTreeWidgetItem* xItem = createItem( gcItem );
1941         xItem->setText( 0, "X" );
1942         xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1943         QTreeWidgetItem* yItem = createItem( gcItem );
1944         yItem->setText( 0, "Y" );
1945         yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1946         QTreeWidgetItem* zItem = createItem( gcItem );
1947         zItem->setText( 0, "Z" );
1948         zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1949         // element position
1950         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1951         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1952           if ( !CORBA::is_nil( aMesh ) ) {
1953             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1954             int shapeID = pos.shapeID;
1955             if ( shapeID > 0 ) {
1956               QTreeWidgetItem* shItem = createItem( elemItem, Bold );
1957               QString shapeType;
1958               switch ( pos.shapeType ) {
1959               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1960               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1961               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1962               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1963               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1964               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1965               }
1966               shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ) );
1967               shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ) );
1968             }
1969           }
1970         }
1971         // groups element belongs to
1972         if ( !CORBA::is_nil( aMesh ) ) {
1973           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1974           QTreeWidgetItem* groupsItem = 0;
1975           for ( int i = 0; i < groups->length(); i++ ) {
1976             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1977             if ( CORBA::is_nil( aGrp ) ) continue;
1978             QString aName = aGrp->GetName();
1979             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1980               if ( !groupsItem ) {
1981                 groupsItem = createItem( elemItem, Bold );
1982                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1983               }
1984               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1985               it->setText( 0, aName.trimmed() );
1986               if ( grp_details ) {
1987                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1988                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1989                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1990                 
1991                 // type : group on geometry, standalone group, group on filter
1992                 QTreeWidgetItem* typeItem = createItem( it );
1993                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1994                 if ( !CORBA::is_nil( aStdGroup ) ) {
1995                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1996                 }
1997                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1998                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1999                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2000                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2001                   if ( sobj ) {
2002                     QTreeWidgetItem* gobjItem = createItem( typeItem );
2003                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
2004                     gobjItem->setText( 1, sobj->GetName().c_str() );
2005                   }
2006                 }
2007                 else if ( !CORBA::is_nil( aFltGroup ) ) {
2008                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
2009                 }
2010                 
2011                 // size
2012                 QTreeWidgetItem* sizeItem = createItem( it );
2013                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
2014                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
2015                 
2016                 // color
2017                 SALOMEDS::Color color = aGrp->GetColor();
2018                 QTreeWidgetItem* colorItem = createItem( it );
2019                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
2020                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2021               }
2022             }
2023           }
2024         }
2025       }
2026     }
2027   }
2028 }
2029
2030 /*!
2031   \brief Internal clean-up (reset widget)
2032 */
2033 void SMESHGUI_TreeElemInfo::clearInternal()
2034 {
2035   myInfo->clear();
2036   myInfo->repaint();
2037 }
2038
2039 /*!
2040   \brief Create new tree item.
2041   \param parent parent tree widget item
2042   \param flags item flag
2043   \return new tree widget item
2044 */
2045 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
2046 {
2047   QTreeWidgetItem* item;
2048   if ( parent )
2049     item = new QTreeWidgetItem( parent );
2050   else
2051     item = new QTreeWidgetItem( myInfo );
2052
2053   item->setFlags( item->flags() | Qt::ItemIsEditable );
2054
2055   QFont f = item->font( 0 );
2056   f.setBold( true );
2057   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
2058     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2059       item->setFont( i, f );
2060   }
2061
2062   item->setExpanded( true );
2063   return item;
2064 }
2065
2066 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2067 {
2068   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2069   if ( widgets.isEmpty() ) return;
2070   QTreeWidgetItem* aTreeItem = widgets.first();
2071   int type = aTreeItem->data( 1, TypeRole ).toInt();
2072   int id   = aTreeItem->data( 1, IdRole ).toInt();
2073   QMenu menu;
2074   QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ) );
2075   if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a )
2076     emit( itemInfo( id ) );
2077   else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a )
2078     emit( itemInfo( aTreeItem->text( 1 ) ) );
2079 }
2080
2081 void  SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
2082 {
2083   if ( theItem ) {
2084     int type = theItem->data( 1, TypeRole ).toInt();
2085     int id   = theItem->data( 1, IdRole ).toInt();
2086     if ( type == ElemConnectivity && id > 0 )
2087       emit( itemInfo( id ) );
2088     else if ( type == NodeConnectivity )
2089       emit( itemInfo( theItem->text( 1 ) ) );
2090   }
2091 }
2092
2093 void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
2094 {
2095   out << QString( 12, '-' ) << "\n";
2096   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
2097   out << QString( 12, '-' ) << "\n";
2098
2099   QTreeWidgetItemIterator it( myInfo );
2100   while ( *it ) {
2101     if ( !( *it )->text(0).isEmpty() ) {
2102       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2103       if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1);
2104       out << "\n";
2105     }
2106     ++it;
2107   }
2108   out << "\n";
2109 }
2110
2111 /*!
2112   \class GrpComputor
2113   \brief Mesh information computer
2114   \internal
2115   
2116   The class is created for different computation operation. Currently it is used
2117   to compute number of underlying nodes for the groups.
2118 */
2119
2120 /*!
2121   \brief Contructor
2122 */
2123 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
2124   : QObject( parent ), myItem( item )
2125 {
2126   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
2127 }
2128
2129 /*!
2130   \brief Compute function
2131 */
2132 void GrpComputor::compute()
2133 {
2134   if ( !CORBA::is_nil( myGroup ) && myItem ) {
2135     QTreeWidgetItem* item = myItem;
2136     myItem = 0;
2137     int nbNodes = myGroup->GetNumberOfNodes();
2138     item->treeWidget()->removeItemWidget( item, 1 );
2139     item->setText( 1, QString::number( nbNodes ));
2140   }
2141 }
2142
2143 /*!
2144   \class SMESHGUI_AddInfo
2145   \brief The wigdet shows additional information on the mesh object.
2146 */
2147
2148 /*!
2149   \brief Constructor
2150   \param parent parent widget
2151 */
2152 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2153 : QTreeWidget( parent )
2154 {
2155   setColumnCount( 2 );
2156   header()->setStretchLastSection( true );
2157   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2158   header()->hide();
2159 }
2160
2161 /*!
2162   \brief Destructor
2163 */
2164 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2165 {
2166 }
2167
2168 /*!
2169   \brief Show additional information on the selected object
2170   \param obj object being processed (mesh, sub-mesh, group, ID source)
2171 */
2172 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2173 {
2174   setProperty( "group_index", 0 );
2175   setProperty( "submesh_index",  0 );
2176   myComputors.clear();
2177   clear();
2178
2179   if ( CORBA::is_nil( obj ) ) return;
2180
2181   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2182   if ( !sobj ) return;
2183
2184   // name
2185   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2186   nameItem->setText( 0, tr( "NAME" ) );
2187   nameItem->setText( 1, sobj->GetName().c_str() );
2188   
2189   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2190   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2191   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2192   
2193   if ( !aMesh->_is_nil() )
2194     meshInfo( aMesh, nameItem );
2195   else if ( !aSubMesh->_is_nil() )
2196     subMeshInfo( aSubMesh, nameItem );
2197   else if ( !aGroup->_is_nil() )
2198     groupInfo( aGroup.in(), nameItem );
2199 }
2200
2201 /*!
2202   \brief Create new tree item.
2203   \param parent parent tree widget item
2204   \param flags item flag
2205   \return new tree widget item
2206 */
2207 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2208 {
2209   QTreeWidgetItem* item;
2210
2211   if ( parent )
2212     item = new QTreeWidgetItem( parent );
2213   else
2214     item = new QTreeWidgetItem( this );
2215
2216   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2217
2218   QFont f = item->font( 0 );
2219   f.setBold( true );
2220   for ( int i = 0; i < columnCount(); i++ ) {
2221     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2222       item->setFont( i, f );
2223   }
2224
2225   item->setExpanded( true );
2226   return item;
2227 }
2228
2229 /*!
2230   \brief Show mesh info
2231   \param mesh mesh object
2232   \param parent parent tree item
2233 */
2234 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2235 {
2236   // type
2237   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2238   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2239   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2240   typeItem->setText( 0, tr( "TYPE" ) );
2241   if ( !CORBA::is_nil( shape ) ) {
2242     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2243     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2244     if ( sobj ) {
2245       QTreeWidgetItem* gobjItem = createItem( typeItem );
2246       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2247       gobjItem->setText( 1, sobj->GetName().c_str() );
2248     }
2249   }
2250   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2251     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2252     QTreeWidgetItem* fileItem = createItem( typeItem );
2253     fileItem->setText( 0, tr( "FILE_NAME" ) );
2254     fileItem->setText( 1, (char*)inf->fileName );
2255   }
2256   else {
2257     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2258   }
2259   
2260   // groups
2261   myGroups = mesh->GetGroups();
2262   showGroups();
2263
2264   // sub-meshes
2265   mySubMeshes = mesh->GetSubMeshes();
2266   showSubMeshes();
2267 }
2268
2269 /*!
2270   \brief Show sub-mesh info
2271   \param subMesh sub-mesh object
2272   \param parent parent tree item
2273 */
2274 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2275 {
2276   bool isShort = parent->parent() != 0;
2277
2278   if ( !isShort ) {
2279     // parent mesh
2280     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2281     if ( sobj ) {
2282       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2283       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2284       nameItem->setText( 1, sobj->GetName().c_str() );
2285     }
2286   }
2287   
2288   // shape
2289   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2290   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2291   if ( sobj ) {
2292     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2293     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2294     gobjItem->setText( 1, sobj->GetName().c_str() );
2295   }
2296 }
2297
2298 /*!
2299   \brief Show group info
2300   \param grp mesh group object
2301   \param parent parent tree item
2302 */
2303 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2304 {
2305   bool isShort = parent->parent() != 0;
2306
2307   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2308   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2309   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2310
2311   if ( !isShort ) {
2312     // parent mesh
2313     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2314     if ( sobj ) {
2315       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2316       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2317       nameItem->setText( 1, sobj->GetName().c_str() );
2318     }
2319   }
2320
2321   // type : group on geometry, standalone group, group on filter
2322   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2323   typeItem->setText( 0, tr( "TYPE" ) );
2324   if ( !CORBA::is_nil( aStdGroup ) ) {
2325     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2326   }
2327   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2328     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2329     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2330     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2331     if ( sobj ) {
2332       QTreeWidgetItem* gobjItem = createItem( typeItem );
2333       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2334       gobjItem->setText( 1, sobj->GetName().c_str() );
2335     }
2336   }
2337   else if ( !CORBA::is_nil( aFltGroup ) ) {
2338     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2339   }
2340
2341   if ( !isShort ) {
2342     // entity type
2343     QString etype = tr( "UNKNOWN" );
2344     switch( grp->GetType() ) {
2345     case SMESH::NODE:
2346       etype = tr( "NODE" );
2347       break;
2348     case SMESH::EDGE:
2349       etype = tr( "EDGE" );
2350       break;
2351     case SMESH::FACE:
2352       etype = tr( "FACE" );
2353       break;
2354     case SMESH::VOLUME:
2355       etype = tr( "VOLUME" );
2356       break;
2357     case SMESH::ELEM0D:
2358       etype = tr( "0DELEM" );
2359       break;
2360     case SMESH::BALL:
2361       etype = tr( "BALL" );
2362       break;
2363     default:
2364       break;
2365     }
2366     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2367     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2368     etypeItem->setText( 1, etype );
2369   }
2370
2371   // size
2372   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2373   sizeItem->setText( 0, tr( "SIZE" ) );
2374   sizeItem->setText( 1, QString::number( grp->Size() ) );
2375
2376   // color
2377   SALOMEDS::Color color = grp->GetColor();
2378   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2379   colorItem->setText( 0, tr( "COLOR" ) );
2380   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2381
2382   // nb of underlying nodes
2383   if ( grp->GetType() != SMESH::NODE) {
2384     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2385     nodesItem->setText( 0, tr( "NB_NODES" ) );
2386     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2387     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2388     bool meshLoaded = mesh->IsLoaded();
2389     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
2390     if ( toShowNodes && meshLoaded ) {
2391       // already calculated and up-to-date
2392       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2393     }
2394     else {
2395       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2396       setItemWidget( nodesItem, 1, btn );
2397       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2398       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2399       myComputors.append( comp );
2400       if ( !meshLoaded )
2401         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2402     }
2403   }
2404 }
2405
2406 void SMESHGUI_AddInfo::showGroups()
2407 {
2408   myComputors.clear();
2409
2410   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2411   if ( !parent ) return;
2412
2413   int idx = property( "group_index" ).toInt();
2414
2415   QTreeWidgetItem* itemGroups = 0;
2416   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2417     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2418       itemGroups = parent->child( i );
2419       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2420       if ( extra )
2421         extra->updateControls( myGroups->length(), idx );
2422       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2423     }
2424   }
2425
2426   QMap<int, QTreeWidgetItem*> grpItems;
2427   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2428     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2429     if ( CORBA::is_nil( grp ) ) continue;
2430     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2431     if ( !grpSObj ) continue;
2432
2433     int grpType = grp->GetType();
2434
2435     if ( !itemGroups ) {
2436       // create top-level groups container item
2437       itemGroups = createItem( parent, Bold | All );
2438       itemGroups->setText( 0, tr( "GROUPS" ) );
2439       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2440
2441       // total number of groups > 10, show extra widgets for info browsing
2442       if ( myGroups->length() > MAXITEMS ) {
2443         ExtraWidget* extra = new ExtraWidget( this, true );
2444         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2445         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2446         setItemWidget( itemGroups, 1, extra );
2447         extra->updateControls( myGroups->length(), idx );
2448       }
2449     }
2450
2451     if ( grpItems.find( grpType ) == grpItems.end() ) {
2452       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2453       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2454       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2455     }
2456   
2457     // group name
2458     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2459     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2460
2461     // group info
2462     groupInfo( grp.in(), grpNameItem );
2463   }
2464 }
2465
2466 void SMESHGUI_AddInfo::showSubMeshes()
2467 {
2468   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2469   if ( !parent ) return;
2470
2471   int idx = property( "submesh_index" ).toInt();
2472
2473   QTreeWidgetItem* itemSubMeshes = 0;
2474   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2475     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2476       itemSubMeshes = parent->child( i );
2477       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2478       if ( extra )
2479         extra->updateControls( mySubMeshes->length(), idx );
2480       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2481     }
2482   }
2483
2484   QMap<int, QTreeWidgetItem*> smItems;
2485   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2486     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2487     if ( CORBA::is_nil( sm ) ) continue;
2488     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2489     if ( !smSObj ) continue;
2490     
2491     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2492     if ( CORBA::is_nil(gobj ) ) continue;
2493     
2494     int smType = gobj->GetShapeType();
2495     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2496
2497     if ( !itemSubMeshes ) {
2498       itemSubMeshes = createItem( parent, Bold | All );
2499       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2500       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2501
2502       // total number of sub-meshes > 10, show extra widgets for info browsing
2503       if ( mySubMeshes->length() > MAXITEMS ) {
2504         ExtraWidget* extra = new ExtraWidget( this, true );
2505         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2506         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2507         setItemWidget( itemSubMeshes, 1, extra );
2508         extra->updateControls( mySubMeshes->length(), idx );
2509       }
2510     }
2511          
2512     if ( smItems.find( smType ) == smItems.end() ) {
2513       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2514       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2515       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2516     }
2517     
2518     // submesh name
2519     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2520     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2521     
2522     // submesh info
2523     subMeshInfo( sm.in(), smNameItem );
2524   }
2525 }
2526
2527 /*!
2528  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2529  */
2530 void SMESHGUI_AddInfo::changeLoadToCompute()
2531 {
2532   for ( int i = 0; i < myComputors.count(); ++i )
2533   {
2534     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2535     {
2536       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2537         btn->setText( tr("COMPUTE") );
2538     }
2539   }
2540 }
2541
2542 void SMESHGUI_AddInfo::showPreviousGroups()
2543 {
2544   int idx = property( "group_index" ).toInt();
2545   setProperty( "group_index", idx-1 );
2546   showGroups();
2547 }
2548
2549 void SMESHGUI_AddInfo::showNextGroups()
2550 {
2551   int idx = property( "group_index" ).toInt();
2552   setProperty( "group_index", idx+1 );
2553   showGroups();
2554 }
2555
2556 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2557 {
2558   int idx = property( "submesh_index" ).toInt();
2559   setProperty( "submesh_index", idx-1 );
2560   showSubMeshes();
2561 }
2562
2563 void SMESHGUI_AddInfo::showNextSubMeshes()
2564 {
2565   int idx = property( "submesh_index" ).toInt();
2566   setProperty( "submesh_index", idx+1 );
2567   showSubMeshes();
2568 }
2569
2570 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2571 {
2572   out << QString( 15, '-')       << "\n";
2573   out << tr( "ADDITIONAL_INFO" ) << "\n";
2574   out << QString( 15, '-' )      << "\n";
2575   QTreeWidgetItemIterator it( this );
2576   while ( *it ) {
2577     if ( !( ( *it )->text(0) ).isEmpty() ) {
2578       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2579       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2580         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2581       }
2582       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2583       out << "\n";
2584     }
2585     ++it;
2586   }
2587   out << "\n";
2588 }
2589
2590 /*!
2591   \class SMESHGUI_MeshInfoDlg
2592   \brief Mesh information dialog box
2593 */
2594
2595 /*!
2596   \brief Constructor
2597   \param parent parent widget
2598   \param page specifies the dialog page to be shown at the start-up
2599 */
2600 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2601 : QDialog( parent ), myActor( 0 )
2602 {
2603   setModal( false );
2604   setAttribute( Qt::WA_DeleteOnClose, true );
2605   setWindowTitle( tr( "MESH_INFO" ) );
2606   setSizeGripEnabled( true );
2607
2608   myTabWidget = new QTabWidget( this );
2609
2610   // base info 
2611
2612   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2613   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2614
2615   // elem info 
2616   
2617   QWidget* w = new QWidget( myTabWidget );
2618
2619   myMode = new QButtonGroup( this );
2620   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2621   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2622   myMode->button( NodeMode )->setChecked( true );
2623   myID = new QLineEdit( w );
2624   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2625
2626   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2627   mode = qMin( 1, qMax( 0, mode ) );
2628   
2629   if ( mode == 0 ) 
2630     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2631   else
2632     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2633
2634   QGridLayout* elemLayout = new QGridLayout( w );
2635   elemLayout->setMargin( MARGIN );
2636   elemLayout->setSpacing( SPACING );
2637   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2638   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2639   elemLayout->addWidget( myID, 0, 2 );
2640   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2641   
2642   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2643
2644   // additional info
2645
2646   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2647   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2648
2649   // controls info
2650
2651   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
2652   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
2653
2654   // buttons
2655
2656   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2657   okBtn->setAutoDefault( true );
2658   okBtn->setDefault( true );
2659   okBtn->setFocus();
2660   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2661   dumpBtn->setAutoDefault( true );
2662   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2663   helpBtn->setAutoDefault( true );
2664
2665   QHBoxLayout* btnLayout = new QHBoxLayout;
2666   btnLayout->setSpacing( SPACING );
2667   btnLayout->setMargin( 0 );
2668
2669   btnLayout->addWidget( okBtn );
2670   btnLayout->addWidget( dumpBtn );
2671   btnLayout->addStretch( 10 );
2672   btnLayout->addWidget( helpBtn );
2673
2674   QVBoxLayout* l = new QVBoxLayout ( this );
2675   l->setMargin( MARGIN );
2676   l->setSpacing( SPACING );
2677   l->addWidget( myTabWidget );
2678   l->addLayout( btnLayout );
2679
2680   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2681
2682   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2683   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2684   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2685   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2686   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2687   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2688   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2689   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2690   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2691   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2692
2693   updateSelection();
2694 }
2695
2696 /*!
2697   \brief Destructor
2698 */
2699 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2700 {
2701 }
2702
2703 /*!
2704   \brief Show mesh information
2705   \param IO interactive object
2706 */
2707 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2708 {
2709   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2710   if ( !CORBA::is_nil( obj ) ) {
2711     myBaseInfo->showInfo( obj );
2712     myAddInfo->showInfo( obj );
2713     myCtrlInfo->showInfo( obj );
2714
2715     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2716     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2717     QString ID;
2718     int nb = 0;
2719     if ( myActor && selector ) {
2720       nb = myMode->checkedId() == NodeMode ? 
2721         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2722         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2723     }
2724     myElemInfo->setSource( myActor ) ;
2725     if ( nb > 0 ) {
2726       myID->setText( ID.trimmed() );
2727       QSet<long> ids;
2728       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2729       foreach ( ID, idTxt )
2730         ids << ID.trimmed().toLong();
2731       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2732     }
2733     else {
2734       myID->clear();
2735       myElemInfo->clear();
2736     }
2737   }
2738 }
2739
2740 /*!
2741   \brief Perform clean-up actions on the dialog box closing.
2742 */
2743 void SMESHGUI_MeshInfoDlg::reject()
2744 {
2745   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2746   selMgr->clearFilters();
2747   SMESH::SetPointRepresentation( false );
2748   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2749     aViewWindow->SetSelectionMode( ActorSelection );
2750   QDialog::reject();
2751 }
2752
2753 /*!
2754   \brief Process keyboard event
2755   \param e key press event
2756 */
2757 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2758 {
2759   QDialog::keyPressEvent( e );
2760   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2761     e->accept();
2762     help();
2763   }
2764 }
2765
2766 /*!
2767   \brief Reactivate dialog box, when mouse pointer goes into it.
2768 */
2769 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2770 {
2771   //activate();
2772 }
2773
2774 /*!
2775   \brief Setup selection mode depending on the current dialog box state.
2776 */
2777 void SMESHGUI_MeshInfoDlg::updateSelection()
2778 {
2779   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2780
2781   disconnect( selMgr, 0, this, 0 );
2782   selMgr->clearFilters();
2783
2784   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo || myTabWidget->currentIndex() == CtrlInfo ) {
2785     SMESH::SetPointRepresentation( false );
2786     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2787       aViewWindow->SetSelectionMode( ActorSelection );
2788   }
2789   else {
2790     if ( myMode->checkedId() == NodeMode ) {
2791       SMESH::SetPointRepresentation( true );
2792       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2793         aViewWindow->SetSelectionMode( NodeSelection );
2794     }
2795     else {
2796       SMESH::SetPointRepresentation( false );
2797       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2798         aViewWindow->SetSelectionMode( CellSelection );
2799     }
2800   }
2801
2802   QString oldID = myID->text().trimmed();
2803   SMESH_Actor* oldActor = myActor;
2804   myID->clear();
2805   
2806   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2807   updateInfo();
2808   
2809   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
2810     myID->setText( oldID );
2811     idChanged();
2812   }
2813 }
2814
2815 /*!
2816   \brief Show help page
2817 */
2818 void SMESHGUI_MeshInfoDlg::help()
2819 {
2820   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
2821                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
2822                        "mesh_infos_page.html#mesh_element_info_anchor" );
2823 }
2824
2825 /*!
2826   \brief Show mesh information
2827 */
2828 void SMESHGUI_MeshInfoDlg::updateInfo()
2829 {
2830   SUIT_OverrideCursor wc;
2831
2832   SALOME_ListIO selected;
2833   SMESHGUI::selectionMgr()->selectedObjects( selected );
2834
2835   if ( selected.Extent() == 1 ) {
2836     Handle(SALOME_InteractiveObject) IO = selected.First();
2837     showInfo( IO );
2838   }
2839 //   else {
2840 //     myBaseInfo->clear();
2841 //     myElemInfo->clear();
2842 //     myAddInfo->clear();
2843 //   }
2844 }
2845
2846 /*!
2847   \brief Activate dialog box
2848 */
2849 void SMESHGUI_MeshInfoDlg::activate()
2850 {
2851   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
2852   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
2853   myTabWidget->setEnabled( true );
2854   updateSelection();
2855 }
2856
2857 /*!
2858   \brief Deactivate dialog box
2859 */
2860 void SMESHGUI_MeshInfoDlg::deactivate()
2861 {
2862   myTabWidget->setEnabled( false );
2863   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2864 }
2865
2866 /*!
2867   \brief Called when users switches between node / element modes.
2868 */
2869 void SMESHGUI_MeshInfoDlg::modeChanged()
2870 {
2871   myID->clear();
2872   updateSelection();
2873 }
2874
2875 /*!
2876   \brief Caled when users prints mesh element ID in the corresponding field.
2877 */
2878 void SMESHGUI_MeshInfoDlg::idChanged()
2879 {
2880   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2881   if ( myActor && selector ) {
2882     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
2883     TColStd_MapOfInteger ID;
2884     QSet<long> ids;
2885     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
2886     foreach ( QString tid, idTxt ) {
2887       long id = tid.trimmed().toLong();
2888       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
2889         myActor->GetObject()->GetMesh()->FindElement( id ) :
2890         myActor->GetObject()->GetMesh()->FindNode( id );
2891       if ( e ) {
2892         ID.Add( id );
2893         ids << id;
2894       }
2895     }
2896     selector->AddOrRemoveIndex( IO, ID, false );
2897     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
2898       aViewWindow->highlight( IO, true, true );
2899       aViewWindow->Repaint();
2900     }
2901     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2902   }
2903 }
2904
2905 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
2906 {
2907   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
2908     myMode->button( NodeMode )->click();
2909     myID->setText( QString::number( id ) );
2910   }
2911 }
2912
2913 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
2914 {
2915   if ( !theStr.isEmpty() ) {
2916     myMode->button( ElemMode )->click();
2917     myID->setText( theStr );
2918   }
2919 }
2920
2921 void SMESHGUI_MeshInfoDlg::dump()
2922 {
2923   SUIT_Application* app = SUIT_Session::session()->activeApplication();
2924   if ( !app ) return;
2925   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
2926   if ( !appStudy ) return;
2927   _PTR( Study ) aStudy = appStudy->studyDS();
2928
2929   QStringList aFilters;
2930   aFilters.append( tr( "TEXT_FILES" ) );
2931
2932   bool anIsBase = true;
2933   bool anIsElem = true;
2934   bool anIsAdd  = true;
2935   bool anIsCtrl = true;
2936
2937   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
2938     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
2939     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
2940     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
2941     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
2942   }
2943
2944   DumpFileDlg fd( this );
2945   fd.setWindowTitle( tr( "SAVE_INFO" ) );
2946   fd.setFilters( aFilters );
2947   fd.myBaseChk->setChecked( anIsBase );
2948   fd.myElemChk->setChecked( anIsElem );
2949   fd.myAddChk ->setChecked( anIsAdd );
2950   fd.myCtrlChk->setChecked( anIsCtrl );
2951   if ( fd.exec() == QDialog::Accepted )
2952   {
2953     QString aFileName = fd.selectedFile();
2954
2955     bool toBase = fd.myBaseChk->isChecked();
2956     bool toElem = fd.myElemChk->isChecked();
2957     bool toAdd  = fd.myAddChk->isChecked();
2958     bool toCtrl = fd.myCtrlChk->isChecked();
2959
2960     if ( !aFileName.isEmpty() ) {
2961       QFileInfo aFileInfo( aFileName );
2962       if ( aFileInfo.isDir() )
2963         return;
2964  
2965       QFile aFile( aFileName );
2966       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
2967         return;
2968       
2969       QTextStream out( &aFile );
2970       
2971       if ( toBase ) myBaseInfo->saveInfo( out );
2972       if ( toElem ) myElemInfo->saveInfo( out );
2973       if ( toAdd )  myAddInfo ->saveInfo( out );
2974       if ( toCtrl ) myCtrlInfo->saveInfo( out );
2975     }
2976   }
2977 }
2978
2979 /*!
2980   \class SMESHGUI_CtrlInfo
2981   \brief Class for the mesh controls information widget.
2982 */
2983
2984 /*!
2985   \brief Constructor
2986   \param parent parent widget
2987 */
2988 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
2989   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
2990 {
2991   setFrameStyle( StyledPanel | Sunken );
2992
2993   myMainLayout = new QGridLayout( this );
2994   myMainLayout->setMargin( MARGIN );
2995   myMainLayout->setSpacing( SPACING );
2996
2997   // name
2998   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
2999   QLabel* aName = createField();
3000   aName->setMinimumWidth( 150 );
3001   myWidgets << aName;
3002
3003   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3004   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3005
3006   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3007
3008   // nodes info
3009   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3010   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3011   QLabel* aNodesFree = createField();
3012   myWidgets << aNodesFree;
3013   myPredicates << aFilterMgr->CreateFreeNodes();
3014   //
3015   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3016   QLabel* aNodesDouble = createField();
3017   myWidgets << aNodesDouble;
3018   myPredicates << aFilterMgr->CreateEqualNodes();
3019   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3020   myToleranceWidget = new SMESHGUI_SpinBox( this );
3021   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3022   myToleranceWidget->setAcceptNames( false );
3023   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3024
3025   // edges info
3026   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3027   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3028   QLabel* anEdgesDouble = createField();
3029   myWidgets << anEdgesDouble;
3030   myPredicates << aFilterMgr->CreateEqualEdges();
3031
3032   // faces info
3033   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3034   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3035   QLabel* aFacesDouble = createField();
3036   myWidgets << aFacesDouble;
3037   myPredicates << aFilterMgr->CreateEqualFaces();
3038   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3039   QLabel* aFacesOver = createField();
3040   myWidgets << aFacesOver;
3041   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3042   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3043   myPlot = createPlot( this );
3044   myAspectRatio = aFilterMgr->CreateAspectRatio();
3045  
3046   // volumes info
3047   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3048   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3049   QLabel* aVolumesDouble = createField();
3050   myWidgets << aVolumesDouble;
3051   myPredicates << aFilterMgr->CreateEqualVolumes();
3052   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3053   QLabel* aVolumesOver = createField();
3054   myWidgets << aVolumesOver;
3055   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3056   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3057   myPlot3D = createPlot( this );
3058   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3059
3060   QToolButton* aFreeNodesBtn = new QToolButton( this );
3061   aFreeNodesBtn->setIcon(aComputeIcon);
3062   myButtons << aFreeNodesBtn;       //0
3063
3064   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3065   aDoubleNodesBtn->setIcon(aComputeIcon);
3066   myButtons << aDoubleNodesBtn;     //1
3067
3068   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3069   aDoubleEdgesBtn->setIcon(aComputeIcon);
3070   myButtons << aDoubleEdgesBtn;     //2
3071
3072   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3073   aDoubleFacesBtn->setIcon(aComputeIcon);
3074   myButtons << aDoubleFacesBtn;     //3
3075
3076   QToolButton* aOverContFacesBtn = new QToolButton( this );
3077   aOverContFacesBtn->setIcon(aComputeIcon);
3078   myButtons << aOverContFacesBtn;   //4
3079
3080   QToolButton* aComputeFaceBtn = new QToolButton( this );
3081   aComputeFaceBtn->setIcon(aComputeIcon);
3082   myButtons << aComputeFaceBtn;     //5
3083
3084   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3085   aDoubleVolumesBtn->setIcon(aComputeIcon);
3086   myButtons << aDoubleVolumesBtn;   //6
3087
3088   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3089   aOverContVolumesBtn->setIcon(aComputeIcon);
3090   myButtons << aOverContVolumesBtn; //7
3091
3092   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3093   aComputeVolumeBtn->setIcon(aComputeIcon);
3094   myButtons << aComputeVolumeBtn;   //8
3095
3096   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3097   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3098   connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3099   connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3100   connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3101   connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3102   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3103   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3104   connect( aOverContVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3105   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3106
3107   setFontAttributes( aNameLab );
3108   setFontAttributes( aNodesLab );
3109   setFontAttributes( anEdgesLab );
3110   setFontAttributes( aFacesLab );
3111   setFontAttributes( aVolumesLab );
3112
3113   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3114   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3115   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3116   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3117   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3118   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3119   myMainLayout->addWidget( aNodesDoubleLab,    3, 0 );       //6
3120   myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
3121   myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
3122   myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
3123   myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
3124   myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
3125   myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
3126   myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
3127   myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
3128   myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
3129   myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
3130   myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
3131   myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
3132   myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
3133   myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
3134   myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
3135   myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
3136   myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
3137   myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
3138   myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
3139   myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
3140   myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
3141   myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
3142   myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
3143   myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
3144   myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
3145   myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
3146   myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
3147   myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
3148  
3149   myMainLayout->setColumnStretch(  0,  0 );
3150   myMainLayout->setColumnStretch(  1,  5 );
3151   myMainLayout->setRowStretch   ( 11,  5 );
3152   myMainLayout->setRowStretch   ( 16,  5 );
3153   myMainLayout->setRowStretch   ( 17,  1 );
3154
3155   clearInternal();
3156 }
3157
3158 /*!
3159   \brief Destructor
3160 */
3161 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3162 {}
3163
3164 /*!
3165   \brief Change widget font attributes (bold, ...).
3166   \param w widget
3167   \param attr font attributes (XORed flags)
3168 */
3169 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3170 {
3171   if ( w ) {
3172     QFont f = w->font();
3173     f.setBold( true );
3174     w->setFont( f );
3175   }
3176 }
3177
3178 /*!
3179   \brief Create info field
3180   \return new info field
3181 */
3182 QLabel* SMESHGUI_CtrlInfo::createField()
3183 {
3184   QLabel* lab = new QLabel( this );
3185   lab->setFrameStyle( StyledPanel | Sunken );
3186   lab->setAlignment( Qt::AlignCenter );
3187   lab->setAutoFillBackground( true );
3188   QPalette pal = lab->palette();
3189   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
3190   lab->setPalette( pal );
3191   lab->setMinimumWidth( 60 );
3192   return lab;
3193 }
3194
3195 /*!
3196   \brief Create QwtPlot
3197   \return new QwtPlot
3198 */
3199 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3200 {
3201   QwtPlot* aPlot = new QwtPlot( parent );
3202   aPlot->setMinimumSize( 100, 100 );
3203   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3204   xFont.setPointSize( 5 );
3205   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3206   yFont.setPointSize( 5 );
3207   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3208   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3209   aPlot->replot();
3210   return aPlot;
3211 }
3212
3213 /*!
3214   \brief Show controls information on the selected object
3215 */
3216 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3217 {
3218   clearInternal();
3219
3220   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3221   if ( myObject->_is_nil() ) return;
3222
3223   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3224     myWidgets[0]->setText( aSO->GetName().c_str() );
3225
3226   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3227   if ( mesh->_is_nil() ) return;
3228
3229   const bool meshLoaded = mesh->IsLoaded();
3230   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3231     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3232     for ( int i = 0; i < myButtons.count(); ++i )
3233       myButtons[i]->setEnabled( true );
3234
3235   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3236   if ( ! &nbElemsByType.in() ) return;
3237
3238   const CORBA::Long ctrlLimit =
3239     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3240
3241   // nodes info
3242   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3243   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3244                                 nbElemsByType[ SMESH::FACE ] +
3245                                 nbElemsByType[ SMESH::VOLUME ] );
3246   if ( nbNodes + nbElems > 0 ) {
3247     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3248       // free nodes
3249       computeFreeNodesInfo();
3250       // double nodes
3251       computeDoubleNodesInfo();
3252     }
3253     else {
3254       myButtons[0]->setEnabled( true );
3255       myButtons[1]->setEnabled( true );
3256     }
3257   }
3258   else {
3259     for( int i=2; i<=10; i++)
3260       myMainLayout->itemAt(i)->widget()->setVisible( false );
3261   }
3262
3263   // edges info
3264   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3265     // double edges
3266     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3267       computeDoubleEdgesInfo();
3268     else
3269       myButtons[2]->setEnabled( true );
3270   }
3271   else {
3272     for( int i=11; i<=14; i++)
3273       myMainLayout->itemAt(i)->widget()->setVisible( false );
3274   }
3275  
3276   // faces info
3277   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3278     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3279       // double faces
3280       computeDoubleFacesInfo();
3281       // over constrained faces
3282       computeOverConstrainedFacesInfo();
3283       // aspect Ratio histogram
3284       computeAspectRatio();
3285     }
3286     else {
3287       myButtons[3]->setEnabled( true );
3288       myButtons[4]->setEnabled( true );
3289       myButtons[5]->setEnabled( true );
3290     }
3291   }
3292   else {
3293     myMainLayout->setRowStretch(11,0);
3294     for( int i=15; i<=24; i++)
3295       myMainLayout->itemAt(i)->widget()->setVisible( false );
3296   }
3297
3298   // volumes info
3299   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3300     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3301       // double volumes
3302       computeDoubleVolumesInfo();
3303       // over constrained volumes
3304       computeOverConstrainedVolumesInfo();
3305       // aspect Ratio 3D histogram
3306       computeAspectRatio3D();
3307      }
3308      else {
3309        myButtons[6]->setEnabled( true );
3310        myButtons[7]->setEnabled( true );
3311        myButtons[8]->setEnabled( true );
3312      }
3313   }
3314   else {
3315     myMainLayout->setRowStretch(16,0);
3316     for( int i=25; i<=34; i++)
3317       myMainLayout->itemAt(i)->widget()->setVisible( false );
3318   }
3319 }
3320
3321 //================================================================================
3322 /*!
3323  * \brief Computes and shows nb of elements satisfying a given predicate
3324  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3325  *  \param [in] iBut - index of one of myButtons to disable
3326  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3327  */
3328 //================================================================================
3329
3330 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3331 {
3332   myButtons[ iBut ]->setEnabled( false );
3333   myWidgets[ iWdg ]->setText( "" );
3334   if ( myObject->_is_nil() ) return;
3335
3336   SUIT_OverrideCursor wc;
3337
3338   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3339   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3340   {
3341     mesh->Load();
3342     this->showInfo( myObject ); // try to show all values
3343     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3344       return; // <ft> predicate already computed
3345   }
3346   // look for a predicate of type <ft>
3347   for ( int i = 0; i < myPredicates.count(); ++i )
3348     if ( myPredicates[i]->GetFunctorType() == ft )
3349     {
3350       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3351       myWidgets[ iWdg ]->setText( QString::number( nb ));
3352     }
3353 }
3354
3355 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3356 {
3357   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3358 }
3359
3360 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3361 {
3362   computeNb( SMESH::FT_EqualNodes, 1, 2 );
3363 }
3364
3365 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3366 {
3367   computeNb( SMESH::FT_EqualEdges, 2, 3 );
3368 }
3369
3370 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3371 {
3372   computeNb( SMESH::FT_EqualFaces, 3, 4 );
3373 }
3374
3375 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3376 {
3377   computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
3378 }
3379
3380 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3381 {
3382   computeNb( SMESH::FT_EqualVolumes, 6, 6 );
3383 }
3384
3385 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3386 {
3387   computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
3388 }
3389
3390 void SMESHGUI_CtrlInfo::computeAspectRatio()
3391 {
3392   myButtons[5]->setEnabled( false );
3393
3394   if ( myObject->_is_nil() ) return;
3395
3396   SUIT_OverrideCursor wc;
3397
3398   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3399   if ( aHistogram && !aHistogram->isEmpty() ) {
3400     QwtPlotItem* anItem = aHistogram->createPlotItem();
3401     anItem->attach( myPlot );
3402     myPlot->replot();
3403   }
3404   delete aHistogram;
3405 }
3406
3407 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3408 {
3409   myButtons[8]->setEnabled( false );
3410
3411   if ( myObject->_is_nil() ) return;
3412
3413   SUIT_OverrideCursor wc;
3414
3415   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3416   if ( aHistogram && !aHistogram->isEmpty() ) {
3417     QwtPlotItem* anItem = aHistogram->createPlotItem();
3418     anItem->attach( myPlot3D );
3419     myPlot3D->replot();
3420   }
3421   delete aHistogram;
3422 }
3423
3424 /*!
3425   \brief Internal clean-up (reset widget)
3426 */
3427 void SMESHGUI_CtrlInfo::clearInternal()
3428 {
3429   for( int i=0; i<=34; i++)
3430     myMainLayout->itemAt(i)->widget()->setVisible( true );
3431   for( int i=0; i<=8; i++)
3432     myButtons[i]->setEnabled( false );
3433   myPlot->detachItems();
3434   myPlot3D->detachItems();
3435   myPlot->replot();
3436   myPlot3D->replot();
3437   myWidgets[0]->setText( QString() );
3438   for ( int i = 1; i < myWidgets.count(); i++ )
3439     myWidgets[i]->setText( "" );
3440   myMainLayout->setRowStretch(11,5);
3441   myMainLayout->setRowStretch(16,5);
3442 }
3443
3444 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3445 {
3446   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3447   myButtons[1]->setEnabled( true );
3448   myWidgets[2]->setText("");
3449 }
3450
3451 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3452 {
3453   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3454   if ( mesh->_is_nil() ) return 0;
3455   if ( !mesh->IsLoaded() )
3456     mesh->Load();
3457   aNumFun->SetMesh( mesh );
3458
3459   CORBA::Long cprecision = 6;
3460   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
3461     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3462   aNumFun->SetPrecision( cprecision );
3463
3464   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3465
3466   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3467                                                                   /*isLogarithmic=*/false,
3468                                                                   myObject );
3469   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3470   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3471   if ( &histogramVar.in() )
3472   {
3473     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3474       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3475     if ( histogramVar->length() >= 2 )
3476       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3477   }
3478   return aHistogram;
3479 }
3480
3481 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3482   out << QString( 20, '-' ) << "\n";
3483   out << tr( "CTRL_INFO"  ) << "\n";
3484   out << QString( 20, '-' ) << "\n";
3485   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3486   out <<                                 tr( "NODES_INFO" )                     << "\n";
3487   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3488   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3489   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3490   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3491   out <<                                 tr( "FACES_INFO" )                     << "\n";
3492   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3493   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3494   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3495   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3496   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3497 }
3498
3499 /*!
3500   \class SMESHGUI_CtrlInfoDlg
3501   \brief Controls information dialog box
3502 */
3503
3504 /*!
3505   \brief Constructor
3506   \param parent parent widget
3507   \param page specifies the dialog page to be shown at the start-up
3508 */
3509 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3510 : QDialog( parent )
3511 {
3512   setAttribute( Qt::WA_DeleteOnClose, true );
3513   setWindowTitle( tr( "CTRL_INFO" ) );
3514   setMinimumSize( 400, 600 );
3515
3516   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3517   
3518   // buttons
3519   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3520   okBtn->setAutoDefault( true );
3521   okBtn->setDefault( true );
3522   okBtn->setFocus();
3523   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3524   dumpBtn->setAutoDefault( true );
3525   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3526   helpBtn->setAutoDefault( true );
3527
3528   QHBoxLayout* btnLayout = new QHBoxLayout;
3529   btnLayout->setSpacing( SPACING );
3530   btnLayout->setMargin( 0 );
3531
3532   btnLayout->addWidget( okBtn );
3533   btnLayout->addWidget( dumpBtn );
3534   btnLayout->addStretch( 10 );
3535   btnLayout->addWidget( helpBtn );
3536
3537   QVBoxLayout* l = new QVBoxLayout ( this );
3538   l->setMargin( MARGIN );
3539   l->setSpacing( SPACING );
3540   l->addWidget( myCtrlInfo );
3541   l->addLayout( btnLayout );
3542
3543   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
3544   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3545   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3546   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3547   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
3548
3549   updateSelection();
3550 }
3551
3552 /*!
3553   \brief Destructor
3554 */
3555 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3556 {
3557 }
3558
3559 /*!
3560   \brief Show controls information
3561   \param IO interactive object
3562 */
3563 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3564 {  
3565   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ) )
3566     myCtrlInfo->showInfo( obj );
3567 }
3568
3569 /*!
3570   \brief Perform clean-up actions on the dialog box closing.
3571 */
3572 void SMESHGUI_CtrlInfoDlg::reject()
3573 {
3574   SMESH::SetPointRepresentation( false );
3575   QDialog::reject();
3576 }
3577
3578 /*!
3579   \brief Setup selection mode depending on the current dialog box state.
3580 */
3581 void SMESHGUI_CtrlInfoDlg::updateSelection()
3582 {
3583   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3584   disconnect( selMgr, 0, this, 0 );
3585   SMESH::SetPointRepresentation( false );  
3586   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3587   updateInfo();  
3588 }
3589
3590 /*!
3591   \brief Show mesh information
3592 */
3593 void SMESHGUI_CtrlInfoDlg::updateInfo()
3594 {
3595   SUIT_OverrideCursor wc;
3596
3597   SALOME_ListIO selected;
3598   SMESHGUI::selectionMgr()->selectedObjects( selected );
3599
3600   if ( selected.Extent() == 1 ) {
3601     Handle(SALOME_InteractiveObject) IO = selected.First();
3602     showInfo( IO );
3603   }
3604 }
3605
3606 /*!
3607   \brief Activate dialog box
3608 */
3609 void SMESHGUI_CtrlInfoDlg::activate()
3610 {
3611   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3612   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3613   updateSelection();
3614 }
3615
3616 /*!
3617   \brief Deactivate dialog box
3618 */
3619 void SMESHGUI_CtrlInfoDlg::deactivate()
3620 {
3621   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3622 }
3623
3624 /*!
3625  * \brief Dump contents into a file
3626  */
3627 void SMESHGUI_CtrlInfoDlg::dump()
3628 {
3629   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3630   if ( !app ) return;
3631   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3632   if ( !appStudy ) return;
3633   _PTR( Study ) aStudy = appStudy->studyDS();
3634
3635   QStringList aFilters;
3636   aFilters.append( tr( "TEXT_FILES" ) );
3637
3638   DumpFileDlg fd( this );
3639   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3640   fd.setFilters( aFilters );
3641   fd.myBaseChk->hide();
3642   fd.myElemChk->hide();
3643   fd.myAddChk ->hide();
3644   fd.myCtrlChk->hide();
3645   if ( fd.exec() == QDialog::Accepted )
3646   {
3647     QString aFileName = fd.selectedFile();
3648     if ( !aFileName.isEmpty() ) {
3649       QFileInfo aFileInfo( aFileName );
3650       if ( aFileInfo.isDir() )
3651         return;
3652  
3653       QFile aFile( aFileName );
3654       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3655         return;
3656       
3657       QTextStream out( &aFile );
3658       myCtrlInfo->saveInfo( out );
3659     }
3660   }
3661 }
3662
3663 /*!
3664  * \brief Show help
3665  */
3666 void SMESHGUI_CtrlInfoDlg::help()
3667 {
3668   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
3669 }