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