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