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