Salome HOME
Merge remote branch 'origin/V7_dev' into V8_0_0_BR
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2015  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, v;
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, v;
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     QTreeWidgetItem* item = myItem;
2328     myItem = 0;
2329     int nb = myToComputeSize ? myGroup->Size() : myGroup->GetNumberOfNodes();
2330     item->treeWidget()->removeItemWidget( item, 1 );
2331     item->setText( 1, QString::number( nb ));
2332   }
2333 }
2334
2335 /*!
2336   \class SMESHGUI_AddInfo
2337   \brief The wigdet shows additional information on the mesh object.
2338 */
2339
2340 /*!
2341   \brief Constructor
2342   \param parent parent widget
2343 */
2344 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2345 : QTreeWidget( parent )
2346 {
2347   setColumnCount( 2 );
2348   header()->setStretchLastSection( true );
2349 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
2350   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2351 #else
2352   header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2353 #endif
2354   header()->hide();
2355 }
2356
2357 /*!
2358   \brief Destructor
2359 */
2360 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2361 {
2362 }
2363
2364 /*!
2365   \brief Show additional information on the selected object
2366   \param obj object being processed (mesh, sub-mesh, group, ID source)
2367 */
2368 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2369 {
2370   setProperty( "group_index", 0 );
2371   setProperty( "submesh_index",  0 );
2372   myComputors.clear();
2373   clear();
2374
2375   if ( CORBA::is_nil( obj ) ) return;
2376
2377   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2378   if ( !sobj ) return;
2379
2380   // name
2381   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2382   nameItem->setText( 0, tr( "NAME" ) );
2383   nameItem->setText( 1, sobj->GetName().c_str() );
2384   
2385   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2386   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2387   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2388   
2389   if ( !aMesh->_is_nil() )
2390     meshInfo( aMesh, nameItem );
2391   else if ( !aSubMesh->_is_nil() )
2392     subMeshInfo( aSubMesh, nameItem );
2393   else if ( !aGroup->_is_nil() )
2394     groupInfo( aGroup.in(), nameItem );
2395 }
2396
2397 /*!
2398   \brief Create new tree item.
2399   \param parent parent tree widget item
2400   \param flags item flag
2401   \return new tree widget item
2402 */
2403 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2404 {
2405   QTreeWidgetItem* item;
2406
2407   if ( parent )
2408     item = new QTreeWidgetItem( parent );
2409   else
2410     item = new QTreeWidgetItem( this );
2411
2412   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2413
2414   QFont f = item->font( 0 );
2415   f.setBold( true );
2416   for ( int i = 0; i < columnCount(); i++ ) {
2417     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2418       item->setFont( i, f );
2419   }
2420
2421   item->setExpanded( true );
2422   return item;
2423 }
2424
2425 /*!
2426   \brief Show mesh info
2427   \param mesh mesh object
2428   \param parent parent tree item
2429 */
2430 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2431 {
2432   // type
2433   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2434   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2435   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2436   typeItem->setText( 0, tr( "TYPE" ) );
2437   if ( !CORBA::is_nil( shape ) ) {
2438     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2439     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2440     if ( sobj ) {
2441       QTreeWidgetItem* gobjItem = createItem( typeItem );
2442       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2443       gobjItem->setText( 1, sobj->GetName().c_str() );
2444     }
2445   }
2446   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2447     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2448     QTreeWidgetItem* fileItem = createItem( typeItem );
2449     fileItem->setText( 0, tr( "FILE_NAME" ) );
2450     fileItem->setText( 1, (char*)inf->fileName );
2451   }
2452   else {
2453     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2454   }
2455   
2456   // groups
2457   myGroups = mesh->GetGroups();
2458   showGroups();
2459
2460   // sub-meshes
2461   mySubMeshes = mesh->GetSubMeshes();
2462   showSubMeshes();
2463 }
2464
2465 /*!
2466   \brief Show sub-mesh info
2467   \param subMesh sub-mesh object
2468   \param parent parent tree item
2469 */
2470 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2471 {
2472   bool isShort = parent->parent() != 0;
2473
2474   if ( !isShort ) {
2475     // parent mesh
2476     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2477     if ( sobj ) {
2478       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2479       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2480       nameItem->setText( 1, sobj->GetName().c_str() );
2481     }
2482   }
2483   
2484   // shape
2485   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2486   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2487   if ( sobj ) {
2488     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2489     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2490     gobjItem->setText( 1, sobj->GetName().c_str() );
2491   }
2492 }
2493
2494 /*!
2495   \brief Show group info
2496   \param grp mesh group object
2497   \param parent parent tree item
2498 */
2499 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2500 {
2501   bool isShort = parent->parent() != 0;
2502
2503   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2504   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2505   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2506
2507   if ( !isShort ) {
2508     // parent mesh
2509     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2510     if ( sobj ) {
2511       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2512       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2513       nameItem->setText( 1, sobj->GetName().c_str() );
2514     }
2515   }
2516
2517   // type : group on geometry, standalone group, group on filter
2518   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2519   typeItem->setText( 0, tr( "TYPE" ) );
2520   if ( !CORBA::is_nil( aStdGroup ) ) {
2521     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2522   }
2523   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2524     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2525     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2526     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2527     if ( sobj ) {
2528       QTreeWidgetItem* gobjItem = createItem( typeItem );
2529       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2530       gobjItem->setText( 1, sobj->GetName().c_str() );
2531     }
2532   }
2533   else if ( !CORBA::is_nil( aFltGroup ) ) {
2534     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2535   }
2536
2537   if ( !isShort ) {
2538     // entity type
2539     QString etype = tr( "UNKNOWN" );
2540     switch( grp->GetType() ) {
2541     case SMESH::NODE:
2542       etype = tr( "NODE" );
2543       break;
2544     case SMESH::EDGE:
2545       etype = tr( "EDGE" );
2546       break;
2547     case SMESH::FACE:
2548       etype = tr( "FACE" );
2549       break;
2550     case SMESH::VOLUME:
2551       etype = tr( "VOLUME" );
2552       break;
2553     case SMESH::ELEM0D:
2554       etype = tr( "0DELEM" );
2555       break;
2556     case SMESH::BALL:
2557       etype = tr( "BALL" );
2558       break;
2559     default:
2560       break;
2561     }
2562     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2563     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2564     etypeItem->setText( 1, etype );
2565   }
2566
2567   SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2568   bool            meshLoaded = mesh->IsLoaded();
2569
2570   // size. Don't call grp->Size() for GroupOnFilter - issue IPAL52831
2571   int groupSize = -1;
2572   if ( grp->IsNodeInfoAvailable() || CORBA::is_nil( aFltGroup ))
2573     groupSize = grp->Size();
2574
2575   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2576   sizeItem->setText( 0, tr( "SIZE" ) );
2577   if ( groupSize > -1 ) {
2578     sizeItem->setText( 1, QString::number( groupSize ) );
2579   }
2580   else {
2581     QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2582     setItemWidget( sizeItem, 1, btn );
2583     GrpComputor* comp = new GrpComputor( grp, sizeItem, this, /*size=*/true );
2584     connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2585     myComputors.append( comp );
2586     if ( !meshLoaded )
2587       connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2588   }
2589
2590   // color
2591   SALOMEDS::Color color = grp->GetColor();
2592   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2593   colorItem->setText( 0, tr( "COLOR" ) );
2594   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2595
2596   // nb of underlying nodes
2597   if ( grp->GetType() != SMESH::NODE) {
2598     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2599     nodesItem->setText( 0, tr( "NB_NODES" ) );
2600     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2601     bool toShowNodes = groupSize >= 0 ? ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || groupSize <= nbNodesLimit ) : false;
2602     if ( toShowNodes && meshLoaded ) {
2603       // already calculated and up-to-date
2604       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2605     }
2606     else {
2607       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2608       setItemWidget( nodesItem, 1, btn );
2609       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2610       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2611       myComputors.append( comp );
2612       if ( !meshLoaded )
2613         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2614     }
2615   }
2616 }
2617
2618 void SMESHGUI_AddInfo::showGroups()
2619 {
2620   myComputors.clear();
2621
2622   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2623   if ( !parent ) return;
2624
2625   int idx = property( "group_index" ).toInt();
2626
2627   QTreeWidgetItem* itemGroups = 0;
2628   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2629     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2630       itemGroups = parent->child( i );
2631       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2632       if ( extra )
2633         extra->updateControls( myGroups->length(), idx );
2634       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2635     }
2636   }
2637
2638   QMap<int, QTreeWidgetItem*> grpItems;
2639   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2640     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2641     if ( CORBA::is_nil( grp ) ) continue;
2642     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2643     if ( !grpSObj ) continue;
2644
2645     int grpType = grp->GetType();
2646
2647     if ( !itemGroups ) {
2648       // create top-level groups container item
2649       itemGroups = createItem( parent, Bold | All );
2650       itemGroups->setText( 0, tr( "GROUPS" ) );
2651       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2652
2653       // total number of groups > 10, show extra widgets for info browsing
2654       if ((int) myGroups->length() > MAXITEMS ) {
2655         ExtraWidget* extra = new ExtraWidget( this, true );
2656         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2657         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2658         setItemWidget( itemGroups, 1, extra );
2659         extra->updateControls( myGroups->length(), idx );
2660       }
2661     }
2662
2663     if ( grpItems.find( grpType ) == grpItems.end() ) {
2664       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2665       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2666       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2667     }
2668   
2669     // group name
2670     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2671     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2672
2673     // group info
2674     groupInfo( grp.in(), grpNameItem );
2675   }
2676 }
2677
2678 void SMESHGUI_AddInfo::showSubMeshes()
2679 {
2680   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2681   if ( !parent ) return;
2682
2683   int idx = property( "submesh_index" ).toInt();
2684
2685   QTreeWidgetItem* itemSubMeshes = 0;
2686   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2687     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2688       itemSubMeshes = parent->child( i );
2689       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2690       if ( extra )
2691         extra->updateControls( mySubMeshes->length(), idx );
2692       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2693     }
2694   }
2695
2696   QMap<int, QTreeWidgetItem*> smItems;
2697   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2698     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2699     if ( CORBA::is_nil( sm ) ) continue;
2700     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2701     if ( !smSObj ) continue;
2702     
2703     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2704     if ( CORBA::is_nil(gobj ) ) continue;
2705     
2706     int smType = gobj->GetShapeType();
2707     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2708
2709     if ( !itemSubMeshes ) {
2710       itemSubMeshes = createItem( parent, Bold | All );
2711       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2712       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2713
2714       // total number of sub-meshes > 10, show extra widgets for info browsing
2715       if ((int) mySubMeshes->length() > MAXITEMS ) {
2716         ExtraWidget* extra = new ExtraWidget( this, true );
2717         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2718         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2719         setItemWidget( itemSubMeshes, 1, extra );
2720         extra->updateControls( mySubMeshes->length(), idx );
2721       }
2722     }
2723          
2724     if ( smItems.find( smType ) == smItems.end() ) {
2725       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2726       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2727       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2728     }
2729     
2730     // submesh name
2731     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2732     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2733     
2734     // submesh info
2735     subMeshInfo( sm.in(), smNameItem );
2736   }
2737 }
2738
2739 /*!
2740  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2741  */
2742 void SMESHGUI_AddInfo::changeLoadToCompute()
2743 {
2744   for ( int i = 0; i < myComputors.count(); ++i )
2745   {
2746     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2747     {
2748       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2749         btn->setText( tr("COMPUTE") );
2750     }
2751   }
2752 }
2753
2754 void SMESHGUI_AddInfo::showPreviousGroups()
2755 {
2756   int idx = property( "group_index" ).toInt();
2757   setProperty( "group_index", idx-1 );
2758   showGroups();
2759 }
2760
2761 void SMESHGUI_AddInfo::showNextGroups()
2762 {
2763   int idx = property( "group_index" ).toInt();
2764   setProperty( "group_index", idx+1 );
2765   showGroups();
2766 }
2767
2768 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2769 {
2770   int idx = property( "submesh_index" ).toInt();
2771   setProperty( "submesh_index", idx-1 );
2772   showSubMeshes();
2773 }
2774
2775 void SMESHGUI_AddInfo::showNextSubMeshes()
2776 {
2777   int idx = property( "submesh_index" ).toInt();
2778   setProperty( "submesh_index", idx+1 );
2779   showSubMeshes();
2780 }
2781
2782 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2783 {
2784   out << QString( 15, '-')       << "\n";
2785   out << tr( "ADDITIONAL_INFO" ) << "\n";
2786   out << QString( 15, '-' )      << "\n";
2787   QTreeWidgetItemIterator it( this );
2788   while ( *it ) {
2789     if ( !( ( *it )->text(0) ).isEmpty() ) {
2790       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2791       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2792         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2793       }
2794       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2795       out << "\n";
2796     }
2797     ++it;
2798   }
2799   out << "\n";
2800 }
2801
2802 /*!
2803   \class SMESHGUI_MeshInfoDlg
2804   \brief Mesh information dialog box
2805 */
2806
2807 /*!
2808   \brief Constructor
2809   \param parent parent widget
2810   \param page specifies the dialog page to be shown at the start-up
2811 */
2812 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2813 : QDialog( parent ), myActor( 0 )
2814 {
2815   setModal( false );
2816   setAttribute( Qt::WA_DeleteOnClose, true );
2817   setWindowTitle( tr( "MESH_INFO" ) );
2818   setSizeGripEnabled( true );
2819
2820   myTabWidget = new QTabWidget( this );
2821
2822   // base info 
2823
2824   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2825   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2826
2827   // elem info 
2828   
2829   QWidget* w = new QWidget( myTabWidget );
2830
2831   myMode = new QButtonGroup( this );
2832   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2833   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2834   myMode->button( NodeMode )->setChecked( true );
2835   myID = new QLineEdit( w );
2836   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2837
2838   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2839   mode = qMin( 1, qMax( 0, mode ) );
2840   
2841   if ( mode == 0 ) 
2842     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2843   else
2844     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2845
2846   QGridLayout* elemLayout = new QGridLayout( w );
2847   elemLayout->setMargin( MARGIN );
2848   elemLayout->setSpacing( SPACING );
2849   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2850   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2851   elemLayout->addWidget( myID, 0, 2 );
2852   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2853   
2854   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2855
2856   // additional info
2857
2858   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2859   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2860
2861   // controls info
2862
2863   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
2864   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
2865
2866   // buttons
2867
2868   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2869   okBtn->setAutoDefault( true );
2870   okBtn->setDefault( true );
2871   okBtn->setFocus();
2872   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2873   dumpBtn->setAutoDefault( true );
2874   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2875   helpBtn->setAutoDefault( true );
2876
2877   QHBoxLayout* btnLayout = new QHBoxLayout;
2878   btnLayout->setSpacing( SPACING );
2879   btnLayout->setMargin( 0 );
2880
2881   btnLayout->addWidget( okBtn );
2882   btnLayout->addWidget( dumpBtn );
2883   btnLayout->addStretch( 10 );
2884   btnLayout->addWidget( helpBtn );
2885
2886   QVBoxLayout* l = new QVBoxLayout ( this );
2887   l->setMargin( MARGIN );
2888   l->setSpacing( SPACING );
2889   l->addWidget( myTabWidget );
2890   l->addLayout( btnLayout );
2891
2892   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2893
2894   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2895   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2896   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2897   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2898   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2899   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2900   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2901   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2902   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2903   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2904
2905   updateSelection();
2906 }
2907
2908 /*!
2909   \brief Destructor
2910 */
2911 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2912 {
2913 }
2914
2915 /*!
2916   \brief Show mesh information
2917   \param IO interactive object
2918 */
2919 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2920 {
2921   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2922   if ( !CORBA::is_nil( obj ) ) {
2923     myAddInfo->showInfo( obj );  // nb of nodes in a group can be computed by myAddInfo,
2924     myBaseInfo->showInfo( obj ); // and it will be used by myBaseInfo (IPAL52871)
2925     myCtrlInfo->showInfo( obj );
2926
2927     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2928     SVTK_Selector* selector = SMESH::GetSelector();
2929     QString ID;
2930     int nb = 0;
2931     if ( myActor && selector ) {
2932       nb = myMode->checkedId() == NodeMode ? 
2933         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2934         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2935     }
2936     myElemInfo->setSource( myActor ) ;
2937     if ( nb > 0 ) {
2938       myID->setText( ID.trimmed() );
2939       QSet<long> ids;
2940       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2941       foreach ( ID, idTxt )
2942         ids << ID.trimmed().toLong();
2943       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2944     }
2945     else {
2946       myID->clear();
2947       myElemInfo->clear();
2948     }
2949   }
2950 }
2951
2952 /*!
2953   \brief Perform clean-up actions on the dialog box closing.
2954 */
2955 void SMESHGUI_MeshInfoDlg::reject()
2956 {
2957   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2958   selMgr->clearFilters();
2959   SMESH::SetPointRepresentation( false );
2960   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2961     aViewWindow->SetSelectionMode( ActorSelection );
2962   QDialog::reject();
2963 }
2964
2965 /*!
2966   \brief Process keyboard event
2967   \param e key press event
2968 */
2969 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2970 {
2971   QDialog::keyPressEvent( e );
2972   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2973     e->accept();
2974     help();
2975   }
2976 }
2977
2978 /*!
2979   \brief Reactivate dialog box, when mouse pointer goes into it.
2980 */
2981 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2982 {
2983   //activate();
2984 }
2985
2986 /*!
2987   \brief Setup selection mode depending on the current dialog box state.
2988 */
2989 void SMESHGUI_MeshInfoDlg::updateSelection()
2990 {
2991   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2992
2993   disconnect( selMgr, 0, this, 0 );
2994   selMgr->clearFilters();
2995
2996   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo || myTabWidget->currentIndex() == CtrlInfo ) {
2997     SMESH::SetPointRepresentation( false );
2998     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2999       aViewWindow->SetSelectionMode( ActorSelection );
3000   }
3001   else {
3002     if ( myMode->checkedId() == NodeMode ) {
3003       SMESH::SetPointRepresentation( true );
3004       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3005         aViewWindow->SetSelectionMode( NodeSelection );
3006     }
3007     else {
3008       SMESH::SetPointRepresentation( false );
3009       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3010         aViewWindow->SetSelectionMode( CellSelection );
3011     }
3012   }
3013
3014   QString oldID = myID->text().trimmed();
3015   SMESH_Actor* oldActor = myActor;
3016   myID->clear();
3017   
3018   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3019   updateInfo();
3020   
3021   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
3022     myID->setText( oldID );
3023     idChanged();
3024   }
3025 }
3026
3027 /*!
3028   \brief Show help page
3029 */
3030 void SMESHGUI_MeshInfoDlg::help()
3031 {
3032   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
3033                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
3034                        "mesh_infos_page.html#mesh_element_info_anchor" );
3035 }
3036
3037 /*!
3038   \brief Show mesh information
3039 */
3040 void SMESHGUI_MeshInfoDlg::updateInfo()
3041 {
3042   SUIT_OverrideCursor wc;
3043
3044   SALOME_ListIO selected;
3045   SMESHGUI::selectionMgr()->selectedObjects( selected );
3046
3047   if ( selected.Extent() == 1 ) {
3048     Handle(SALOME_InteractiveObject) IO = selected.First();
3049     showInfo( IO );
3050   }
3051 //   else {
3052 //     myBaseInfo->clear();
3053 //     myElemInfo->clear();
3054 //     myAddInfo->clear();
3055 //   }
3056 }
3057
3058 /*!
3059   \brief Activate dialog box
3060 */
3061 void SMESHGUI_MeshInfoDlg::activate()
3062 {
3063   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3064   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3065   myTabWidget->setEnabled( true );
3066   updateSelection();
3067 }
3068
3069 /*!
3070   \brief Deactivate dialog box
3071 */
3072 void SMESHGUI_MeshInfoDlg::deactivate()
3073 {
3074   myTabWidget->setEnabled( false );
3075   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3076 }
3077
3078 /*!
3079   \brief Called when users switches between node / element modes.
3080 */
3081 void SMESHGUI_MeshInfoDlg::modeChanged()
3082 {
3083   myID->clear();
3084   updateSelection();
3085 }
3086
3087 /*!
3088   \brief Caled when users prints mesh element ID in the corresponding field.
3089 */
3090 void SMESHGUI_MeshInfoDlg::idChanged()
3091 {
3092   SVTK_Selector* selector = SMESH::GetSelector();
3093   if ( myActor && selector ) {
3094     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
3095     TColStd_MapOfInteger ID;
3096     QSet<long> ids;
3097     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3098     foreach ( QString tid, idTxt ) {
3099       long id = tid.trimmed().toLong();
3100       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
3101         myActor->GetObject()->GetMesh()->FindElement( id ) :
3102         myActor->GetObject()->GetMesh()->FindNode( id );
3103       if ( e ) {
3104         ID.Add( id );
3105         ids << id;
3106       }
3107     }
3108     selector->AddOrRemoveIndex( IO, ID, false );
3109     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
3110       aViewWindow->highlight( IO, true, true );
3111       aViewWindow->Repaint();
3112     }
3113     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
3114   }
3115 }
3116
3117 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
3118 {
3119   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
3120     myMode->button( NodeMode )->click();
3121     myID->setText( QString::number( id ) );
3122   }
3123 }
3124
3125 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
3126 {
3127   if ( !theStr.isEmpty() ) {
3128     myMode->button( ElemMode )->click();
3129     myID->setText( theStr );
3130   }
3131 }
3132
3133 void SMESHGUI_MeshInfoDlg::dump()
3134 {
3135   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3136   if ( !app ) return;
3137   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3138   if ( !appStudy ) return;
3139   _PTR( Study ) aStudy = appStudy->studyDS();
3140
3141   QStringList aFilters;
3142   aFilters.append( tr( "TEXT_FILES" ) );
3143
3144   bool anIsBase = true;
3145   bool anIsElem = true;
3146   bool anIsAdd  = true;
3147   bool anIsCtrl = true;
3148
3149   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
3150     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
3151     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
3152     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
3153     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
3154   }
3155
3156   DumpFileDlg fd( this );
3157   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3158   fd.setNameFilters( aFilters );
3159   fd.myBaseChk->setChecked( anIsBase );
3160   fd.myElemChk->setChecked( anIsElem );
3161   fd.myAddChk ->setChecked( anIsAdd );
3162   fd.myCtrlChk->setChecked( anIsCtrl );
3163   if ( fd.exec() == QDialog::Accepted )
3164   {
3165     QString aFileName = fd.selectedFile();
3166
3167     bool toBase = fd.myBaseChk->isChecked();
3168     bool toElem = fd.myElemChk->isChecked();
3169     bool toAdd  = fd.myAddChk->isChecked();
3170     bool toCtrl = fd.myCtrlChk->isChecked();
3171
3172     if ( !aFileName.isEmpty() ) {
3173       QFileInfo aFileInfo( aFileName );
3174       if ( aFileInfo.isDir() )
3175         return;
3176  
3177       QFile aFile( aFileName );
3178       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3179         return;
3180       
3181       QTextStream out( &aFile );
3182       
3183       if ( toBase ) myBaseInfo->saveInfo( out );
3184       if ( toElem ) myElemInfo->saveInfo( out );
3185       if ( toAdd )  myAddInfo ->saveInfo( out );
3186       if ( toCtrl ) myCtrlInfo->saveInfo( out );
3187     }
3188   }
3189 }
3190
3191 /*!
3192   \class SMESHGUI_CtrlInfo
3193   \brief Class for the mesh controls information widget.
3194 */
3195
3196 /*!
3197   \brief Constructor
3198   \param parent parent widget
3199 */
3200 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
3201   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
3202 {
3203   setFrameStyle( StyledPanel | Sunken );
3204
3205   myMainLayout = new QGridLayout( this );
3206   myMainLayout->setMargin( MARGIN );
3207   myMainLayout->setSpacing( SPACING );
3208
3209   // name
3210   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
3211   QLabel* aName = createField();
3212   aName->setMinimumWidth( 150 );
3213   myWidgets << aName;
3214
3215   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3216   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3217
3218   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3219
3220   // nodes info
3221   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3222   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3223   QLabel* aNodesFree = createField();
3224   myWidgets << aNodesFree;
3225   myPredicates << aFilterMgr->CreateFreeNodes();
3226   //
3227   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3228   QLabel* aNodesDouble = createField();
3229   myWidgets << aNodesDouble;
3230   myPredicates << aFilterMgr->CreateEqualNodes();
3231   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3232   myToleranceWidget = new SMESHGUI_SpinBox( this );
3233   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3234   myToleranceWidget->setAcceptNames( false );
3235   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3236
3237   // edges info
3238   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3239   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3240   QLabel* anEdgesDouble = createField();
3241   myWidgets << anEdgesDouble;
3242   myPredicates << aFilterMgr->CreateEqualEdges();
3243
3244   // faces info
3245   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3246   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3247   QLabel* aFacesDouble = createField();
3248   myWidgets << aFacesDouble;
3249   myPredicates << aFilterMgr->CreateEqualFaces();
3250   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3251   QLabel* aFacesOver = createField();
3252   myWidgets << aFacesOver;
3253   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3254   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3255   myPlot = createPlot( this );
3256   myAspectRatio = aFilterMgr->CreateAspectRatio();
3257  
3258   // volumes info
3259   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3260   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3261   QLabel* aVolumesDouble = createField();
3262   myWidgets << aVolumesDouble;
3263   myPredicates << aFilterMgr->CreateEqualVolumes();
3264   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3265   QLabel* aVolumesOver = createField();
3266   myWidgets << aVolumesOver;
3267   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3268   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3269   myPlot3D = createPlot( this );
3270   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3271
3272   QToolButton* aFreeNodesBtn = new QToolButton( this );
3273   aFreeNodesBtn->setIcon(aComputeIcon);
3274   myButtons << aFreeNodesBtn;       //0
3275
3276   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3277   aDoubleNodesBtn->setIcon(aComputeIcon);
3278   myButtons << aDoubleNodesBtn;     //1
3279
3280   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3281   aDoubleEdgesBtn->setIcon(aComputeIcon);
3282   myButtons << aDoubleEdgesBtn;     //2
3283
3284   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3285   aDoubleFacesBtn->setIcon(aComputeIcon);
3286   myButtons << aDoubleFacesBtn;     //3
3287
3288   QToolButton* aOverContFacesBtn = new QToolButton( this );
3289   aOverContFacesBtn->setIcon(aComputeIcon);
3290   myButtons << aOverContFacesBtn;   //4
3291
3292   QToolButton* aComputeFaceBtn = new QToolButton( this );
3293   aComputeFaceBtn->setIcon(aComputeIcon);
3294   myButtons << aComputeFaceBtn;     //5
3295
3296   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3297   aDoubleVolumesBtn->setIcon(aComputeIcon);
3298   myButtons << aDoubleVolumesBtn;   //6
3299
3300   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3301   aOverContVolumesBtn->setIcon(aComputeIcon);
3302   myButtons << aOverContVolumesBtn; //7
3303
3304   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3305   aComputeVolumeBtn->setIcon(aComputeIcon);
3306   myButtons << aComputeVolumeBtn;   //8
3307
3308   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3309   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3310   connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3311   connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3312   connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3313   connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3314   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3315   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3316   connect( aOverContVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3317   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3318
3319   setFontAttributes( aNameLab );
3320   setFontAttributes( aNodesLab );
3321   setFontAttributes( anEdgesLab );
3322   setFontAttributes( aFacesLab );
3323   setFontAttributes( aVolumesLab );
3324
3325   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3326   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3327   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3328   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3329   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3330   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3331   myMainLayout->addWidget( aNodesDoubleLab,    3, 0 );       //6
3332   myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
3333   myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
3334   myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
3335   myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
3336   myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
3337   myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
3338   myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
3339   myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
3340   myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
3341   myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
3342   myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
3343   myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
3344   myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
3345   myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
3346   myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
3347   myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
3348   myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
3349   myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
3350   myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
3351   myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
3352   myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
3353   myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
3354   myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
3355   myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
3356   myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
3357   myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
3358   myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
3359   myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
3360  
3361   myMainLayout->setColumnStretch(  0,  0 );
3362   myMainLayout->setColumnStretch(  1,  5 );
3363   myMainLayout->setRowStretch   ( 11,  5 );
3364   myMainLayout->setRowStretch   ( 16,  5 );
3365   myMainLayout->setRowStretch   ( 17,  1 );
3366
3367   clearInternal();
3368 }
3369
3370 /*!
3371   \brief Destructor
3372 */
3373 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3374 {}
3375
3376 /*!
3377   \brief Change widget font attributes (bold, ...).
3378   \param w widget
3379   \param attr font attributes (XORed flags)
3380 */
3381 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3382 {
3383   if ( w ) {
3384     QFont f = w->font();
3385     f.setBold( true );
3386     w->setFont( f );
3387   }
3388 }
3389
3390 /*!
3391   \brief Create info field
3392   \return new info field
3393 */
3394 QLabel* SMESHGUI_CtrlInfo::createField()
3395 {
3396   QLabel* lab = new QLabel( this );
3397   lab->setFrameStyle( StyledPanel | Sunken );
3398   lab->setAlignment( Qt::AlignCenter );
3399   lab->setAutoFillBackground( true );
3400   QPalette pal = lab->palette();
3401   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
3402   lab->setPalette( pal );
3403   lab->setMinimumWidth( 60 );
3404   return lab;
3405 }
3406
3407 /*!
3408   \brief Create QwtPlot
3409   \return new QwtPlot
3410 */
3411 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3412 {
3413   QwtPlot* aPlot = new QwtPlot( parent );
3414   aPlot->setMinimumSize( 100, 100 );
3415   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3416   xFont.setPointSize( 5 );
3417   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3418   yFont.setPointSize( 5 );
3419   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3420   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3421   aPlot->replot();
3422   return aPlot;
3423 }
3424
3425 /*!
3426   \brief Show controls information on the selected object
3427 */
3428 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3429 {
3430   clearInternal();
3431
3432   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3433   if ( myObject->_is_nil() ) return;
3434
3435   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3436     myWidgets[0]->setText( aSO->GetName().c_str() );
3437
3438   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3439   if ( mesh->_is_nil() ) return;
3440
3441   const bool meshLoaded = mesh->IsLoaded();
3442   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3443     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3444     for ( int i = 0; i < myButtons.count(); ++i )
3445       myButtons[i]->setEnabled( true );
3446
3447   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3448   if ( ! &nbElemsByType.in() ) return;
3449
3450   const CORBA::Long ctrlLimit =
3451     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3452
3453   // nodes info
3454   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3455   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3456                                 nbElemsByType[ SMESH::FACE ] +
3457                                 nbElemsByType[ SMESH::VOLUME ] );
3458   if ( nbNodes + nbElems > 0 ) {
3459     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3460       // free nodes
3461       computeFreeNodesInfo();
3462       // double nodes
3463       if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
3464         computeDoubleNodesInfo();
3465     }
3466     else {
3467       myButtons[0]->setEnabled( true );
3468       myButtons[1]->setEnabled( true );
3469     }
3470   }
3471   else {
3472     for( int i=2; i<=10; i++)
3473       myMainLayout->itemAt(i)->widget()->setVisible( false );
3474   }
3475
3476   // edges info
3477   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3478     // double edges
3479     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3480       computeDoubleEdgesInfo();
3481     else
3482       myButtons[2]->setEnabled( true );
3483   }
3484   else {
3485     for( int i=11; i<=14; i++)
3486       myMainLayout->itemAt(i)->widget()->setVisible( false );
3487   }
3488  
3489   // faces info
3490   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3491     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3492       // double faces
3493       computeDoubleFacesInfo();
3494       // over constrained faces
3495       computeOverConstrainedFacesInfo();
3496       // aspect Ratio histogram
3497       computeAspectRatio();
3498     }
3499     else {
3500       myButtons[3]->setEnabled( true );
3501       myButtons[4]->setEnabled( true );
3502       myButtons[5]->setEnabled( true );
3503     }
3504 #ifdef DISABLE_PLOT2DVIEWER
3505     myMainLayout->setRowStretch(11,0);
3506     for( int i=22; i<=24; i++)
3507       myMainLayout->itemAt(i)->widget()->setVisible( false );
3508 #endif
3509   }
3510   else {
3511     myMainLayout->setRowStretch(11,0);
3512     for( int i=15; i<=24; i++)
3513       myMainLayout->itemAt(i)->widget()->setVisible( false );
3514   }
3515
3516   // volumes info
3517   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3518     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3519       // double volumes
3520       computeDoubleVolumesInfo();
3521       // over constrained volumes
3522       computeOverConstrainedVolumesInfo();
3523       // aspect Ratio 3D histogram
3524       computeAspectRatio3D();
3525      }
3526      else {
3527        myButtons[6]->setEnabled( true );
3528        myButtons[7]->setEnabled( true );
3529        myButtons[8]->setEnabled( true );
3530      }
3531 #ifdef DISABLE_PLOT2DVIEWER
3532     myMainLayout->setRowStretch(16,0);
3533     for( int i=32; i<=34; i++)
3534       myMainLayout->itemAt(i)->widget()->setVisible( false );
3535 #endif
3536   }
3537   else {
3538     myMainLayout->setRowStretch(16,0);
3539     for( int i=25; i<=34; i++)
3540       myMainLayout->itemAt(i)->widget()->setVisible( false );
3541   }
3542 }
3543
3544 //================================================================================
3545 /*!
3546  * \brief Computes and shows nb of elements satisfying a given predicate
3547  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3548  *  \param [in] iBut - index of one of myButtons to disable
3549  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3550  */
3551 //================================================================================
3552
3553 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3554 {
3555   myButtons[ iBut ]->setEnabled( false );
3556   myWidgets[ iWdg ]->setText( "" );
3557   if ( myObject->_is_nil() ) return;
3558
3559   SUIT_OverrideCursor wc;
3560
3561   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3562   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3563   {
3564     mesh->Load();
3565     this->showInfo( myObject ); // try to show all values
3566     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3567       return; // <ft> predicate already computed
3568   }
3569   // look for a predicate of type <ft>
3570   for ( int i = 0; i < myPredicates.count(); ++i )
3571     if ( myPredicates[i]->GetFunctorType() == ft )
3572     {
3573       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3574       myWidgets[ iWdg ]->setText( QString::number( nb ));
3575     }
3576 }
3577
3578 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3579 {
3580   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3581 }
3582
3583 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3584 {
3585   computeNb( SMESH::FT_EqualNodes, 1, 2 );
3586 }
3587
3588 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3589 {
3590   computeNb( SMESH::FT_EqualEdges, 2, 3 );
3591 }
3592
3593 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3594 {
3595   computeNb( SMESH::FT_EqualFaces, 3, 4 );
3596 }
3597
3598 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3599 {
3600   computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
3601 }
3602
3603 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3604 {
3605   computeNb( SMESH::FT_EqualVolumes, 6, 6 );
3606 }
3607
3608 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3609 {
3610   computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
3611 }
3612
3613 void SMESHGUI_CtrlInfo::computeAspectRatio()
3614 {
3615 #ifndef DISABLE_PLOT2DVIEWER
3616   myButtons[5]->setEnabled( false );
3617
3618   if ( myObject->_is_nil() ) return;
3619
3620   SUIT_OverrideCursor wc;
3621
3622   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3623   if ( aHistogram && !aHistogram->isEmpty() ) {
3624     QwtPlotItem* anItem = aHistogram->createPlotItem();
3625     anItem->attach( myPlot );
3626     myPlot->replot();
3627   }
3628   delete aHistogram;
3629 #endif
3630 }
3631
3632 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3633 {
3634 #ifndef DISABLE_PLOT2DVIEWER
3635   myButtons[8]->setEnabled( false );
3636
3637   if ( myObject->_is_nil() ) return;
3638
3639   SUIT_OverrideCursor wc;
3640
3641   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3642   if ( aHistogram && !aHistogram->isEmpty() ) {
3643     QwtPlotItem* anItem = aHistogram->createPlotItem();
3644     anItem->attach( myPlot3D );
3645     myPlot3D->replot();
3646   }
3647   delete aHistogram;
3648 #endif
3649 }
3650
3651 /*!
3652   \brief Internal clean-up (reset widget)
3653 */
3654 void SMESHGUI_CtrlInfo::clearInternal()
3655 {
3656   for( int i=0; i<=34; i++)
3657     myMainLayout->itemAt(i)->widget()->setVisible( true );
3658   for( int i=0; i<=8; i++)
3659     myButtons[i]->setEnabled( false );
3660   myPlot->detachItems();
3661   myPlot3D->detachItems();
3662   myPlot->replot();
3663   myPlot3D->replot();
3664   myWidgets[0]->setText( QString() );
3665   for ( int i = 1; i < myWidgets.count(); i++ )
3666     myWidgets[i]->setText( "" );
3667   myMainLayout->setRowStretch(11,5);
3668   myMainLayout->setRowStretch(16,5);
3669 }
3670
3671 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3672 {
3673   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3674   myButtons[1]->setEnabled( true );
3675   myWidgets[2]->setText("");
3676 }
3677
3678 #ifndef DISABLE_PLOT2DVIEWER
3679 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3680 {
3681   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3682   if ( mesh->_is_nil() ) return 0;
3683   if ( !mesh->IsLoaded() )
3684     mesh->Load();
3685   aNumFun->SetMesh( mesh );
3686
3687   CORBA::Long cprecision = 6;
3688   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
3689     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3690   aNumFun->SetPrecision( cprecision );
3691
3692   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3693
3694   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3695                                                                   /*isLogarithmic=*/false,
3696                                                                   myObject );
3697   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3698   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3699   if ( &histogramVar.in() )
3700   {
3701     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3702       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3703     if ( histogramVar->length() >= 2 )
3704       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3705   }
3706   return aHistogram;
3707 }
3708 #endif
3709
3710 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3711   out << QString( 20, '-' ) << "\n";
3712   out << tr( "CTRL_INFO"  ) << "\n";
3713   out << QString( 20, '-' ) << "\n";
3714   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3715   out <<                                 tr( "NODES_INFO" )                     << "\n";
3716   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3717   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3718   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3719   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3720   out <<                                 tr( "FACES_INFO" )                     << "\n";
3721   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3722   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3723   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3724   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3725   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3726 }
3727
3728 /*!
3729   \class SMESHGUI_CtrlInfoDlg
3730   \brief Controls information dialog box
3731 */
3732
3733 /*!
3734   \brief Constructor
3735   \param parent parent widget
3736   \param page specifies the dialog page to be shown at the start-up
3737 */
3738 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3739 : QDialog( parent )
3740 {
3741   setAttribute( Qt::WA_DeleteOnClose, true );
3742   setWindowTitle( tr( "CTRL_INFO" ) );
3743   setMinimumSize( 400, 600 );
3744
3745   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3746   
3747   // buttons
3748   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3749   okBtn->setAutoDefault( true );
3750   okBtn->setDefault( true );
3751   okBtn->setFocus();
3752   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3753   dumpBtn->setAutoDefault( true );
3754   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3755   helpBtn->setAutoDefault( true );
3756
3757   QHBoxLayout* btnLayout = new QHBoxLayout;
3758   btnLayout->setSpacing( SPACING );
3759   btnLayout->setMargin( 0 );
3760
3761   btnLayout->addWidget( okBtn );
3762   btnLayout->addWidget( dumpBtn );
3763   btnLayout->addStretch( 10 );
3764   btnLayout->addWidget( helpBtn );
3765
3766   QVBoxLayout* l = new QVBoxLayout ( this );
3767   l->setMargin( MARGIN );
3768   l->setSpacing( SPACING );
3769   l->addWidget( myCtrlInfo );
3770   l->addLayout( btnLayout );
3771
3772   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
3773   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3774   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3775   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3776   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
3777
3778   updateSelection();
3779 }
3780
3781 /*!
3782   \brief Destructor
3783 */
3784 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3785 {
3786 }
3787
3788 /*!
3789   \brief Show controls information
3790   \param IO interactive object
3791 */
3792 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3793 {  
3794   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ) )
3795     myCtrlInfo->showInfo( obj );
3796 }
3797
3798 /*!
3799   \brief Perform clean-up actions on the dialog box closing.
3800 */
3801 void SMESHGUI_CtrlInfoDlg::reject()
3802 {
3803   SMESH::SetPointRepresentation( false );
3804   QDialog::reject();
3805 }
3806
3807 /*!
3808   \brief Setup selection mode depending on the current dialog box state.
3809 */
3810 void SMESHGUI_CtrlInfoDlg::updateSelection()
3811 {
3812   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3813   disconnect( selMgr, 0, this, 0 );
3814   SMESH::SetPointRepresentation( false );  
3815   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3816   updateInfo();  
3817 }
3818
3819 /*!
3820   \brief Show mesh information
3821 */
3822 void SMESHGUI_CtrlInfoDlg::updateInfo()
3823 {
3824   SUIT_OverrideCursor wc;
3825
3826   SALOME_ListIO selected;
3827   SMESHGUI::selectionMgr()->selectedObjects( selected );
3828
3829   if ( selected.Extent() == 1 ) {
3830     Handle(SALOME_InteractiveObject) IO = selected.First();
3831     showInfo( IO );
3832   }
3833 }
3834
3835 /*!
3836   \brief Activate dialog box
3837 */
3838 void SMESHGUI_CtrlInfoDlg::activate()
3839 {
3840   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3841   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3842   updateSelection();
3843 }
3844
3845 /*!
3846   \brief Deactivate dialog box
3847 */
3848 void SMESHGUI_CtrlInfoDlg::deactivate()
3849 {
3850   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3851 }
3852
3853 /*!
3854  * \brief Dump contents into a file
3855  */
3856 void SMESHGUI_CtrlInfoDlg::dump()
3857 {
3858   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3859   if ( !app ) return;
3860   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3861   if ( !appStudy ) return;
3862   _PTR( Study ) aStudy = appStudy->studyDS();
3863
3864   QStringList aFilters;
3865   aFilters.append( tr( "TEXT_FILES" ) );
3866
3867   DumpFileDlg fd( this );
3868   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3869   fd.setNameFilters( aFilters );
3870   fd.myBaseChk->hide();
3871   fd.myElemChk->hide();
3872   fd.myAddChk ->hide();
3873   fd.myCtrlChk->hide();
3874   if ( fd.exec() == QDialog::Accepted )
3875   {
3876     QString aFileName = fd.selectedFile();
3877     if ( !aFileName.isEmpty() ) {
3878       QFileInfo aFileInfo( aFileName );
3879       if ( aFileInfo.isDir() )
3880         return;
3881  
3882       QFile aFile( aFileName );
3883       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3884         return;
3885       
3886       QTextStream out( &aFile );
3887       myCtrlInfo->saveInfo( out );
3888     }
3889   }
3890 }
3891
3892 /*!
3893  * \brief Show help
3894  */
3895 void SMESHGUI_CtrlInfoDlg::help()
3896 {
3897   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
3898 }