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