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