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