Salome HOME
Merge remote branch 'origin/V7_dev'
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESHGUI_MeshInfo.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24
25 #include "SMESHGUI_MeshInfo.h"
26
27 #include "SMDSAbs_ElementType.hxx"
28 #include "SMDS_BallElement.hxx"
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_Mesh.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMESHDS_Mesh.hxx"
34 #include "SMESHGUI.h"
35 #include "SMESHGUI_FilterUtils.h"
36 #include "SMESHGUI_IdValidator.h"
37 #include "SMESHGUI_SpinBox.h"
38 #include "SMESHGUI_Utils.h"
39 #include "SMESHGUI_VTKUtils.h"
40 #include "SMESH_Actor.h"
41
42 #include <LightApp_SelectionMgr.h>
43 #include <SUIT_FileDlg.h>
44 #include <SUIT_OverrideCursor.h>
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_Session.h>
47 #include <SVTK_ViewWindow.h>
48
49 #include <SALOMEDSClient_Study.hxx>
50 #include <SalomeApp_Study.h>
51
52 #include <QApplication>
53 #include <QButtonGroup>
54 #include <QCheckBox>
55 #include <QContextMenuEvent>
56 #include <QGridLayout>
57 #include <QHBoxLayout>
58 #include <QHeaderView>
59 #include <QItemDelegate>
60 #include <QKeyEvent>
61 #include <QLabel>
62 #include <QLineEdit>
63 #include <QMenu>
64 #include <QPushButton>
65 #include <QToolButton>
66 #include <QRadioButton>
67 #include <QTextStream>
68 #include <QTabWidget>
69 #include <QTextBrowser>
70 #include <QVBoxLayout>
71
72 #include "utilities.h"
73
74 #include <SALOMEconfig.h>
75 #include CORBA_SERVER_HEADER(GEOM_Gen)
76
77 namespace {
78
79 const int SPACING      = 6;
80 const int MARGIN       = 9;
81 const int MAXITEMS     = 10;
82 const int GROUPS_ID    = 100;
83 const int SUBMESHES_ID = 200;
84 const int SPACING_INFO = 2;
85
86 enum InfoRole {
87   TypeRole = Qt::UserRole + 10,
88   IdRole,
89 };
90
91 enum InfoType {
92   NodeConnectivity = 100,
93   ElemConnectivity,
94 };
95 } // namesapce
96
97 /*!
98   \class ExtraWidget
99   \internal
100 */
101 class ExtraWidget : public QWidget
102 {
103 public:
104   ExtraWidget( QWidget*, bool = false );
105   ~ExtraWidget();
106
107   void updateControls( int, int, int = MAXITEMS );
108
109 public:
110   QLabel*      current;
111   QPushButton* prev;
112   QPushButton* next;
113   bool         brief;
114 };
115
116 ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b )
117 {
118   current = new QLabel( this );
119   current->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
120   prev = new QPushButton( tr( "<<" ), this );
121   next = new QPushButton( tr( ">>" ), this );
122   QHBoxLayout* hbl = new QHBoxLayout( this );
123   hbl->setContentsMargins( 0, SPACING, 0, 0 );
124   hbl->setSpacing( SPACING );
125   hbl->addStretch();
126   hbl->addWidget( current );
127   hbl->addWidget( prev );
128   hbl->addWidget( next );
129 }
130
131 ExtraWidget::~ExtraWidget()
132 {
133 }
134
135 void ExtraWidget::updateControls( int total, int index, int blockSize )
136 {
137   setVisible( total > blockSize );
138   QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" );
139   current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total ) ).arg( total ) );
140   prev->setEnabled( index > 0 );
141   next->setEnabled( (index+1)*blockSize < total );
142 }
143
144 /*!
145   \class DumpFileDlg
146   \brief Customization of standard "Save file" dialog box for dump info operation
147   \internal
148 */
149
150 class DumpFileDlg : public SUIT_FileDlg
151 {
152 public:
153   DumpFileDlg( QWidget* parent );
154
155   QCheckBox* myBaseChk;
156   QCheckBox* myElemChk;
157   QCheckBox* myAddChk;
158   QCheckBox* myCtrlChk;
159 };
160
161 /*!
162   \brief Constructor
163   \internal
164 */
165 DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
166 {
167   QGridLayout* grid = ::qobject_cast<QGridLayout *>( layout() );
168   if ( grid ) {
169     QWidget* hB = new QWidget( this );
170     myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
171     myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
172     myAddChk  = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
173     myCtrlChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
174
175     QGridLayout* layout = new QGridLayout( hB );
176     layout->addWidget( myBaseChk, 0, 0 );
177     layout->addWidget( myElemChk, 0, 1 );
178     layout->addWidget( myAddChk, 1, 0 );
179     layout->addWidget( myCtrlChk, 1, 1 );
180
181     QPushButton* pb = new QPushButton( this );
182
183     int row = grid->rowCount();
184     grid->addWidget( new QLabel( "", this ), row, 0 );
185     grid->addWidget( hB, row, 1, 1, 3 );
186     grid->addWidget( pb, row, 5 );
187
188     pb->hide();
189   }
190 }
191
192 /*!
193   \brief Get depth of the tree item
194   \internal
195   \param theItem tree widget item
196   \return item's depth in tree widget (where top-level items have zero depth)
197 */
198 static int itemDepth( QTreeWidgetItem* item )
199 {
200   int d = 0;
201   QTreeWidgetItem* p = item->parent();
202   while ( p ) {
203     d++;
204     p = p->parent();
205   }
206   return d;
207 }
208
209 /*!
210   \class SMESHGUI_MeshInfo
211   \brief Base mesh information widget
212   
213   Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
214 */
215
216 /*!
217   \brief Constructor.
218   \param parent parent widget
219 */
220 SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
221   : QFrame( parent ), myWidgets( iElementsEnd )
222 {
223   setFrameStyle( StyledPanel | Sunken );
224
225   QGridLayout* l = new QGridLayout( this );
226   l->setMargin( MARGIN );
227   l->setSpacing( SPACING );
228
229   int index = 0;
230
231   // object
232   QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
233   QLabel* aName        = createField();
234   aName->setObjectName("meshName");
235   aName->setMinimumWidth( 150 );
236   QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
237   QLabel* aObj         = createField();
238   aObj->setObjectName("meshType");
239   aObj->setMinimumWidth( 150 );
240   myWidgets[ index++ ] << aNameLab << aName;
241   myWidgets[ index++ ] << aObjLab  << aObj;
242
243   // nodes
244   QWidget* aNodesLine  = createLine();
245   QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
246   QLabel*  aNodes      = createField();
247   aNodes->setObjectName("nbNodes");
248   myWidgets[ index++ ] << aNodesLine;
249   myWidgets[ index++ ] << aNodesLab << aNodes;
250
251   // elements
252   QWidget* aElemLine   = createLine();
253   QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),     this );
254   QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),        this );
255   QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),       this );
256   QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ),    this );
257   QLabel*  aElemBiQuad = new QLabel( tr( "BI_QUADRATIC_LAB" ), this );
258   myWidgets[ index++ ] << aElemLine;
259   myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad << aElemBiQuad;
260
261   // ... Number elements
262   QWidget* aNbLine     = createLine(); 
263   QLabel*  aNbTotal    = createField();
264   aNbTotal->setObjectName("totalNbElems");
265   QLabel*  aNbLin      = createField();
266   aNbLin->setObjectName("totalNbLinearElems");
267   QLabel*  aNbQuad     = createField();
268   aNbQuad->setObjectName("totalNbQuadraticElems");
269   QLabel*  aNbBiQuad   = createField();
270   aNbBiQuad->setObjectName("totalNbBiQuadraticElems");
271   myWidgets[ index++ ] << aNbLine;
272   myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad << aNbBiQuad;
273
274   // ... 0D elements
275   QWidget* a0DLine     = createLine();
276   QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
277   QLabel*  a0DTotal    = createField();
278   a0DTotal->setObjectName("nb0D");
279
280   myWidgets[ index++ ] << a0DLine;
281   myWidgets[ index++ ] << a0DLab << a0DTotal;
282
283   // ... Ball elements
284   QWidget* aBallLine     = createLine();
285   QLabel*  aBallLab      = new QLabel( tr( "BALL_LAB" ), this );
286   QLabel*  aBallTotal    = createField();
287   aBallTotal->setObjectName("nbBall");
288   myWidgets[ index++ ] << aBallLine;
289   myWidgets[ index++ ] << aBallLab << aBallTotal;
290
291   // ... 1D elements
292   QWidget* a1DLine     = createLine();
293   QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
294   QLabel*  a1DTotal    = createField();
295   a1DTotal->setObjectName("nb1D");
296   QLabel*  a1DLin      = createField();
297   a1DLin->setObjectName("nbLinear1D");
298   QLabel*  a1DQuad     = createField();
299   a1DQuad->setObjectName("nbQuadratic1D");
300   myWidgets[ index++ ] << a1DLine;
301   myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad;
302
303   // ... 2D elements
304   QWidget* a2DLine      = createLine();
305   QLabel*  a2DLab       = new QLabel( tr( "2D_LAB" ), this );
306   QLabel*  a2DTotal     = createField();
307   a2DTotal->setObjectName("nb2D");
308   QLabel*  a2DLin       = createField();
309   a2DLin->setObjectName("nbLinear2D");
310   QLabel*  a2DQuad      = createField();
311   a2DQuad->setObjectName("nbQuadratic2D");
312   QLabel*  a2DBiQuad    = createField();
313   a2DBiQuad->setObjectName("nbBiQuadratic2D");
314   QLabel*  a2DTriLab    = new QLabel( tr( "TRIANGLES_LAB" ), this );
315   QLabel*  a2DTriTotal  = createField();
316   a2DTriTotal->setObjectName("nbTriangle");
317   QLabel*  a2DTriLin    = createField();
318   a2DTriLin->setObjectName("nbLinearTriangle");
319   QLabel*  a2DTriQuad   = createField();
320   a2DTriQuad->setObjectName("nbQuadraticTriangle");
321   QLabel*  a2DTriBiQuad = createField();
322     a2DTriBiQuad->setObjectName("nbBiQuadraticTriangle");
323   QLabel*  a2DQuaLab    = new QLabel( tr( "QUADRANGLES_LAB" ), this );
324   QLabel*  a2DQuaTotal  = createField();
325   a2DQuaTotal->setObjectName("nbQuadrangle");
326   QLabel*  a2DQuaLin    = createField();
327   a2DQuaLin->setObjectName("nbLinearQuadrangle");
328   QLabel*  a2DQuaQuad   = createField();
329   a2DQuaQuad->setObjectName("nbQuadraticQuadrangle");
330   QLabel*  a2DQuaBiQuad = createField();
331   a2DQuaBiQuad->setObjectName("nbBiQuadraticQuadrangle");
332   QLabel*  a2DPolLab    = new QLabel( tr( "POLYGONS_LAB" ), this );
333   QLabel*  a2DPolTotal  = createField();
334   a2DPolTotal->setObjectName("nbPolygon");
335   QLabel*  a2DPolLin    = createField();
336   a2DPolLin->setObjectName("nbLinearPolygon");
337   QLabel*  a2DPolQuad   = createField();
338   a2DPolQuad->setObjectName("nbQuadraticPolygon");
339   myWidgets[ index++ ] << a2DLine;
340   myWidgets[ index++ ] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad    << a2DBiQuad;
341   myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad << a2DTriBiQuad;
342   myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad << a2DQuaBiQuad;
343   myWidgets[ index++ ] << a2DPolLab << a2DPolTotal << a2DPolLin << a2DPolQuad;
344
345   // ... 3D elements
346   QWidget* a3DLine      = createLine();
347   QLabel*  a3DLab       = new QLabel( tr( "3D_LAB" ), this );
348   QLabel*  a3DTotal     = createField();
349   a3DTotal->setObjectName("nb3D");
350   QLabel*  a3DLin       = createField();
351   a3DLin->setObjectName("nbLinear3D");
352   QLabel*  a3DQuad      = createField();
353   a3DQuad->setObjectName("nbQuadratic3D");
354   QLabel*  a3DBiQuad    = createField();
355   a3DBiQuad->setObjectName("nbBiQuadratic3D");
356   QLabel*  a3DTetLab    = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
357   QLabel*  a3DTetTotal  = createField();
358   a3DTetTotal->setObjectName("nbTetrahedron");
359   QLabel*  a3DTetLin    = createField();
360   a3DTetLin->setObjectName("nbLinearTetrahedron");
361   QLabel*  a3DTetQuad   = createField();
362   a3DTetQuad->setObjectName("nbQudraticTetrahedron");
363   QLabel*  a3DHexLab    = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
364   QLabel*  a3DHexTotal  = createField();
365   a3DHexTotal->setObjectName("nbHexahedron");
366   QLabel*  a3DHexLin    = createField();
367   a3DHexLin->setObjectName("nbLinearHexahedron");
368   QLabel*  a3DHexQuad   = createField();
369   a3DHexQuad->setObjectName("nbQuadraticHexahedron");
370   QLabel*  a3DHexBiQuad = createField();
371   a3DHexBiQuad->setObjectName("nbBiQuadraticHexahedron");
372   QLabel*  a3DPyrLab    = new QLabel( tr( "PYRAMIDS_LAB" ), this );
373   QLabel*  a3DPyrTotal  = createField();
374   a3DPyrTotal->setObjectName("nbPyramid");
375   QLabel*  a3DPyrLin    = createField();
376   a3DPyrLin->setObjectName("nbLinearPyramid");
377   QLabel*  a3DPyrQuad   = createField();
378   a3DPyrQuad->setObjectName("nbQuadraticPyramid");
379   QLabel*  a3DPriLab    = new QLabel( tr( "PRISMS_LAB" ), this );
380   QLabel*  a3DPriTotal  = createField();
381   a3DPriTotal->setObjectName("nbPrism");
382   QLabel*  a3DPriLin    = createField();
383   a3DPriLin->setObjectName("nbLinearPrism");
384   QLabel*  a3DPriQuad   = createField();
385   a3DPriQuad->setObjectName("nbQuadraticPrism");
386   QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
387   QLabel*  a3DHexPriTotal = createField();
388   a3DHexPriTotal->setObjectName("nbHexagonalPrism");
389   QLabel*  a3DPolLab    = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
390   QLabel*  a3DPolTotal  = createField();
391   a3DPolTotal->setObjectName("nbPolyhedron");
392   myWidgets[ index++ ] << a3DLine;
393   myWidgets[ index++ ] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad    << a3DBiQuad;
394   myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
395   myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad << a3DHexBiQuad;
396   myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
397   myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
398   myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal;
399   myWidgets[ index++ ] << a3DPolLab << a3DPolTotal;
400
401   myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
402   myLoadBtn->setAutoDefault( true );
403   connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
404   
405   setFontAttributes( aNameLab,    Bold );
406   setFontAttributes( aObjLab,     Bold );
407   setFontAttributes( aNodesLab,   Bold );
408   setFontAttributes( aElemLab,    Bold );
409   setFontAttributes( aElemTotal,  Italic );
410   setFontAttributes( aElemLin,    Italic );
411   setFontAttributes( aElemQuad,   Italic );
412   setFontAttributes( aElemBiQuad, Italic );
413   setFontAttributes( a0DLab,      Bold );
414   setFontAttributes( aBallLab,    Bold );
415   setFontAttributes( a1DLab,      Bold );
416   setFontAttributes( a2DLab,      Bold );
417   setFontAttributes( a3DLab,      Bold );
418
419   l->addWidget( aNameLab,     0, 0 );
420   l->addWidget( aName,        0, 1, 1, 4 );
421   l->addWidget( aObjLab,      1, 0 );
422   l->addWidget( aObj,         1, 1, 1, 4 );
423   l->addWidget( aNodesLine,   2, 0, 1, 5 );
424   l->addWidget( aNodesLab,    3, 0 );
425   l->addWidget( aNodes,       3, 1 );
426   l->addWidget( aElemLine,    4, 0, 1, 5 );
427   l->addWidget( aElemLab,     5, 0 );
428   l->addWidget( aElemTotal,   5, 1 );
429   l->addWidget( aElemLin,     5, 2 );
430   l->addWidget( aElemQuad,    5, 3 );
431   l->addWidget( aElemBiQuad,  5, 4 );
432   l->addWidget( aNbLine,      6, 1, 1, 4 );
433   l->addWidget( aNbTotal,     7, 1 );
434   l->addWidget( aNbLin,       7, 2 );
435   l->addWidget( aNbQuad,      7, 3 );
436   l->addWidget( aNbBiQuad,    7, 4 );
437   l->addWidget( a0DLine,      8, 1, 1, 4 );
438   l->addWidget( a0DLab,       9, 0 );
439   l->addWidget( a0DTotal,     9, 1 );
440   l->addWidget( aBallLine,    10, 1, 1, 4 );
441   l->addWidget( aBallLab,     11, 0 );
442   l->addWidget( aBallTotal,   11, 1 );
443   l->addWidget( a1DLine,      12, 1, 1, 4 );
444   l->addWidget( a1DLab,       13, 0 );
445   l->addWidget( a1DTotal,     13, 1 );
446   l->addWidget( a1DLin,       13, 2 );
447   l->addWidget( a1DQuad,      13, 3 );
448   l->addWidget( a2DLine,      14, 1, 1, 4 );
449   l->addWidget( a2DLab,       15, 0 );
450   l->addWidget( a2DTotal,     15, 1 );
451   l->addWidget( a2DLin,       15, 2 );
452   l->addWidget( a2DQuad,      15, 3 );
453   l->addWidget( a2DBiQuad,    15, 4 );
454   l->addWidget( a2DTriLab,    16, 0 );
455   l->addWidget( a2DTriTotal,  16, 1 );
456   l->addWidget( a2DTriLin,    16, 2 );
457   l->addWidget( a2DTriQuad,   16, 3 );
458   l->addWidget( a2DTriBiQuad, 16, 4 );
459   l->addWidget( a2DQuaLab,    17, 0 );
460   l->addWidget( a2DQuaTotal,  17, 1 );
461   l->addWidget( a2DQuaLin,    17, 2 );
462   l->addWidget( a2DQuaQuad,   17, 3 );
463   l->addWidget( a2DQuaBiQuad, 17, 4 );
464   l->addWidget( a2DPolLab,    18, 0 );
465   l->addWidget( a2DPolTotal,  18, 1 );
466   l->addWidget( a2DPolLin,    18, 2 );
467   l->addWidget( a2DPolQuad,   18, 3 );
468   l->addWidget( a3DLine,      19, 1, 1, 4 );
469   l->addWidget( a3DLab,       20, 0 );
470   l->addWidget( a3DTotal,     20, 1 );
471   l->addWidget( a3DLin,       20, 2 );
472   l->addWidget( a3DQuad,      20, 3 );
473   l->addWidget( a3DBiQuad,    20, 4 );
474   l->addWidget( a3DTetLab,    21, 0 );
475   l->addWidget( a3DTetTotal,  21, 1 );
476   l->addWidget( a3DTetLin,    21, 2 );
477   l->addWidget( a3DTetQuad,   21, 3 );
478   l->addWidget( a3DHexLab,    22, 0 );
479   l->addWidget( a3DHexTotal,  22, 1 );
480   l->addWidget( a3DHexLin,    22, 2 );
481   l->addWidget( a3DHexQuad,   22, 3 );
482   l->addWidget( a3DHexBiQuad, 22, 4 );
483   l->addWidget( a3DPyrLab,    23, 0 );
484   l->addWidget( a3DPyrTotal,  23, 1 );
485   l->addWidget( a3DPyrLin,    23, 2 );
486   l->addWidget( a3DPyrQuad,   23, 3 );
487   l->addWidget( a3DPriLab,    24, 0 );
488   l->addWidget( a3DPriTotal,  24, 1 );
489   l->addWidget( a3DPriLin,    24, 2 );
490   l->addWidget( a3DPriQuad,   24, 3 );
491   l->addWidget( a3DHexPriLab,   25, 0 );
492   l->addWidget( a3DHexPriTotal, 25, 1 );
493   l->addWidget( a3DPolLab,    26, 0 );
494   l->addWidget( a3DPolTotal,  26, 1 );
495   l->addWidget( myLoadBtn,    28, 1, 1, 4 );
496
497   l->setColumnStretch( 0, 0 );
498   l->setColumnStretch( 1, 5 );
499   l->setColumnStretch( 2, 5 );
500   l->setColumnStretch( 3, 5 );
501   l->setColumnStretch( 4, 5 );
502   l->setRowStretch( 27, 5 );
503
504   clear();
505 }
506
507 /*!
508   \brief Destructor
509 */
510 SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
511 {
512 }
513
514 /*!
515   \brief Show information on the mesh object.
516   \param obj object being processed (mesh, sub-mesh, group, ID source)
517 */
518 void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
519 {
520   clear();
521   if ( !CORBA::is_nil( obj ) ) {
522     _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
523     if ( sobj ) 
524       myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
525     SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
526     SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
527     SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
528     if ( !aMesh->_is_nil() ) {
529       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) );
530     }
531     else if ( !aSubMesh->_is_nil() ) {
532       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) );
533     }
534     else if ( !aGroup->_is_nil() ) {
535       QString objType;
536       switch( aGroup->GetType() ) {
537       case SMESH::NODE:  objType = tr( "OBJECT_GROUP_NODES"   );break;
538       case SMESH::EDGE:  objType = tr( "OBJECT_GROUP_EDGES"   );break;
539       case SMESH::FACE:  objType = tr( "OBJECT_GROUP_FACES"   );break;
540       case SMESH::VOLUME:objType = tr( "OBJECT_GROUP_VOLUMES" );break;
541       case SMESH::ELEM0D:objType = tr( "OBJECT_GROUP_0DELEMS" );break;
542       case SMESH::BALL:  objType = tr( "OBJECT_GROUP_BALLS"   );break;
543       default:           objType = tr( "OBJECT_GROUP"         );break;
544       }
545       myWidgets[iObject][iSingle]->setProperty( "text", objType );
546     }
547     SMESH::long_array_var info = obj->GetMeshInfo();
548     myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
549     myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
550     myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ) );
551     long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
552     myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ) );
553     myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) );
554     myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) );
555     long nbTriangles     = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_BiQuad_Triangle];
556     long nbQuadrangles   = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
557     long nb2DPolygons    = info[SMDSEntity_Polygon]    + info[SMDSEntity_Quad_Polygon];
558     long nb2DLinear      = info[SMDSEntity_Triangle]        + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
559     long nb2DQuadratic   = info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_Quad_Polygon];
560     long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle];
561     long nb2DTotal       = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic;
562
563     myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( nb2DTotal ));
564     myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( nb2DLinear ) );
565     myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( nb2DQuadratic ) );
566     myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( nb2DBiQuadratic ) );
567     myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( nbTriangles ) );
568     myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) );
569     myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) );
570     myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Triangle] ) );
571     myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( nbQuadrangles ) );
572     myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) );
573     myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) );
574     myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Quadrangle] ) );
575     myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( nb2DPolygons ));
576     myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
577     myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Polygon] ) );
578     long nbTetrahedrons  = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
579     long nbHexahedrons   = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
580     long nbPyramids      = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
581     long nbPrisms        = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta];
582     long nb3DLinear      = info[SMDSEntity_Tetra]   + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
583     long nb3DQuadratic   = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
584     long nb3DBiQuadratic = info[SMDSEntity_TriQuad_Hexa];
585     long nb3DTotal       = nb3DLinear + nb3DQuadratic + nb3DBiQuadratic;
586     myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( nb3DTotal ) );
587     myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( nb3DLinear ) );
588     myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( nb3DQuadratic ) );
589     myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( nb3DBiQuadratic ) );
590     myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( nbTetrahedrons ) );
591     myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
592     myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) );
593     myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( nbHexahedrons ) );
594     myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) );
595     myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ) );
596     myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_TriQuad_Hexa] ) );
597     myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( nbPyramids ) );
598     myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) );
599     myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) );
600     myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( nbPrisms ) );
601     myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) );
602     myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) );
603     myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
604     myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
605     long nbElemTotal       = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DTotal + nb3DTotal;
606     long nbElemLinerial    = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear;
607     long nbElemQuadratic   = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic;
608     long nbElemBiQuadratic = nb2DBiQuadratic + nb3DBiQuadratic;
609     myWidgets[iNb][iTotal]      ->setProperty( "text", QString::number( nbElemTotal ) );
610     myWidgets[iNb][iLinear]     ->setProperty( "text", QString::number( nbElemLinerial ) );
611     myWidgets[iNb][iQuadratic]  ->setProperty( "text", QString::number( nbElemQuadratic ) );
612     myWidgets[iNb][iBiQuadratic]->setProperty( "text", QString::number( nbElemBiQuadratic ) );
613     // before full loading from study file, type of elements in a sub-mesh can't be defined
614     // in some cases
615     bool infoOK = obj->IsMeshInfoCorrect();
616     myLoadBtn->setVisible( !infoOK );
617     if ( !infoOK )
618     {
619       // two options:
620       // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
621       // 2. No info at all (for a group on geom or filter)
622       bool hasAnyInfo = false;
623       for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
624         hasAnyInfo = info[i];
625       if ( hasAnyInfo ) // believe it is a sub-mesh
626       {
627         if ( nb2DLinear + nb2DQuadratic + nb2DBiQuadratic > 0 )
628         {
629           myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
630           myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
631           myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
632           myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
633           myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
634           myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
635           myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
636           myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
637           myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
638           myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
639           myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
640           myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", "?" );
641           myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", "?" );
642           myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
643           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
644           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
645           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
646           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
647         }
648         else if ( nb3DLinear + nb3DQuadratic + nb3DBiQuadratic > 0 )
649         {
650           myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
651           myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
652           myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", "?" );
653           myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
654           myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
655           myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
656           myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
657           myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
658           myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
659           myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
660           myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
661           myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
662           myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
663           myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
664           myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
665           myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
666           myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
667           myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
668           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
669           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
670           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
671           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
672         }
673       }
674       else
675       {
676         myWidgets[iNodes][iTotal]               ->setProperty( "text", "?" );
677         myWidgets[i0D][iTotal]                  ->setProperty( "text", "?" );
678         myWidgets[iBalls][iTotal]               ->setProperty( "text", "?" );
679         myWidgets[i1D][iTotal]                  ->setProperty( "text", "?" );
680         myWidgets[i1D][iLinear]                 ->setProperty( "text", "?" );
681         myWidgets[i1D][iQuadratic]              ->setProperty( "text", "?" );
682         myWidgets[i2D][iTotal]                  ->setProperty( "text", "?" );
683         myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
684         myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
685         myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
686         myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
687         myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
688         myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
689         myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
690         myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
691         myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
692         myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
693         myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
694         myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
695         myWidgets[i3D][iTotal]                  ->setProperty( "text", "?" );
696         myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
697         myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
698         myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
699         myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
700         myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
701         myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
702         myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
703         myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
704         myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
705         myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
706         myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
707         myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
708         myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
709         myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
710         myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
711         myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
712         myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
713         myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
714         myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
715         myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
716         myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
717       }
718     }
719   }
720 }
721
722 /*!
723   \brief Load mesh from a study file
724 */
725 void SMESHGUI_MeshInfo::loadMesh()
726 {
727   SUIT_OverrideCursor wc;
728
729   SALOME_ListIO selected;
730   SMESHGUI::selectionMgr()->selectedObjects( selected );
731
732   if ( selected.Extent() == 1 ) {
733     Handle(SALOME_InteractiveObject) IO = selected.First();
734     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
735     if ( !CORBA::is_nil( obj ) ) {
736       SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
737       if ( !mesh->_is_nil() )
738       {
739         mesh->Load();
740         showInfo( obj );
741       }
742     }
743   }
744 }
745
746 /*!
747   \brief Reset the widget to the initial state (nullify all fields).
748 */
749 void SMESHGUI_MeshInfo::clear()
750 {
751   myWidgets[iName][iSingle]               ->setProperty( "text", QString() );
752   myWidgets[iObject][iSingle]             ->setProperty( "text", QString() );
753   myWidgets[iNodes][iTotal]               ->setProperty( "text", QString::number( 0 ) );
754   myWidgets[i0D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
755   myWidgets[iBalls][iTotal]               ->setProperty( "text", QString::number( 0 ) );
756   myWidgets[i1D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
757   myWidgets[i1D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
758   myWidgets[i1D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
759   myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
760   myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
761   myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
762   myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
763   myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( 0 ) );
764   myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( 0 ) );
765   myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( 0 ) );
766   myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( 0 ) );
767   myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( 0 ) );
768   myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( 0 ) );
769   myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
770   myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
771   myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( 0 ) );
772   myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
773   myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( 0 ) );
774   myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
775   myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
776   myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
777   myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
778   myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( 0 ) );
779   myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( 0 ) );
780   myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( 0 ) );
781   myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
782   myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( 0 ) );
783   myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
784   myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
785   myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( 0 ) );
786   myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( 0 ) );
787   myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
788   myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( 0 ) );
789   myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( 0 ) );
790   myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( 0 ) );
791   myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( 0 ) );
792   myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
793   myWidgets[iNb][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
794   myWidgets[iNb][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
795   myWidgets[iNb][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
796   myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
797 }
798
799 /*!
800   \brief Create info field
801   \return new info field
802 */
803 QLabel* SMESHGUI_MeshInfo::createField()
804 {
805   QLabel* lab = new QLabel( this );
806   lab->setFrameStyle( StyledPanel | Sunken );
807   lab->setAlignment( Qt::AlignCenter );
808   lab->setAutoFillBackground( true );
809   QPalette pal = lab->palette();
810   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
811   lab->setPalette( pal );
812   lab->setMinimumWidth( 70 );
813   return lab;
814 }
815
816 /*!
817   \brief Create horizontal rule.
818   \return new line object
819 */
820 QWidget* SMESHGUI_MeshInfo::createLine()
821 {
822   QFrame* line = new QFrame( this );
823   line->setFrameStyle( HLine | Sunken );
824   return line;
825 }
826
827 /*!
828   \brief Change widget font attributes (bold, italic, ...).
829   \param w widget
830   \param attr font attributes (XORed flags)
831   \param val value to be set to attributes
832 */
833 void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
834 {
835   if ( w && attr ) {
836     QFont f = w->font();
837     if ( attr & Bold   ) f.setBold( val );
838     if ( attr & Italic ) f.setItalic( val );
839     w->setFont( f );
840   }
841 }
842
843 /*!
844   \brief Show/hide group(s) of fields.
845   \param start beginning of the block
846   \param end end of the block
847   \param on visibility flag
848 */
849 void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
850 {
851   start = qMax( 0, start );
852   end   = qMin( end, (int)iElementsEnd );
853   for ( int i = start; i < end; i++ ) {
854     wlist wl = myWidgets[i];
855     foreach ( QWidget* w, wl ) w->setVisible( on );
856   }
857 }
858
859 void SMESHGUI_MeshInfo::saveInfo( QTextStream &out )
860 {
861   out << QString( 9, '-' ) << "\n";
862   out << tr( "BASE_INFO" ) << "\n";
863   out << QString( 9, '-' ) << "\n";
864   out <<                                   tr( "NAME_LAB" )         << "  " << ( myWidgets[iName][iSingle]->property( "text" ) ).toString() << "\n";
865   out <<                                   tr( "OBJECT_LAB" )       << "  " << ( myWidgets[iObject][iSingle]->property( "text" ) ).toString() << "\n";
866   out <<                                   tr( "NODES_LAB" )        << "  " << ( myWidgets[iNodes][iTotal]->property( "text" ) ).toString() << "\n";
867   out <<                                   tr( "ELEMENTS_LAB" )     << "\n";
868   out << QString( SPACING_INFO,   ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iNb][iTotal]->property( "text" ) ).toString() << "\n";
869   out << QString( SPACING_INFO,   ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[iNb][iLinear]->property( "text" ) ).toString() << "\n";
870   out << QString( SPACING_INFO,   ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" ) ).toString() << "\n";
871   out << QString( SPACING_INFO,   ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[iNb][iBiQuadratic]->property( "text" ) ).toString() << "\n";
872   out << QString( SPACING_INFO,   ' ' ) << tr( "0D_LAB" )           << "\n";
873   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i0D][iTotal]->property( "text" ) ).toString() << "\n";
874   out << QString( SPACING_INFO,   ' ' ) << tr( "BALL_LAB" )         << "\n";
875   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iBalls][iTotal]->property( "text" ) ).toString() << "\n";
876   out << QString( SPACING_INFO,   ' ' ) << tr( "1D_LAB" )           << "\n";
877   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i1D][iTotal]->property( "text" ) ).toString() << "\n";
878   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i1D][iLinear]->property( "text" ) ).toString() << "\n";
879   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" ) ).toString() << "\n";
880   out << QString( SPACING_INFO,   ' ' ) << tr( "2D_LAB" )           << "\n";
881   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2D][iTotal]->property( "text" ) ).toString() << "\n";
882   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2D][iLinear]->property( "text" ) ).toString() << "\n";
883   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" ) ).toString() << "\n";
884   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
885   out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" )    << "\n";
886   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" ) ).toString() << "\n";
887   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" ) ).toString() << "\n";
888   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" ) ).toString() << "\n";
889   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DTriangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
890   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" )  << "\n";
891   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" ) ).toString() << "\n";
892   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" ) ).toString() << "\n";
893   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" ) ).toString() << "\n";
894   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
895   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" )     << "\n";
896   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n";
897   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DPolygons][iLinear]->property( "text" ) ).toString() << "\n";
898   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DPolygons][iQuadratic]->property( "text" ) ).toString() << "\n";
899   out << QString( SPACING_INFO,   ' ' ) << tr( "3D_LAB" )           << "\n";
900   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n";
901   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n";
902   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" ) ).toString() << "\n";
903   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
904   out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n";
905   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" ) ).toString() << "\n";
906   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" ) ).toString() << "\n";
907   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
908   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" )  << "\n";
909   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" ) ).toString() << "\n";
910   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" ) ).toString() << "\n";
911   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
912   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iBiQuadratic]->property( "text" ) ).toString() << "\n";
913   out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" )     << "\n";
914   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" ) ).toString() << "\n";
915   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" ) ).toString() << "\n";
916   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" ) ).toString() << "\n";
917   out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" )       << "\n";
918   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" ) ).toString() << "\n";
919   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" ) ).toString() << "\n";
920   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" ) ).toString() << "\n";
921   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" )   << "\n";
922   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" ) ).toString() << "\n";
923   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" )  << "\n";
924   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" ) ).toString() << "\n" << "\n";
925 }
926
927 /*!
928   \class SMESHGUI_ElemInfo
929   \brief Base class for the mesh element information widget.
930 */
931
932 /*!
933   \brief Constructor
934   \param parent parent widget
935 */
936 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
937 : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
938 {
939   myFrame = new QWidget( this );
940   myExtra = new ExtraWidget( this );
941   QVBoxLayout* vbl = new QVBoxLayout( this );
942   vbl->setMargin( 0 );
943   vbl->setSpacing( 0 );
944   vbl->addWidget( myFrame );
945   vbl->addWidget( myExtra );
946   connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
947   connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
948   clear();
949 }
950
951 /*!
952   \brief Destructor
953 */
954 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
955 {
956 }
957
958 /*!
959   \brief Set mesh data source (actor)
960   \param actor mesh object actor
961 */
962 void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
963 {
964   if ( myActor != actor ) {
965     myActor = actor;
966     myIsElement = -1;
967     clear();
968   }
969 }
970
971 /*!
972   \brief Show mesh element information
973   \param id mesh node / element ID
974   \param isElem show mesh element information if \c true or mesh node information if \c false
975 */
976 void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
977 {
978   QSet<long> ids;
979   ids << id;
980   showInfo( ids, isElem );
981 }
982
983 /*!
984   \brief Show mesh element information
985   \param ids mesh nodes / elements identifiers
986   \param isElem show mesh element information if \c true or mesh node information if \c false
987 */
988 void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
989 {
990   QList<long> newIds = ids.toList();
991   qSort( newIds );
992   if ( myIDs == newIds && myIsElement == isElem ) return;
993
994   myIDs = newIds;
995   myIsElement = isElem;
996   myIndex = 0;
997   updateControls();
998   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
999 }
1000
1001 /*!
1002   \brief Clear mesh element information widget
1003 */
1004 void SMESHGUI_ElemInfo::clear()
1005 {
1006   myIDs.clear();
1007   myIndex = 0;
1008   clearInternal();
1009   updateControls();
1010 }
1011
1012 /*!
1013   \brief Get central area widget
1014   \return central widget
1015 */
1016 QWidget* SMESHGUI_ElemInfo::frame() const
1017 {
1018   return myFrame;
1019 }
1020
1021 /*!
1022   \brief Get actor
1023   \return actor being used
1024 */
1025 SMESH_Actor* SMESHGUI_ElemInfo::actor() const
1026 {
1027   return myActor;
1028 }
1029
1030 /*!
1031   \brief Get current info mode.
1032   \return \c true if mesh element information is shown or \c false if node information is shown
1033 */
1034 bool SMESHGUI_ElemInfo::isElements() const
1035 {
1036   return myIsElement;
1037 }
1038
1039 /*!
1040   \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
1041   \brief Show information on the specified nodes / elements
1042
1043   This function is to be redefined in sub-classes.
1044
1045   \param ids nodes / elements identifiers information is to be shown on
1046 */
1047
1048 /*!
1049   \brief Internal clean-up (reset widget)
1050 */
1051 void SMESHGUI_ElemInfo::clearInternal()
1052 {
1053 }
1054
1055 /*!
1056   \brief Get node connectivity
1057   \param node mesh node
1058   \return node connectivity map
1059 */
1060 SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
1061 {
1062   Connectivity elmap;
1063   if ( node ) {
1064     SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
1065     while ( it && it->more() ) {
1066       const SMDS_MeshElement* ne = it->next();
1067       elmap[ ne->GetType() ] << ne->GetID();
1068     }
1069   }
1070   return elmap;
1071 }
1072
1073 /*!
1074   \brief Format connectivity data to string representation
1075   \param connectivity connetivity map
1076   \param type element type
1077   \return string representation of the connectivity
1078 */
1079 QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
1080 {
1081   QStringList str;
1082   if ( connectivity.contains( type ) ) {
1083     QList<int> elements = connectivity[ type ];
1084     qSort( elements );
1085     foreach( int id, elements )
1086       str << QString::number( id );
1087   }
1088   return str.join( " " );
1089 }
1090
1091 /*!
1092   \brief Calculate gravity center of the mesh element
1093   \param element mesh element
1094 */
1095 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
1096 {
1097   XYZ xyz;
1098   if ( element ) {
1099     SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
1100     while ( nodeIt->more() ) {
1101       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1102       xyz.add( node->X(), node->Y(), node->Z() );
1103     }
1104     xyz.divide( element->NbNodes() );
1105   }
1106   return xyz;
1107 }
1108
1109 /*!
1110   \brief Calculate normal vector to the mesh face
1111   \param element mesh face
1112 */
1113 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::normal( const SMDS_MeshElement* element )
1114 {
1115   gp_XYZ n = SMESH::getNormale( dynamic_cast<const SMDS_MeshFace*>( element ) );
1116   return XYZ(n.X(), n.Y(), n.Z());
1117 }
1118
1119 /*!
1120   \brief This slot is called from "Show Previous" button click.
1121   Shows information on the previous group of the items.
1122 */
1123 void SMESHGUI_ElemInfo::showPrevious()
1124 {
1125   myIndex = qMax( 0, myIndex-1 );
1126   updateControls();
1127   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1128 }
1129
1130 /*!
1131   \brief This slot is called from "Show Next" button click.
1132   Shows information on the next group of the items.
1133 */
1134 void SMESHGUI_ElemInfo::showNext()
1135 {
1136   myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
1137   updateControls();
1138   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1139 }
1140
1141 /*!
1142   \brief Update widgets state
1143 */
1144 void SMESHGUI_ElemInfo::updateControls()
1145 {
1146   myExtra->updateControls( myIDs.count(), myIndex );
1147 }
1148
1149 /*!
1150   \class SMESHGUI_SimpleElemInfo
1151   \brief Represents mesh element information in the simple text area.
1152 */
1153
1154 /*!
1155   \brief Constructor
1156   \param parent parent widget
1157 */
1158 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
1159 : SMESHGUI_ElemInfo( parent )
1160 {
1161   myInfo = new QTextBrowser( frame() );
1162   QVBoxLayout* l = new QVBoxLayout( frame() );
1163   l->setMargin( 0 );
1164   l->addWidget( myInfo );
1165 }
1166
1167 /*!
1168   \brief Show mesh element information
1169   \param ids mesh nodes / elements identifiers
1170 */
1171 void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
1172 {
1173   clearInternal();
1174   
1175   if ( actor() ) {
1176     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1177     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1178     int cprecision = -1;
1179     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1180       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1181     foreach ( long id, ids ) {
1182       if ( !isElements() ) {
1183         //
1184         // show node info
1185         //
1186         const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
1187         if ( !node ) return;
1188
1189         // node ID
1190         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( id ) );
1191         // separator
1192         myInfo->append( "" );
1193         // coordinates
1194         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1195                         arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1196                         arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1197                         arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1198         // separator
1199         myInfo->append( "" );
1200         // connectivity
1201         Connectivity connectivity = nodeConnectivity( node );
1202         if ( !connectivity.isEmpty() ) {
1203           myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1204           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1205           if ( !con.isEmpty() )
1206             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1207           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1208           if ( !con.isEmpty() )
1209             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1210           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1211           if ( !con.isEmpty() )
1212             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ).arg( con ) );
1213           con = formatConnectivity( connectivity, SMDSAbs_Face );
1214           if ( !con.isEmpty() )
1215             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1216           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1217           if ( !con.isEmpty() )
1218             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1219         }
1220         else {
1221           myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1222         }
1223         // node position
1224         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1225         if ( !CORBA::is_nil( aMeshPtr ) ) {
1226           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1227           int shapeID = pos->shapeID;
1228           if ( shapeID > 0 ) {
1229             QString shapeType;
1230             double u, 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     SUIT_OverrideCursor wc;
2328     QTreeWidgetItem* item = myItem;
2329     myItem = 0;
2330     int nb = myToComputeSize ? myGroup->Size() : myGroup->GetNumberOfNodes();
2331     item->treeWidget()->removeItemWidget( item, 1 );
2332     item->setText( 1, QString::number( nb ));
2333   }
2334 }
2335
2336 /*!
2337   \class SMESHGUI_AddInfo
2338   \brief The wigdet shows additional information on the mesh object.
2339 */
2340
2341 /*!
2342   \brief Constructor
2343   \param parent parent widget
2344 */
2345 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2346 : QTreeWidget( parent )
2347 {
2348   setColumnCount( 2 );
2349   header()->setStretchLastSection( true );
2350 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
2351   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2352 #else
2353   header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2354 #endif
2355   header()->hide();
2356 }
2357
2358 /*!
2359   \brief Destructor
2360 */
2361 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2362 {
2363 }
2364
2365 /*!
2366   \brief Show additional information on the selected object
2367   \param obj object being processed (mesh, sub-mesh, group, ID source)
2368 */
2369 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2370 {
2371   setProperty( "group_index", 0 );
2372   setProperty( "submesh_index",  0 );
2373   myComputors.clear();
2374   clear();
2375
2376   if ( CORBA::is_nil( obj ) ) return;
2377
2378   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2379   if ( !sobj ) return;
2380
2381   // name
2382   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2383   nameItem->setText( 0, tr( "NAME" ) );
2384   nameItem->setText( 1, sobj->GetName().c_str() );
2385   
2386   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2387   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2388   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2389   
2390   if ( !aMesh->_is_nil() )
2391     meshInfo( aMesh, nameItem );
2392   else if ( !aSubMesh->_is_nil() )
2393     subMeshInfo( aSubMesh, nameItem );
2394   else if ( !aGroup->_is_nil() )
2395     groupInfo( aGroup.in(), nameItem );
2396 }
2397
2398 /*!
2399   \brief Create new tree item.
2400   \param parent parent tree widget item
2401   \param flags item flag
2402   \return new tree widget item
2403 */
2404 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2405 {
2406   QTreeWidgetItem* item;
2407
2408   if ( parent )
2409     item = new QTreeWidgetItem( parent );
2410   else
2411     item = new QTreeWidgetItem( this );
2412
2413   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2414
2415   QFont f = item->font( 0 );
2416   f.setBold( true );
2417   for ( int i = 0; i < columnCount(); i++ ) {
2418     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2419       item->setFont( i, f );
2420   }
2421
2422   item->setExpanded( true );
2423   return item;
2424 }
2425
2426 /*!
2427   \brief Show mesh info
2428   \param mesh mesh object
2429   \param parent parent tree item
2430 */
2431 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2432 {
2433   // type
2434   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2435   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2436   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2437   typeItem->setText( 0, tr( "TYPE" ) );
2438   if ( !CORBA::is_nil( shape ) ) {
2439     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2440     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2441     if ( sobj ) {
2442       QTreeWidgetItem* gobjItem = createItem( typeItem );
2443       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2444       gobjItem->setText( 1, sobj->GetName().c_str() );
2445     }
2446   }
2447   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2448     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2449     QTreeWidgetItem* fileItem = createItem( typeItem );
2450     fileItem->setText( 0, tr( "FILE_NAME" ) );
2451     fileItem->setText( 1, (char*)inf->fileName );
2452   }
2453   else {
2454     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2455   }
2456   
2457   // groups
2458   myGroups = mesh->GetGroups();
2459   showGroups();
2460
2461   // sub-meshes
2462   mySubMeshes = mesh->GetSubMeshes();
2463   showSubMeshes();
2464 }
2465
2466 /*!
2467   \brief Show sub-mesh info
2468   \param subMesh sub-mesh object
2469   \param parent parent tree item
2470 */
2471 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2472 {
2473   bool isShort = parent->parent() != 0;
2474
2475   if ( !isShort ) {
2476     // parent mesh
2477     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2478     if ( sobj ) {
2479       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2480       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2481       nameItem->setText( 1, sobj->GetName().c_str() );
2482     }
2483   }
2484   
2485   // shape
2486   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2487   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2488   if ( sobj ) {
2489     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2490     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2491     gobjItem->setText( 1, sobj->GetName().c_str() );
2492   }
2493 }
2494
2495 /*!
2496   \brief Show group info
2497   \param grp mesh group object
2498   \param parent parent tree item
2499 */
2500 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2501 {
2502   bool isShort = parent->parent() != 0;
2503
2504   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2505   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2506   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2507
2508   if ( !isShort ) {
2509     // parent mesh
2510     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2511     if ( sobj ) {
2512       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2513       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2514       nameItem->setText( 1, sobj->GetName().c_str() );
2515     }
2516   }
2517
2518   // type : group on geometry, standalone group, group on filter
2519   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2520   typeItem->setText( 0, tr( "TYPE" ) );
2521   if ( !CORBA::is_nil( aStdGroup ) ) {
2522     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2523   }
2524   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2525     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2526     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2527     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2528     if ( sobj ) {
2529       QTreeWidgetItem* gobjItem = createItem( typeItem );
2530       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2531       gobjItem->setText( 1, sobj->GetName().c_str() );
2532     }
2533   }
2534   else if ( !CORBA::is_nil( aFltGroup ) ) {
2535     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2536   }
2537
2538   if ( !isShort ) {
2539     // entity type
2540     QString etype = tr( "UNKNOWN" );
2541     switch( grp->GetType() ) {
2542     case SMESH::NODE:
2543       etype = tr( "NODE" );
2544       break;
2545     case SMESH::EDGE:
2546       etype = tr( "EDGE" );
2547       break;
2548     case SMESH::FACE:
2549       etype = tr( "FACE" );
2550       break;
2551     case SMESH::VOLUME:
2552       etype = tr( "VOLUME" );
2553       break;
2554     case SMESH::ELEM0D:
2555       etype = tr( "0DELEM" );
2556       break;
2557     case SMESH::BALL:
2558       etype = tr( "BALL" );
2559       break;
2560     default:
2561       break;
2562     }
2563     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2564     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2565     etypeItem->setText( 1, etype );
2566   }
2567
2568   SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2569   bool            meshLoaded = mesh->IsLoaded();
2570
2571   // size. Don't call grp->Size() for GroupOnFilter - issue IPAL52831
2572   int groupSize = -1;
2573   if ( grp->IsNodeInfoAvailable() || CORBA::is_nil( aFltGroup ))
2574     groupSize = grp->Size();
2575
2576   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2577   sizeItem->setText( 0, tr( "SIZE" ) );
2578   if ( groupSize > -1 ) {
2579     sizeItem->setText( 1, QString::number( groupSize ) );
2580   }
2581   else {
2582     QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2583     setItemWidget( sizeItem, 1, btn );
2584     GrpComputor* comp = new GrpComputor( grp, sizeItem, this, /*size=*/true );
2585     connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2586     myComputors.append( comp );
2587     if ( !meshLoaded )
2588       connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2589   }
2590
2591   // color
2592   SALOMEDS::Color color = grp->GetColor();
2593   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2594   colorItem->setText( 0, tr( "COLOR" ) );
2595   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2596
2597   // nb of underlying nodes
2598   if ( grp->GetType() != SMESH::NODE) {
2599     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2600     nodesItem->setText( 0, tr( "NB_NODES" ) );
2601     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2602     bool toShowNodes = groupSize >= 0 ? ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || groupSize <= nbNodesLimit ) : false;
2603     if ( toShowNodes && meshLoaded ) {
2604       // already calculated and up-to-date
2605       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2606     }
2607     else {
2608       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2609       setItemWidget( nodesItem, 1, btn );
2610       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2611       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2612       myComputors.append( comp );
2613       if ( !meshLoaded )
2614         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2615     }
2616   }
2617 }
2618
2619 void SMESHGUI_AddInfo::showGroups()
2620 {
2621   myComputors.clear();
2622
2623   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2624   if ( !parent ) return;
2625
2626   int idx = property( "group_index" ).toInt();
2627
2628   QTreeWidgetItem* itemGroups = 0;
2629   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2630     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2631       itemGroups = parent->child( i );
2632       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2633       if ( extra )
2634         extra->updateControls( myGroups->length(), idx );
2635       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2636     }
2637   }
2638
2639   QMap<int, QTreeWidgetItem*> grpItems;
2640   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2641     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2642     if ( CORBA::is_nil( grp ) ) continue;
2643     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2644     if ( !grpSObj ) continue;
2645
2646     int grpType = grp->GetType();
2647
2648     if ( !itemGroups ) {
2649       // create top-level groups container item
2650       itemGroups = createItem( parent, Bold | All );
2651       itemGroups->setText( 0, tr( "GROUPS" ) );
2652       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2653
2654       // total number of groups > 10, show extra widgets for info browsing
2655       if ((int) myGroups->length() > MAXITEMS ) {
2656         ExtraWidget* extra = new ExtraWidget( this, true );
2657         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2658         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2659         setItemWidget( itemGroups, 1, extra );
2660         extra->updateControls( myGroups->length(), idx );
2661       }
2662     }
2663
2664     if ( grpItems.find( grpType ) == grpItems.end() ) {
2665       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2666       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2667       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2668     }
2669   
2670     // group name
2671     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2672     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2673
2674     // group info
2675     groupInfo( grp.in(), grpNameItem );
2676   }
2677 }
2678
2679 void SMESHGUI_AddInfo::showSubMeshes()
2680 {
2681   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2682   if ( !parent ) return;
2683
2684   int idx = property( "submesh_index" ).toInt();
2685
2686   QTreeWidgetItem* itemSubMeshes = 0;
2687   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2688     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2689       itemSubMeshes = parent->child( i );
2690       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2691       if ( extra )
2692         extra->updateControls( mySubMeshes->length(), idx );
2693       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2694     }
2695   }
2696
2697   QMap<int, QTreeWidgetItem*> smItems;
2698   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2699     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2700     if ( CORBA::is_nil( sm ) ) continue;
2701     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2702     if ( !smSObj ) continue;
2703     
2704     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2705     if ( CORBA::is_nil(gobj ) ) continue;
2706     
2707     int smType = gobj->GetShapeType();
2708     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2709
2710     if ( !itemSubMeshes ) {
2711       itemSubMeshes = createItem( parent, Bold | All );
2712       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2713       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2714
2715       // total number of sub-meshes > 10, show extra widgets for info browsing
2716       if ((int) mySubMeshes->length() > MAXITEMS ) {
2717         ExtraWidget* extra = new ExtraWidget( this, true );
2718         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2719         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2720         setItemWidget( itemSubMeshes, 1, extra );
2721         extra->updateControls( mySubMeshes->length(), idx );
2722       }
2723     }
2724          
2725     if ( smItems.find( smType ) == smItems.end() ) {
2726       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2727       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2728       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2729     }
2730     
2731     // submesh name
2732     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2733     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2734     
2735     // submesh info
2736     subMeshInfo( sm.in(), smNameItem );
2737   }
2738 }
2739
2740 /*!
2741  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2742  */
2743 void SMESHGUI_AddInfo::changeLoadToCompute()
2744 {
2745   for ( int i = 0; i < myComputors.count(); ++i )
2746   {
2747     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2748     {
2749       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2750         btn->setText( tr("COMPUTE") );
2751     }
2752   }
2753 }
2754
2755 void SMESHGUI_AddInfo::showPreviousGroups()
2756 {
2757   int idx = property( "group_index" ).toInt();
2758   setProperty( "group_index", idx-1 );
2759   showGroups();
2760 }
2761
2762 void SMESHGUI_AddInfo::showNextGroups()
2763 {
2764   int idx = property( "group_index" ).toInt();
2765   setProperty( "group_index", idx+1 );
2766   showGroups();
2767 }
2768
2769 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2770 {
2771   int idx = property( "submesh_index" ).toInt();
2772   setProperty( "submesh_index", idx-1 );
2773   showSubMeshes();
2774 }
2775
2776 void SMESHGUI_AddInfo::showNextSubMeshes()
2777 {
2778   int idx = property( "submesh_index" ).toInt();
2779   setProperty( "submesh_index", idx+1 );
2780   showSubMeshes();
2781 }
2782
2783 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2784 {
2785   out << QString( 15, '-')       << "\n";
2786   out << tr( "ADDITIONAL_INFO" ) << "\n";
2787   out << QString( 15, '-' )      << "\n";
2788   QTreeWidgetItemIterator it( this );
2789   while ( *it ) {
2790     if ( !( ( *it )->text(0) ).isEmpty() ) {
2791       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2792       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2793         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2794       }
2795       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2796       out << "\n";
2797     }
2798     ++it;
2799   }
2800   out << "\n";
2801 }
2802
2803 /*!
2804   \class SMESHGUI_MeshInfoDlg
2805   \brief Mesh information dialog box
2806 */
2807
2808 /*!
2809   \brief Constructor
2810   \param parent parent widget
2811   \param page specifies the dialog page to be shown at the start-up
2812 */
2813 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2814 : QDialog( parent ), myActor( 0 )
2815 {
2816   setModal( false );
2817   setAttribute( Qt::WA_DeleteOnClose, true );
2818   setWindowTitle( tr( "MESH_INFO" ) );
2819   setSizeGripEnabled( true );
2820
2821   myTabWidget = new QTabWidget( this );
2822
2823   // base info 
2824
2825   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2826   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2827
2828   // elem info 
2829   
2830   QWidget* w = new QWidget( myTabWidget );
2831
2832   myMode = new QButtonGroup( this );
2833   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2834   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2835   myMode->button( NodeMode )->setChecked( true );
2836   myID = new QLineEdit( w );
2837   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2838
2839   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2840   mode = qMin( 1, qMax( 0, mode ) );
2841   
2842   if ( mode == 0 ) 
2843     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2844   else
2845     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2846
2847   QGridLayout* elemLayout = new QGridLayout( w );
2848   elemLayout->setMargin( MARGIN );
2849   elemLayout->setSpacing( SPACING );
2850   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2851   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2852   elemLayout->addWidget( myID, 0, 2 );
2853   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2854   
2855   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2856
2857   // additional info
2858
2859   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2860   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2861
2862   // controls info
2863
2864   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
2865   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
2866
2867   // buttons
2868
2869   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2870   okBtn->setAutoDefault( true );
2871   okBtn->setDefault( true );
2872   okBtn->setFocus();
2873   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2874   dumpBtn->setAutoDefault( true );
2875   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2876   helpBtn->setAutoDefault( true );
2877
2878   QHBoxLayout* btnLayout = new QHBoxLayout;
2879   btnLayout->setSpacing( SPACING );
2880   btnLayout->setMargin( 0 );
2881
2882   btnLayout->addWidget( okBtn );
2883   btnLayout->addWidget( dumpBtn );
2884   btnLayout->addStretch( 10 );
2885   btnLayout->addWidget( helpBtn );
2886
2887   QVBoxLayout* l = new QVBoxLayout ( this );
2888   l->setMargin( MARGIN );
2889   l->setSpacing( SPACING );
2890   l->addWidget( myTabWidget );
2891   l->addLayout( btnLayout );
2892
2893   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2894
2895   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2896   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2897   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2898   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2899   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2900   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2901   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2902   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2903   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2904   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2905
2906   updateSelection();
2907 }
2908
2909 /*!
2910   \brief Destructor
2911 */
2912 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2913 {
2914 }
2915
2916 /*!
2917   \brief Show mesh information
2918   \param IO interactive object
2919 */
2920 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2921 {
2922   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2923   if ( !CORBA::is_nil( obj ) ) {
2924     myAddInfo->showInfo( obj );  // nb of nodes in a group can be computed by myAddInfo,
2925     myBaseInfo->showInfo( obj ); // and it will be used by myBaseInfo (IPAL52871)
2926     myCtrlInfo->showInfo( obj );
2927
2928     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2929     SVTK_Selector* selector = SMESH::GetSelector();
2930     QString ID;
2931     int nb = 0;
2932     if ( myActor && selector ) {
2933       nb = myMode->checkedId() == NodeMode ? 
2934         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2935         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2936     }
2937     myElemInfo->setSource( myActor ) ;
2938     if ( nb > 0 ) {
2939       myID->setText( ID.trimmed() );
2940       QSet<long> ids;
2941       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2942       foreach ( ID, idTxt )
2943         ids << ID.trimmed().toLong();
2944       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2945     }
2946     else {
2947       myID->clear();
2948       myElemInfo->clear();
2949     }
2950   }
2951 }
2952
2953 /*!
2954   \brief Perform clean-up actions on the dialog box closing.
2955 */
2956 void SMESHGUI_MeshInfoDlg::reject()
2957 {
2958   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2959   selMgr->clearFilters();
2960   SMESH::SetPointRepresentation( false );
2961   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2962     aViewWindow->SetSelectionMode( ActorSelection );
2963   QDialog::reject();
2964 }
2965
2966 /*!
2967   \brief Process keyboard event
2968   \param e key press event
2969 */
2970 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2971 {
2972   QDialog::keyPressEvent( e );
2973   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2974     e->accept();
2975     help();
2976   }
2977 }
2978
2979 /*!
2980   \brief Reactivate dialog box, when mouse pointer goes into it.
2981 */
2982 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2983 {
2984   //activate();
2985 }
2986
2987 /*!
2988   \brief Setup selection mode depending on the current dialog box state.
2989 */
2990 void SMESHGUI_MeshInfoDlg::updateSelection()
2991 {
2992   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2993
2994   disconnect( selMgr, 0, this, 0 );
2995   selMgr->clearFilters();
2996
2997   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo || myTabWidget->currentIndex() == CtrlInfo ) {
2998     SMESH::SetPointRepresentation( false );
2999     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3000       aViewWindow->SetSelectionMode( ActorSelection );
3001   }
3002   else {
3003     if ( myMode->checkedId() == NodeMode ) {
3004       SMESH::SetPointRepresentation( true );
3005       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3006         aViewWindow->SetSelectionMode( NodeSelection );
3007     }
3008     else {
3009       SMESH::SetPointRepresentation( false );
3010       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3011         aViewWindow->SetSelectionMode( CellSelection );
3012     }
3013   }
3014
3015   QString oldID = myID->text().trimmed();
3016   SMESH_Actor* oldActor = myActor;
3017   myID->clear();
3018   
3019   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3020   updateInfo();
3021   
3022   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
3023     myID->setText( oldID );
3024     idChanged();
3025   }
3026 }
3027
3028 /*!
3029   \brief Show help page
3030 */
3031 void SMESHGUI_MeshInfoDlg::help()
3032 {
3033   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
3034                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
3035                        "mesh_infos_page.html#mesh_element_info_anchor" );
3036 }
3037
3038 /*!
3039   \brief Show mesh information
3040 */
3041 void SMESHGUI_MeshInfoDlg::updateInfo()
3042 {
3043   SUIT_OverrideCursor wc;
3044
3045   SALOME_ListIO selected;
3046   SMESHGUI::selectionMgr()->selectedObjects( selected );
3047
3048   if ( selected.Extent() == 1 ) {
3049     Handle(SALOME_InteractiveObject) IO = selected.First();
3050     showInfo( IO );
3051   }
3052 //   else {
3053 //     myBaseInfo->clear();
3054 //     myElemInfo->clear();
3055 //     myAddInfo->clear();
3056 //   }
3057 }
3058
3059 /*!
3060   \brief Activate dialog box
3061 */
3062 void SMESHGUI_MeshInfoDlg::activate()
3063 {
3064   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3065   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3066   myTabWidget->setEnabled( true );
3067   updateSelection();
3068 }
3069
3070 /*!
3071   \brief Deactivate dialog box
3072 */
3073 void SMESHGUI_MeshInfoDlg::deactivate()
3074 {
3075   myTabWidget->setEnabled( false );
3076   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3077 }
3078
3079 /*!
3080   \brief Called when users switches between node / element modes.
3081 */
3082 void SMESHGUI_MeshInfoDlg::modeChanged()
3083 {
3084   myID->clear();
3085   updateSelection();
3086 }
3087
3088 /*!
3089   \brief Caled when users prints mesh element ID in the corresponding field.
3090 */
3091 void SMESHGUI_MeshInfoDlg::idChanged()
3092 {
3093   SVTK_Selector* selector = SMESH::GetSelector();
3094   if ( myActor && selector ) {
3095     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
3096     TColStd_MapOfInteger ID;
3097     QSet<long> ids;
3098     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3099     foreach ( QString tid, idTxt ) {
3100       long id = tid.trimmed().toLong();
3101       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
3102         myActor->GetObject()->GetMesh()->FindElement( id ) :
3103         myActor->GetObject()->GetMesh()->FindNode( id );
3104       if ( e ) {
3105         ID.Add( id );
3106         ids << id;
3107       }
3108     }
3109     selector->AddOrRemoveIndex( IO, ID, false );
3110     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
3111       aViewWindow->highlight( IO, true, true );
3112       aViewWindow->Repaint();
3113     }
3114     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
3115   }
3116 }
3117
3118 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
3119 {
3120   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
3121     myMode->button( NodeMode )->click();
3122     myID->setText( QString::number( id ) );
3123   }
3124 }
3125
3126 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
3127 {
3128   if ( !theStr.isEmpty() ) {
3129     myMode->button( ElemMode )->click();
3130     myID->setText( theStr );
3131   }
3132 }
3133
3134 void SMESHGUI_MeshInfoDlg::dump()
3135 {
3136   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3137   if ( !app ) return;
3138   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3139   if ( !appStudy ) return;
3140   _PTR( Study ) aStudy = appStudy->studyDS();
3141
3142   QStringList aFilters;
3143   aFilters.append( tr( "TEXT_FILES" ) );
3144
3145   bool anIsBase = true;
3146   bool anIsElem = true;
3147   bool anIsAdd  = true;
3148   bool anIsCtrl = true;
3149
3150   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
3151     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
3152     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
3153     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
3154     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
3155   }
3156
3157   DumpFileDlg fd( this );
3158   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3159   fd.setNameFilters( aFilters );
3160   fd.myBaseChk->setChecked( anIsBase );
3161   fd.myElemChk->setChecked( anIsElem );
3162   fd.myAddChk ->setChecked( anIsAdd );
3163   fd.myCtrlChk->setChecked( anIsCtrl );
3164   if ( fd.exec() == QDialog::Accepted )
3165   {
3166     QString aFileName = fd.selectedFile();
3167
3168     bool toBase = fd.myBaseChk->isChecked();
3169     bool toElem = fd.myElemChk->isChecked();
3170     bool toAdd  = fd.myAddChk->isChecked();
3171     bool toCtrl = fd.myCtrlChk->isChecked();
3172
3173     if ( !aFileName.isEmpty() ) {
3174       QFileInfo aFileInfo( aFileName );
3175       if ( aFileInfo.isDir() )
3176         return;
3177  
3178       QFile aFile( aFileName );
3179       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3180         return;
3181       
3182       QTextStream out( &aFile );
3183       
3184       if ( toBase ) myBaseInfo->saveInfo( out );
3185       if ( toElem ) myElemInfo->saveInfo( out );
3186       if ( toAdd )  myAddInfo ->saveInfo( out );
3187       if ( toCtrl ) myCtrlInfo->saveInfo( out );
3188     }
3189   }
3190 }
3191
3192 /*!
3193   \class SMESHGUI_CtrlInfo
3194   \brief Class for the mesh controls information widget.
3195 */
3196
3197 /*!
3198   \brief Constructor
3199   \param parent parent widget
3200 */
3201 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
3202   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
3203 {
3204   setFrameStyle( StyledPanel | Sunken );
3205
3206   myMainLayout = new QGridLayout( this );
3207   myMainLayout->setMargin( MARGIN );
3208   myMainLayout->setSpacing( SPACING );
3209
3210   // name
3211   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
3212   QLabel* aName = createField();
3213   aName->setMinimumWidth( 150 );
3214   myWidgets << aName;
3215
3216   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3217   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3218
3219   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3220
3221   // nodes info
3222   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3223   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3224   QLabel* aNodesFree = createField();
3225   myWidgets << aNodesFree;
3226   myPredicates << aFilterMgr->CreateFreeNodes();
3227   //
3228   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3229   QLabel* aNodesDouble = createField();
3230   myWidgets << aNodesDouble;
3231   myPredicates << aFilterMgr->CreateEqualNodes();
3232   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3233   myToleranceWidget = new SMESHGUI_SpinBox( this );
3234   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3235   myToleranceWidget->setAcceptNames( false );
3236   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3237
3238   // edges info
3239   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3240   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3241   QLabel* anEdgesDouble = createField();
3242   myWidgets << anEdgesDouble;
3243   myPredicates << aFilterMgr->CreateEqualEdges();
3244
3245   // faces info
3246   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3247   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3248   QLabel* aFacesDouble = createField();
3249   myWidgets << aFacesDouble;
3250   myPredicates << aFilterMgr->CreateEqualFaces();
3251   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3252   QLabel* aFacesOver = createField();
3253   myWidgets << aFacesOver;
3254   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3255   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3256   myPlot = createPlot( this );
3257   myAspectRatio = aFilterMgr->CreateAspectRatio();
3258  
3259   // volumes info
3260   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3261   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3262   QLabel* aVolumesDouble = createField();
3263   myWidgets << aVolumesDouble;
3264   myPredicates << aFilterMgr->CreateEqualVolumes();
3265   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3266   QLabel* aVolumesOver = createField();
3267   myWidgets << aVolumesOver;
3268   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3269   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3270   myPlot3D = createPlot( this );
3271   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3272
3273   QToolButton* aFreeNodesBtn = new QToolButton( this );
3274   aFreeNodesBtn->setIcon(aComputeIcon);
3275   myButtons << aFreeNodesBtn;       //0
3276
3277   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3278   aDoubleNodesBtn->setIcon(aComputeIcon);
3279   myButtons << aDoubleNodesBtn;     //1
3280
3281   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3282   aDoubleEdgesBtn->setIcon(aComputeIcon);
3283   myButtons << aDoubleEdgesBtn;     //2
3284
3285   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3286   aDoubleFacesBtn->setIcon(aComputeIcon);
3287   myButtons << aDoubleFacesBtn;     //3
3288
3289   QToolButton* aOverContFacesBtn = new QToolButton( this );
3290   aOverContFacesBtn->setIcon(aComputeIcon);
3291   myButtons << aOverContFacesBtn;   //4
3292
3293   QToolButton* aComputeFaceBtn = new QToolButton( this );
3294   aComputeFaceBtn->setIcon(aComputeIcon);
3295   myButtons << aComputeFaceBtn;     //5
3296
3297   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3298   aDoubleVolumesBtn->setIcon(aComputeIcon);
3299   myButtons << aDoubleVolumesBtn;   //6
3300
3301   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3302   aOverContVolumesBtn->setIcon(aComputeIcon);
3303   myButtons << aOverContVolumesBtn; //7
3304
3305   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3306   aComputeVolumeBtn->setIcon(aComputeIcon);
3307   myButtons << aComputeVolumeBtn;   //8
3308
3309   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3310   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3311   connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3312   connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3313   connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3314   connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3315   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3316   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3317   connect( aOverContVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3318   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3319
3320   setFontAttributes( aNameLab );
3321   setFontAttributes( aNodesLab );
3322   setFontAttributes( anEdgesLab );
3323   setFontAttributes( aFacesLab );
3324   setFontAttributes( aVolumesLab );
3325
3326   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3327   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3328   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3329   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3330   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3331   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3332   myMainLayout->addWidget( aNodesDoubleLab,    3, 0 );       //6
3333   myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
3334   myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
3335   myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
3336   myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
3337   myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
3338   myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
3339   myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
3340   myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
3341   myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
3342   myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
3343   myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
3344   myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
3345   myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
3346   myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
3347   myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
3348   myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
3349   myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
3350   myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
3351   myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
3352   myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
3353   myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
3354   myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
3355   myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
3356   myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
3357   myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
3358   myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
3359   myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
3360   myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
3361  
3362   myMainLayout->setColumnStretch(  0,  0 );
3363   myMainLayout->setColumnStretch(  1,  5 );
3364   myMainLayout->setRowStretch   ( 11,  5 );
3365   myMainLayout->setRowStretch   ( 16,  5 );
3366   myMainLayout->setRowStretch   ( 17,  1 );
3367
3368   clearInternal();
3369 }
3370
3371 /*!
3372   \brief Destructor
3373 */
3374 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3375 {}
3376
3377 /*!
3378   \brief Change widget font attributes (bold, ...).
3379   \param w widget
3380   \param attr font attributes (XORed flags)
3381 */
3382 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3383 {
3384   if ( w ) {
3385     QFont f = w->font();
3386     f.setBold( true );
3387     w->setFont( f );
3388   }
3389 }
3390
3391 /*!
3392   \brief Create info field
3393   \return new info field
3394 */
3395 QLabel* SMESHGUI_CtrlInfo::createField()
3396 {
3397   QLabel* lab = new QLabel( this );
3398   lab->setFrameStyle( StyledPanel | Sunken );
3399   lab->setAlignment( Qt::AlignCenter );
3400   lab->setAutoFillBackground( true );
3401   QPalette pal = lab->palette();
3402   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
3403   lab->setPalette( pal );
3404   lab->setMinimumWidth( 60 );
3405   return lab;
3406 }
3407
3408 /*!
3409   \brief Create QwtPlot
3410   \return new QwtPlot
3411 */
3412 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3413 {
3414   QwtPlot* aPlot = new QwtPlot( parent );
3415   aPlot->setMinimumSize( 100, 100 );
3416   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3417   xFont.setPointSize( 5 );
3418   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3419   yFont.setPointSize( 5 );
3420   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3421   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3422   aPlot->replot();
3423   return aPlot;
3424 }
3425
3426 /*!
3427   \brief Show controls information on the selected object
3428 */
3429 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3430 {
3431   clearInternal();
3432
3433   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3434   if ( myObject->_is_nil() ) return;
3435
3436   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3437     myWidgets[0]->setText( aSO->GetName().c_str() );
3438
3439   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3440   if ( mesh->_is_nil() ) return;
3441
3442   const bool meshLoaded = mesh->IsLoaded();
3443   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3444     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3445     for ( int i = 0; i < myButtons.count(); ++i )
3446       myButtons[i]->setEnabled( true );
3447
3448   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3449   if ( ! &nbElemsByType.in() ) return;
3450
3451   const CORBA::Long ctrlLimit =
3452     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3453
3454   // nodes info
3455   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3456   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3457                                 nbElemsByType[ SMESH::FACE ] +
3458                                 nbElemsByType[ SMESH::VOLUME ] );
3459   if ( nbNodes + nbElems > 0 ) {
3460     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3461       // free nodes
3462       computeFreeNodesInfo();
3463       // double nodes
3464       if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
3465         computeDoubleNodesInfo();
3466     }
3467     else {
3468       myButtons[0]->setEnabled( true );
3469       myButtons[1]->setEnabled( true );
3470     }
3471   }
3472   else {
3473     for( int i=2; i<=10; i++)
3474       myMainLayout->itemAt(i)->widget()->setVisible( false );
3475   }
3476
3477   // edges info
3478   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3479     // double edges
3480     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3481       computeDoubleEdgesInfo();
3482     else
3483       myButtons[2]->setEnabled( true );
3484   }
3485   else {
3486     for( int i=11; i<=14; i++)
3487       myMainLayout->itemAt(i)->widget()->setVisible( false );
3488   }
3489  
3490   // faces info
3491   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3492     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3493       // double faces
3494       computeDoubleFacesInfo();
3495       // over constrained faces
3496       computeOverConstrainedFacesInfo();
3497       // aspect Ratio histogram
3498       computeAspectRatio();
3499     }
3500     else {
3501       myButtons[3]->setEnabled( true );
3502       myButtons[4]->setEnabled( true );
3503       myButtons[5]->setEnabled( true );
3504     }
3505 #ifdef DISABLE_PLOT2DVIEWER
3506     myMainLayout->setRowStretch(11,0);
3507     for( int i=22; i<=24; i++)
3508       myMainLayout->itemAt(i)->widget()->setVisible( false );
3509 #endif
3510   }
3511   else {
3512     myMainLayout->setRowStretch(11,0);
3513     for( int i=15; i<=24; i++)
3514       myMainLayout->itemAt(i)->widget()->setVisible( false );
3515   }
3516
3517   // volumes info
3518   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3519     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3520       // double volumes
3521       computeDoubleVolumesInfo();
3522       // over constrained volumes
3523       computeOverConstrainedVolumesInfo();
3524       // aspect Ratio 3D histogram
3525       computeAspectRatio3D();
3526      }
3527      else {
3528        myButtons[6]->setEnabled( true );
3529        myButtons[7]->setEnabled( true );
3530        myButtons[8]->setEnabled( true );
3531      }
3532 #ifdef DISABLE_PLOT2DVIEWER
3533     myMainLayout->setRowStretch(16,0);
3534     for( int i=32; i<=34; i++)
3535       myMainLayout->itemAt(i)->widget()->setVisible( false );
3536 #endif
3537   }
3538   else {
3539     myMainLayout->setRowStretch(16,0);
3540     for( int i=25; i<=34; i++)
3541       myMainLayout->itemAt(i)->widget()->setVisible( false );
3542   }
3543 }
3544
3545 //================================================================================
3546 /*!
3547  * \brief Computes and shows nb of elements satisfying a given predicate
3548  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3549  *  \param [in] iBut - index of one of myButtons to disable
3550  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3551  */
3552 //================================================================================
3553
3554 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3555 {
3556   myButtons[ iBut ]->setEnabled( false );
3557   myWidgets[ iWdg ]->setText( "" );
3558   if ( myObject->_is_nil() ) return;
3559
3560   SUIT_OverrideCursor wc;
3561
3562   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3563   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3564   {
3565     mesh->Load();
3566     this->showInfo( myObject ); // try to show all values
3567     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3568       return; // <ft> predicate already computed
3569   }
3570   // look for a predicate of type <ft>
3571   for ( int i = 0; i < myPredicates.count(); ++i )
3572     if ( myPredicates[i]->GetFunctorType() == ft )
3573     {
3574       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3575       myWidgets[ iWdg ]->setText( QString::number( nb ));
3576     }
3577 }
3578
3579 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3580 {
3581   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3582 }
3583
3584 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3585 {
3586   computeNb( SMESH::FT_EqualNodes, 1, 2 );
3587 }
3588
3589 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3590 {
3591   computeNb( SMESH::FT_EqualEdges, 2, 3 );
3592 }
3593
3594 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3595 {
3596   computeNb( SMESH::FT_EqualFaces, 3, 4 );
3597 }
3598
3599 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3600 {
3601   computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
3602 }
3603
3604 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3605 {
3606   computeNb( SMESH::FT_EqualVolumes, 6, 6 );
3607 }
3608
3609 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3610 {
3611   computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
3612 }
3613
3614 void SMESHGUI_CtrlInfo::computeAspectRatio()
3615 {
3616 #ifndef DISABLE_PLOT2DVIEWER
3617   myButtons[5]->setEnabled( false );
3618
3619   if ( myObject->_is_nil() ) return;
3620
3621   SUIT_OverrideCursor wc;
3622
3623   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3624   if ( aHistogram && !aHistogram->isEmpty() ) {
3625     QwtPlotItem* anItem = aHistogram->createPlotItem();
3626     anItem->attach( myPlot );
3627     myPlot->replot();
3628   }
3629   delete aHistogram;
3630 #endif
3631 }
3632
3633 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3634 {
3635 #ifndef DISABLE_PLOT2DVIEWER
3636   myButtons[8]->setEnabled( false );
3637
3638   if ( myObject->_is_nil() ) return;
3639
3640   SUIT_OverrideCursor wc;
3641
3642   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3643   if ( aHistogram && !aHistogram->isEmpty() ) {
3644     QwtPlotItem* anItem = aHistogram->createPlotItem();
3645     anItem->attach( myPlot3D );
3646     myPlot3D->replot();
3647   }
3648   delete aHistogram;
3649 #endif
3650 }
3651
3652 /*!
3653   \brief Internal clean-up (reset widget)
3654 */
3655 void SMESHGUI_CtrlInfo::clearInternal()
3656 {
3657   for( int i=0; i<=34; i++)
3658     myMainLayout->itemAt(i)->widget()->setVisible( true );
3659   for( int i=0; i<=8; i++)
3660     myButtons[i]->setEnabled( false );
3661   myPlot->detachItems();
3662   myPlot3D->detachItems();
3663   myPlot->replot();
3664   myPlot3D->replot();
3665   myWidgets[0]->setText( QString() );
3666   for ( int i = 1; i < myWidgets.count(); i++ )
3667     myWidgets[i]->setText( "" );
3668   myMainLayout->setRowStretch(11,5);
3669   myMainLayout->setRowStretch(16,5);
3670 }
3671
3672 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3673 {
3674   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3675   myButtons[1]->setEnabled( true );
3676   myWidgets[2]->setText("");
3677 }
3678
3679 #ifndef DISABLE_PLOT2DVIEWER
3680 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3681 {
3682   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3683   if ( mesh->_is_nil() ) return 0;
3684   if ( !mesh->IsLoaded() )
3685     mesh->Load();
3686   aNumFun->SetMesh( mesh );
3687
3688   CORBA::Long cprecision = 6;
3689   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
3690     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3691   aNumFun->SetPrecision( cprecision );
3692
3693   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3694
3695   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3696                                                                   /*isLogarithmic=*/false,
3697                                                                   myObject );
3698   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3699   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3700   if ( &histogramVar.in() )
3701   {
3702     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3703       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3704     if ( histogramVar->length() >= 2 )
3705       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3706   }
3707   return aHistogram;
3708 }
3709 #endif
3710
3711 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3712   out << QString( 20, '-' ) << "\n";
3713   out << tr( "CTRL_INFO"  ) << "\n";
3714   out << QString( 20, '-' ) << "\n";
3715   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3716   out <<                                 tr( "NODES_INFO" )                     << "\n";
3717   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3718   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3719   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3720   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3721   out <<                                 tr( "FACES_INFO" )                     << "\n";
3722   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3723   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3724   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3725   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3726   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3727 }
3728
3729 /*!
3730   \class SMESHGUI_CtrlInfoDlg
3731   \brief Controls information dialog box
3732 */
3733
3734 /*!
3735   \brief Constructor
3736   \param parent parent widget
3737   \param page specifies the dialog page to be shown at the start-up
3738 */
3739 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3740 : QDialog( parent )
3741 {
3742   setAttribute( Qt::WA_DeleteOnClose, true );
3743   setWindowTitle( tr( "CTRL_INFO" ) );
3744   setMinimumSize( 400, 600 );
3745
3746   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3747   
3748   // buttons
3749   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3750   okBtn->setAutoDefault( true );
3751   okBtn->setDefault( true );
3752   okBtn->setFocus();
3753   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3754   dumpBtn->setAutoDefault( true );
3755   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3756   helpBtn->setAutoDefault( true );
3757
3758   QHBoxLayout* btnLayout = new QHBoxLayout;
3759   btnLayout->setSpacing( SPACING );
3760   btnLayout->setMargin( 0 );
3761
3762   btnLayout->addWidget( okBtn );
3763   btnLayout->addWidget( dumpBtn );
3764   btnLayout->addStretch( 10 );
3765   btnLayout->addWidget( helpBtn );
3766
3767   QVBoxLayout* l = new QVBoxLayout ( this );
3768   l->setMargin( MARGIN );
3769   l->setSpacing( SPACING );
3770   l->addWidget( myCtrlInfo );
3771   l->addLayout( btnLayout );
3772
3773   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
3774   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3775   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3776   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3777   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
3778
3779   updateSelection();
3780 }
3781
3782 /*!
3783   \brief Destructor
3784 */
3785 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3786 {
3787 }
3788
3789 /*!
3790   \brief Show controls information
3791   \param IO interactive object
3792 */
3793 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3794 {  
3795   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ) )
3796     myCtrlInfo->showInfo( obj );
3797 }
3798
3799 /*!
3800   \brief Perform clean-up actions on the dialog box closing.
3801 */
3802 void SMESHGUI_CtrlInfoDlg::reject()
3803 {
3804   SMESH::SetPointRepresentation( false );
3805   QDialog::reject();
3806 }
3807
3808 /*!
3809   \brief Setup selection mode depending on the current dialog box state.
3810 */
3811 void SMESHGUI_CtrlInfoDlg::updateSelection()
3812 {
3813   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3814   disconnect( selMgr, 0, this, 0 );
3815   SMESH::SetPointRepresentation( false );  
3816   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3817   updateInfo();  
3818 }
3819
3820 /*!
3821   \brief Show mesh information
3822 */
3823 void SMESHGUI_CtrlInfoDlg::updateInfo()
3824 {
3825   SUIT_OverrideCursor wc;
3826
3827   SALOME_ListIO selected;
3828   SMESHGUI::selectionMgr()->selectedObjects( selected );
3829
3830   if ( selected.Extent() == 1 ) {
3831     Handle(SALOME_InteractiveObject) IO = selected.First();
3832     showInfo( IO );
3833   }
3834 }
3835
3836 /*!
3837   \brief Activate dialog box
3838 */
3839 void SMESHGUI_CtrlInfoDlg::activate()
3840 {
3841   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3842   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3843   updateSelection();
3844 }
3845
3846 /*!
3847   \brief Deactivate dialog box
3848 */
3849 void SMESHGUI_CtrlInfoDlg::deactivate()
3850 {
3851   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3852 }
3853
3854 /*!
3855  * \brief Dump contents into a file
3856  */
3857 void SMESHGUI_CtrlInfoDlg::dump()
3858 {
3859   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3860   if ( !app ) return;
3861   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3862   if ( !appStudy ) return;
3863   _PTR( Study ) aStudy = appStudy->studyDS();
3864
3865   QStringList aFilters;
3866   aFilters.append( tr( "TEXT_FILES" ) );
3867
3868   DumpFileDlg fd( this );
3869   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3870   fd.setNameFilters( aFilters );
3871   fd.myBaseChk->hide();
3872   fd.myElemChk->hide();
3873   fd.myAddChk ->hide();
3874   fd.myCtrlChk->hide();
3875   if ( fd.exec() == QDialog::Accepted )
3876   {
3877     QString aFileName = fd.selectedFile();
3878     if ( !aFileName.isEmpty() ) {
3879       QFileInfo aFileInfo( aFileName );
3880       if ( aFileInfo.isDir() )
3881         return;
3882  
3883       QFile aFile( aFileName );
3884       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3885         return;
3886       
3887       QTextStream out( &aFile );
3888       myCtrlInfo->saveInfo( out );
3889     }
3890   }
3891 }
3892
3893 /*!
3894  * \brief Show help
3895  */
3896 void SMESHGUI_CtrlInfoDlg::help()
3897 {
3898   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
3899 }