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