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