Salome HOME
IPAL53870: Dump study script creates an excess sub-mesh
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : SMESHGUI_MeshInfo.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24
25 #include "SMESHGUI_MeshInfo.h"
26
27 #include "SMDSAbs_ElementType.hxx"
28 #include "SMDS_BallElement.hxx"
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_Mesh.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMESHDS_Mesh.hxx"
34 #include "SMESHGUI.h"
35 #include "SMESHGUI_FilterUtils.h"
36 #include "SMESHGUI_IdValidator.h"
37 #include "SMESHGUI_SpinBox.h"
38 #include "SMESHGUI_Utils.h"
39 #include "SMESHGUI_VTKUtils.h"
40 #include "SMESH_Actor.h"
41
42 #include <LightApp_SelectionMgr.h>
43 #include <SUIT_FileDlg.h>
44 #include <SUIT_OverrideCursor.h>
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_Session.h>
47 #include <SVTK_ViewWindow.h>
48
49 #include <SALOMEDSClient_Study.hxx>
50 #include <SalomeApp_Study.h>
51
52 #include <QApplication>
53 #include <QButtonGroup>
54 #include <QCheckBox>
55 #include <QContextMenuEvent>
56 #include <QGridLayout>
57 #include <QHBoxLayout>
58 #include <QHeaderView>
59 #include <QItemDelegate>
60 #include <QKeyEvent>
61 #include <QLabel>
62 #include <QLineEdit>
63 #include <QMenu>
64 #include <QPushButton>
65 #include <QToolButton>
66 #include <QRadioButton>
67 #include <QTextStream>
68 #include <QTabWidget>
69 #include <QTextBrowser>
70 #include <QVBoxLayout>
71
72 #include "utilities.h"
73
74 #include <SALOMEconfig.h>
75 #include CORBA_SERVER_HEADER(GEOM_Gen)
76
77 namespace {
78
79 const int SPACING      = 6;
80 const int MARGIN       = 9;
81 const int MAXITEMS     = 10;
82 const int GROUPS_ID    = 100;
83 const int SUBMESHES_ID = 200;
84 const int SPACING_INFO = 2;
85
86 enum InfoRole {
87   TypeRole = Qt::UserRole + 10,
88   IdRole,
89 };
90
91 enum InfoType {
92   NodeConnectivity = 100,
93   ElemConnectivity,
94 };
95 } // namesapce
96
97 /*!
98   \class ExtraWidget
99   \internal
100 */
101 class ExtraWidget : public QWidget
102 {
103 public:
104   ExtraWidget( QWidget*, bool = false );
105   ~ExtraWidget();
106
107   void updateControls( int, int, int = MAXITEMS );
108
109 public:
110   QLabel*      current;
111   QPushButton* prev;
112   QPushButton* next;
113   bool         brief;
114 };
115
116 ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b )
117 {
118   current = new QLabel( this );
119   current->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
120   prev = new QPushButton( tr( "<<" ), this );
121   next = new QPushButton( tr( ">>" ), this );
122   QHBoxLayout* hbl = new QHBoxLayout( this );
123   hbl->setContentsMargins( 0, SPACING, 0, 0 );
124   hbl->setSpacing( SPACING );
125   hbl->addStretch();
126   hbl->addWidget( current );
127   hbl->addWidget( prev );
128   hbl->addWidget( next );
129 }
130
131 ExtraWidget::~ExtraWidget()
132 {
133 }
134
135 void ExtraWidget::updateControls( int total, int index, int blockSize )
136 {
137   setVisible( total > blockSize );
138   QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" );
139   current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total ) ).arg( total ) );
140   prev->setEnabled( index > 0 );
141   next->setEnabled( (index+1)*blockSize < total );
142 }
143
144 /*!
145   \class DumpFileDlg
146   \brief Customization of standard "Save file" dialog box for dump info operation
147   \internal
148 */
149
150 class DumpFileDlg : public SUIT_FileDlg
151 {
152 public:
153   DumpFileDlg( QWidget* parent );
154
155   QCheckBox* myBaseChk;
156   QCheckBox* myElemChk;
157   QCheckBox* myAddChk;
158   QCheckBox* myCtrlChk;
159 };
160
161 /*!
162   \brief Constructor
163   \internal
164 */
165 DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
166 {
167   QGridLayout* grid = ::qobject_cast<QGridLayout *>( layout() );
168   if ( grid ) {
169     QWidget* hB = new QWidget( this );
170     myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
171     myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
172     myAddChk  = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
173     myCtrlChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
174
175     QGridLayout* layout = new QGridLayout( hB );
176     layout->addWidget( myBaseChk, 0, 0 );
177     layout->addWidget( myElemChk, 0, 1 );
178     layout->addWidget( myAddChk, 1, 0 );
179     layout->addWidget( myCtrlChk, 1, 1 );
180
181     QPushButton* pb = new QPushButton( this );
182
183     int row = grid->rowCount();
184     grid->addWidget( new QLabel( "", this ), row, 0 );
185     grid->addWidget( hB, row, 1, 1, 3 );
186     grid->addWidget( pb, row, 5 );
187
188     pb->hide();
189   }
190 }
191
192 /*!
193   \brief Get depth of the tree item
194   \internal
195   \param theItem tree widget item
196   \return item's depth in tree widget (where top-level items have zero depth)
197 */
198 static int itemDepth( QTreeWidgetItem* item )
199 {
200   int d = 0;
201   QTreeWidgetItem* p = item->parent();
202   while ( p ) {
203     d++;
204     p = p->parent();
205   }
206   return d;
207 }
208
209 /*!
210   \class SMESHGUI_MeshInfo
211   \brief Base mesh information widget
212   
213   Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
214 */
215
216 /*!
217   \brief Constructor.
218   \param parent parent widget
219 */
220 SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
221   : QFrame( parent ), myWidgets( iElementsEnd )
222 {
223   setFrameStyle( StyledPanel | Sunken );
224
225   QGridLayout* l = new QGridLayout( this );
226   l->setMargin( MARGIN );
227   l->setSpacing( SPACING );
228
229   int index = 0;
230
231   // object
232   QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
233   QLabel* aName        = createField();
234   aName->setObjectName("meshName");
235   aName->setMinimumWidth( 150 );
236   QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
237   QLabel* aObj         = createField();
238   aObj->setObjectName("meshType");
239   aObj->setMinimumWidth( 150 );
240   myWidgets[ index++ ] << aNameLab << aName;
241   myWidgets[ index++ ] << aObjLab  << aObj;
242
243   // nodes
244   QWidget* aNodesLine  = createLine();
245   QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
246   QLabel*  aNodes      = createField();
247   aNodes->setObjectName("nbNodes");
248   myWidgets[ index++ ] << aNodesLine;
249   myWidgets[ index++ ] << aNodesLab << aNodes;
250
251   // elements
252   QWidget* aElemLine   = createLine();
253   QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),     this );
254   QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),        this );
255   QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),       this );
256   QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ),    this );
257   QLabel*  aElemBiQuad = new QLabel( tr( "BI_QUADRATIC_LAB" ), this );
258   myWidgets[ index++ ] << aElemLine;
259   myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad << aElemBiQuad;
260
261   // ... Number elements
262   QWidget* aNbLine     = createLine(); 
263   QLabel*  aNbTotal    = createField();
264   aNbTotal->setObjectName("totalNbElems");
265   QLabel*  aNbLin      = createField();
266   aNbLin->setObjectName("totalNbLinearElems");
267   QLabel*  aNbQuad     = createField();
268   aNbQuad->setObjectName("totalNbQuadraticElems");
269   QLabel*  aNbBiQuad   = createField();
270   aNbBiQuad->setObjectName("totalNbBiQuadraticElems");
271   myWidgets[ index++ ] << aNbLine;
272   myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad << aNbBiQuad;
273
274   // ... 0D elements
275   QWidget* a0DLine     = createLine();
276   QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
277   QLabel*  a0DTotal    = createField();
278   a0DTotal->setObjectName("nb0D");
279
280   myWidgets[ index++ ] << a0DLine;
281   myWidgets[ index++ ] << a0DLab << a0DTotal;
282
283   // ... Ball elements
284   QWidget* aBallLine     = createLine();
285   QLabel*  aBallLab      = new QLabel( tr( "BALL_LAB" ), this );
286   QLabel*  aBallTotal    = createField();
287   aBallTotal->setObjectName("nbBall");
288   myWidgets[ index++ ] << aBallLine;
289   myWidgets[ index++ ] << aBallLab << aBallTotal;
290
291   // ... 1D elements
292   QWidget* a1DLine     = createLine();
293   QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
294   QLabel*  a1DTotal    = createField();
295   a1DTotal->setObjectName("nb1D");
296   QLabel*  a1DLin      = createField();
297   a1DLin->setObjectName("nbLinear1D");
298   QLabel*  a1DQuad     = createField();
299   a1DQuad->setObjectName("nbQuadratic1D");
300   myWidgets[ index++ ] << a1DLine;
301   myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad;
302
303   // ... 2D elements
304   QWidget* a2DLine      = createLine();
305   QLabel*  a2DLab       = new QLabel( tr( "2D_LAB" ), this );
306   QLabel*  a2DTotal     = createField();
307   a2DTotal->setObjectName("nb2D");
308   QLabel*  a2DLin       = createField();
309   a2DLin->setObjectName("nbLinear2D");
310   QLabel*  a2DQuad      = createField();
311   a2DQuad->setObjectName("nbQuadratic2D");
312   QLabel*  a2DBiQuad    = createField();
313   a2DBiQuad->setObjectName("nbBiQuadratic2D");
314   QLabel*  a2DTriLab    = new QLabel( tr( "TRIANGLES_LAB" ), this );
315   QLabel*  a2DTriTotal  = createField();
316   a2DTriTotal->setObjectName("nbTriangle");
317   QLabel*  a2DTriLin    = createField();
318   a2DTriLin->setObjectName("nbLinearTriangle");
319   QLabel*  a2DTriQuad   = createField();
320   a2DTriQuad->setObjectName("nbQuadraticTriangle");
321   QLabel*  a2DTriBiQuad = createField();
322     a2DTriBiQuad->setObjectName("nbBiQuadraticTriangle");
323   QLabel*  a2DQuaLab    = new QLabel( tr( "QUADRANGLES_LAB" ), this );
324   QLabel*  a2DQuaTotal  = createField();
325   a2DQuaTotal->setObjectName("nbQuadrangle");
326   QLabel*  a2DQuaLin    = createField();
327   a2DQuaLin->setObjectName("nbLinearQuadrangle");
328   QLabel*  a2DQuaQuad   = createField();
329   a2DQuaQuad->setObjectName("nbQuadraticQuadrangle");
330   QLabel*  a2DQuaBiQuad = createField();
331   a2DQuaBiQuad->setObjectName("nbBiQuadraticQuadrangle");
332   QLabel*  a2DPolLab    = new QLabel( tr( "POLYGONS_LAB" ), this );
333   QLabel*  a2DPolTotal  = createField();
334   a2DPolTotal->setObjectName("nbPolygon");
335   QLabel*  a2DPolLin    = createField();
336   a2DPolLin->setObjectName("nbLinearPolygon");
337   QLabel*  a2DPolQuad   = createField();
338   a2DPolQuad->setObjectName("nbQuadraticPolygon");
339   myWidgets[ index++ ] << a2DLine;
340   myWidgets[ index++ ] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad    << a2DBiQuad;
341   myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad << a2DTriBiQuad;
342   myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad << a2DQuaBiQuad;
343   myWidgets[ index++ ] << a2DPolLab << a2DPolTotal << a2DPolLin << a2DPolQuad;
344
345   // ... 3D elements
346   QWidget* a3DLine      = createLine();
347   QLabel*  a3DLab       = new QLabel( tr( "3D_LAB" ), this );
348   QLabel*  a3DTotal     = createField();
349   a3DTotal->setObjectName("nb3D");
350   QLabel*  a3DLin       = createField();
351   a3DLin->setObjectName("nbLinear3D");
352   QLabel*  a3DQuad      = createField();
353   a3DQuad->setObjectName("nbQuadratic3D");
354   QLabel*  a3DBiQuad    = createField();
355   a3DBiQuad->setObjectName("nbBiQuadratic3D");
356   QLabel*  a3DTetLab    = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
357   QLabel*  a3DTetTotal  = createField();
358   a3DTetTotal->setObjectName("nbTetrahedron");
359   QLabel*  a3DTetLin    = createField();
360   a3DTetLin->setObjectName("nbLinearTetrahedron");
361   QLabel*  a3DTetQuad   = createField();
362   a3DTetQuad->setObjectName("nbQudraticTetrahedron");
363   QLabel*  a3DHexLab    = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
364   QLabel*  a3DHexTotal  = createField();
365   a3DHexTotal->setObjectName("nbHexahedron");
366   QLabel*  a3DHexLin    = createField();
367   a3DHexLin->setObjectName("nbLinearHexahedron");
368   QLabel*  a3DHexQuad   = createField();
369   a3DHexQuad->setObjectName("nbQuadraticHexahedron");
370   QLabel*  a3DHexBiQuad = createField();
371   a3DHexBiQuad->setObjectName("nbBiQuadraticHexahedron");
372   QLabel*  a3DPyrLab    = new QLabel( tr( "PYRAMIDS_LAB" ), this );
373   QLabel*  a3DPyrTotal  = createField();
374   a3DPyrTotal->setObjectName("nbPyramid");
375   QLabel*  a3DPyrLin    = createField();
376   a3DPyrLin->setObjectName("nbLinearPyramid");
377   QLabel*  a3DPyrQuad   = createField();
378   a3DPyrQuad->setObjectName("nbQuadraticPyramid");
379   QLabel*  a3DPriLab    = new QLabel( tr( "PRISMS_LAB" ), this );
380   QLabel*  a3DPriTotal  = createField();
381   a3DPriTotal->setObjectName("nbPrism");
382   QLabel*  a3DPriLin    = createField();
383   a3DPriLin->setObjectName("nbLinearPrism");
384   QLabel*  a3DPriQuad   = createField();
385   a3DPriQuad->setObjectName("nbQuadraticPrism");
386   QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
387   QLabel*  a3DHexPriTotal = createField();
388   a3DHexPriTotal->setObjectName("nbHexagonalPrism");
389   QLabel*  a3DPolLab    = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
390   QLabel*  a3DPolTotal  = createField();
391   a3DPolTotal->setObjectName("nbPolyhedron");
392   myWidgets[ index++ ] << a3DLine;
393   myWidgets[ index++ ] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad    << a3DBiQuad;
394   myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
395   myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad << a3DHexBiQuad;
396   myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
397   myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
398   myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal;
399   myWidgets[ index++ ] << a3DPolLab << a3DPolTotal;
400
401   myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
402   myLoadBtn->setAutoDefault( true );
403   connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
404   
405   setFontAttributes( aNameLab,    Bold );
406   setFontAttributes( aObjLab,     Bold );
407   setFontAttributes( aNodesLab,   Bold );
408   setFontAttributes( aElemLab,    Bold );
409   setFontAttributes( aElemTotal,  Italic );
410   setFontAttributes( aElemLin,    Italic );
411   setFontAttributes( aElemQuad,   Italic );
412   setFontAttributes( aElemBiQuad, Italic );
413   setFontAttributes( a0DLab,      Bold );
414   setFontAttributes( aBallLab,    Bold );
415   setFontAttributes( a1DLab,      Bold );
416   setFontAttributes( a2DLab,      Bold );
417   setFontAttributes( a3DLab,      Bold );
418
419   l->addWidget( aNameLab,     0, 0 );
420   l->addWidget( aName,        0, 1, 1, 4 );
421   l->addWidget( aObjLab,      1, 0 );
422   l->addWidget( aObj,         1, 1, 1, 4 );
423   l->addWidget( aNodesLine,   2, 0, 1, 5 );
424   l->addWidget( aNodesLab,    3, 0 );
425   l->addWidget( aNodes,       3, 1 );
426   l->addWidget( aElemLine,    4, 0, 1, 5 );
427   l->addWidget( aElemLab,     5, 0 );
428   l->addWidget( aElemTotal,   5, 1 );
429   l->addWidget( aElemLin,     5, 2 );
430   l->addWidget( aElemQuad,    5, 3 );
431   l->addWidget( aElemBiQuad,  5, 4 );
432   l->addWidget( aNbLine,      6, 1, 1, 4 );
433   l->addWidget( aNbTotal,     7, 1 );
434   l->addWidget( aNbLin,       7, 2 );
435   l->addWidget( aNbQuad,      7, 3 );
436   l->addWidget( aNbBiQuad,    7, 4 );
437   l->addWidget( a0DLine,      8, 1, 1, 4 );
438   l->addWidget( a0DLab,       9, 0 );
439   l->addWidget( a0DTotal,     9, 1 );
440   l->addWidget( aBallLine,    10, 1, 1, 4 );
441   l->addWidget( aBallLab,     11, 0 );
442   l->addWidget( aBallTotal,   11, 1 );
443   l->addWidget( a1DLine,      12, 1, 1, 4 );
444   l->addWidget( a1DLab,       13, 0 );
445   l->addWidget( a1DTotal,     13, 1 );
446   l->addWidget( a1DLin,       13, 2 );
447   l->addWidget( a1DQuad,      13, 3 );
448   l->addWidget( a2DLine,      14, 1, 1, 4 );
449   l->addWidget( a2DLab,       15, 0 );
450   l->addWidget( a2DTotal,     15, 1 );
451   l->addWidget( a2DLin,       15, 2 );
452   l->addWidget( a2DQuad,      15, 3 );
453   l->addWidget( a2DBiQuad,    15, 4 );
454   l->addWidget( a2DTriLab,    16, 0 );
455   l->addWidget( a2DTriTotal,  16, 1 );
456   l->addWidget( a2DTriLin,    16, 2 );
457   l->addWidget( a2DTriQuad,   16, 3 );
458   l->addWidget( a2DTriBiQuad, 16, 4 );
459   l->addWidget( a2DQuaLab,    17, 0 );
460   l->addWidget( a2DQuaTotal,  17, 1 );
461   l->addWidget( a2DQuaLin,    17, 2 );
462   l->addWidget( a2DQuaQuad,   17, 3 );
463   l->addWidget( a2DQuaBiQuad, 17, 4 );
464   l->addWidget( a2DPolLab,    18, 0 );
465   l->addWidget( a2DPolTotal,  18, 1 );
466   l->addWidget( a2DPolLin,    18, 2 );
467   l->addWidget( a2DPolQuad,   18, 3 );
468   l->addWidget( a3DLine,      19, 1, 1, 4 );
469   l->addWidget( a3DLab,       20, 0 );
470   l->addWidget( a3DTotal,     20, 1 );
471   l->addWidget( a3DLin,       20, 2 );
472   l->addWidget( a3DQuad,      20, 3 );
473   l->addWidget( a3DBiQuad,    20, 4 );
474   l->addWidget( a3DTetLab,    21, 0 );
475   l->addWidget( a3DTetTotal,  21, 1 );
476   l->addWidget( a3DTetLin,    21, 2 );
477   l->addWidget( a3DTetQuad,   21, 3 );
478   l->addWidget( a3DHexLab,    22, 0 );
479   l->addWidget( a3DHexTotal,  22, 1 );
480   l->addWidget( a3DHexLin,    22, 2 );
481   l->addWidget( a3DHexQuad,   22, 3 );
482   l->addWidget( a3DHexBiQuad, 22, 4 );
483   l->addWidget( a3DPyrLab,    23, 0 );
484   l->addWidget( a3DPyrTotal,  23, 1 );
485   l->addWidget( a3DPyrLin,    23, 2 );
486   l->addWidget( a3DPyrQuad,   23, 3 );
487   l->addWidget( a3DPriLab,    24, 0 );
488   l->addWidget( a3DPriTotal,  24, 1 );
489   l->addWidget( a3DPriLin,    24, 2 );
490   l->addWidget( a3DPriQuad,   24, 3 );
491   l->addWidget( a3DHexPriLab,   25, 0 );
492   l->addWidget( a3DHexPriTotal, 25, 1 );
493   l->addWidget( a3DPolLab,    26, 0 );
494   l->addWidget( a3DPolTotal,  26, 1 );
495   l->addWidget( myLoadBtn,    28, 1, 1, 4 );
496
497   l->setColumnStretch( 0, 0 );
498   l->setColumnStretch( 1, 5 );
499   l->setColumnStretch( 2, 5 );
500   l->setColumnStretch( 3, 5 );
501   l->setColumnStretch( 4, 5 );
502   l->setRowStretch( 27, 5 );
503
504   clear();
505 }
506
507 /*!
508   \brief Destructor
509 */
510 SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
511 {
512 }
513
514 /*!
515   \brief Show information on the mesh object.
516   \param obj object being processed (mesh, sub-mesh, group, ID source)
517 */
518 void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
519 {
520   clear();
521   if ( !CORBA::is_nil( obj ) ) {
522     _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
523     if ( sobj ) 
524       myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
525     SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
526     SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
527     SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
528     if ( !aMesh->_is_nil() ) {
529       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) );
530     }
531     else if ( !aSubMesh->_is_nil() ) {
532       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) );
533     }
534     else if ( !aGroup->_is_nil() ) {
535       QString objType;
536       switch( aGroup->GetType() ) {
537       case SMESH::NODE:  objType = tr( "OBJECT_GROUP_NODES"   );break;
538       case SMESH::EDGE:  objType = tr( "OBJECT_GROUP_EDGES"   );break;
539       case SMESH::FACE:  objType = tr( "OBJECT_GROUP_FACES"   );break;
540       case SMESH::VOLUME:objType = tr( "OBJECT_GROUP_VOLUMES" );break;
541       case SMESH::ELEM0D:objType = tr( "OBJECT_GROUP_0DELEMS" );break;
542       case SMESH::BALL:  objType = tr( "OBJECT_GROUP_BALLS"   );break;
543       default:           objType = tr( "OBJECT_GROUP"         );break;
544       }
545       myWidgets[iObject][iSingle]->setProperty( "text", objType );
546     }
547     SMESH::long_array_var info = obj->GetMeshInfo();
548     myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
549     myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
550     myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ) );
551     long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
552     myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ) );
553     myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) );
554     myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) );
555     long nbTriangles     = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_BiQuad_Triangle];
556     long nbQuadrangles   = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
557     long nb2DPolygons    = info[SMDSEntity_Polygon]    + info[SMDSEntity_Quad_Polygon];
558     long nb2DLinear      = info[SMDSEntity_Triangle]        + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
559     long nb2DQuadratic   = info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_Quad_Polygon];
560     long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle];
561     long nb2DTotal       = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic;
562
563     myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( nb2DTotal ));
564     myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( nb2DLinear ) );
565     myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( nb2DQuadratic ) );
566     myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( nb2DBiQuadratic ) );
567     myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( nbTriangles ) );
568     myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) );
569     myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) );
570     myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Triangle] ) );
571     myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( nbQuadrangles ) );
572     myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) );
573     myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) );
574     myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Quadrangle] ) );
575     myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( nb2DPolygons ));
576     myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
577     myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Polygon] ) );
578     long nbTetrahedrons  = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
579     long nbHexahedrons   = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
580     long nbPyramids      = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
581     long nbPrisms        = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta];
582     long nb3DLinear      = info[SMDSEntity_Tetra]   + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
583     long nb3DQuadratic   = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
584     long nb3DBiQuadratic = info[SMDSEntity_TriQuad_Hexa];
585     long nb3DTotal       = nb3DLinear + nb3DQuadratic + nb3DBiQuadratic;
586     myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( nb3DTotal ) );
587     myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( nb3DLinear ) );
588     myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( nb3DQuadratic ) );
589     myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( nb3DBiQuadratic ) );
590     myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( nbTetrahedrons ) );
591     myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
592     myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) );
593     myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( nbHexahedrons ) );
594     myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) );
595     myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ) );
596     myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_TriQuad_Hexa] ) );
597     myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( nbPyramids ) );
598     myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) );
599     myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) );
600     myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( nbPrisms ) );
601     myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) );
602     myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) );
603     myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
604     myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
605     long nbElemTotal       = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DTotal + nb3DTotal;
606     long nbElemLinerial    = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear;
607     long nbElemQuadratic   = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic;
608     long nbElemBiQuadratic = nb2DBiQuadratic + nb3DBiQuadratic;
609     myWidgets[iNb][iTotal]      ->setProperty( "text", QString::number( nbElemTotal ) );
610     myWidgets[iNb][iLinear]     ->setProperty( "text", QString::number( nbElemLinerial ) );
611     myWidgets[iNb][iQuadratic]  ->setProperty( "text", QString::number( nbElemQuadratic ) );
612     myWidgets[iNb][iBiQuadratic]->setProperty( "text", QString::number( nbElemBiQuadratic ) );
613     // before full loading from study file, type of elements in a sub-mesh can't be defined
614     // in some cases
615     bool infoOK = obj->IsMeshInfoCorrect();
616     myLoadBtn->setVisible( !infoOK );
617     if ( !infoOK )
618     {
619       // two options:
620       // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
621       // 2. No info at all (for a group on geom or filter)
622       bool hasAnyInfo = false;
623       for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
624         hasAnyInfo = info[i];
625       if ( hasAnyInfo ) // believe it is a sub-mesh
626       {
627         if ( nb2DLinear + nb2DQuadratic + nb2DBiQuadratic > 0 )
628         {
629           myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
630           myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
631           myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
632           myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
633           myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
634           myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
635           myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
636           myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
637           myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
638           myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
639           myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
640           myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", "?" );
641           myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", "?" );
642           myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
643           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
644           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
645           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
646           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
647         }
648         else if ( nb3DLinear + nb3DQuadratic + nb3DBiQuadratic > 0 )
649         {
650           myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
651           myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
652           myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", "?" );
653           myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
654           myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
655           myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
656           myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
657           myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
658           myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
659           myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
660           myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
661           myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
662           myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
663           myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
664           myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
665           myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
666           myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
667           myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
668           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
669           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
670           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
671           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
672         }
673       }
674       else
675       {
676         myWidgets[iNodes][iTotal]               ->setProperty( "text", "?" );
677         myWidgets[i0D][iTotal]                  ->setProperty( "text", "?" );
678         myWidgets[iBalls][iTotal]               ->setProperty( "text", "?" );
679         myWidgets[i1D][iTotal]                  ->setProperty( "text", "?" );
680         myWidgets[i1D][iLinear]                 ->setProperty( "text", "?" );
681         myWidgets[i1D][iQuadratic]              ->setProperty( "text", "?" );
682         myWidgets[i2D][iTotal]                  ->setProperty( "text", "?" );
683         myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
684         myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
685         myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
686         myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
687         myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
688         myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
689         myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
690         myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
691         myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
692         myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
693         myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
694         myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
695         myWidgets[i3D][iTotal]                  ->setProperty( "text", "?" );
696         myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
697         myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
698         myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
699         myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
700         myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
701         myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
702         myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
703         myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
704         myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
705         myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
706         myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
707         myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
708         myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
709         myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
710         myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
711         myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
712         myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
713         myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
714         myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
715         myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
716         myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
717       }
718     }
719   }
720 }
721
722 /*!
723   \brief Load mesh from a study file
724 */
725 void SMESHGUI_MeshInfo::loadMesh()
726 {
727   SUIT_OverrideCursor wc;
728
729   SALOME_ListIO selected;
730   SMESHGUI::selectionMgr()->selectedObjects( selected );
731
732   if ( selected.Extent() == 1 ) {
733     Handle(SALOME_InteractiveObject) IO = selected.First();
734     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
735     if ( !CORBA::is_nil( obj ) ) {
736       SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
737       if ( !mesh->_is_nil() )
738       {
739         mesh->Load();
740         showInfo( obj );
741       }
742     }
743   }
744 }
745
746 /*!
747   \brief Reset the widget to the initial state (nullify all fields).
748 */
749 void SMESHGUI_MeshInfo::clear()
750 {
751   myWidgets[iName][iSingle]               ->setProperty( "text", QString() );
752   myWidgets[iObject][iSingle]             ->setProperty( "text", QString() );
753   myWidgets[iNodes][iTotal]               ->setProperty( "text", QString::number( 0 ) );
754   myWidgets[i0D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
755   myWidgets[iBalls][iTotal]               ->setProperty( "text", QString::number( 0 ) );
756   myWidgets[i1D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
757   myWidgets[i1D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
758   myWidgets[i1D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
759   myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
760   myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
761   myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
762   myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
763   myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( 0 ) );
764   myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( 0 ) );
765   myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( 0 ) );
766   myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( 0 ) );
767   myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( 0 ) );
768   myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( 0 ) );
769   myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
770   myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
771   myWidgets[i2DPolygons][iLinear]         ->setProperty( "text", QString::number( 0 ) );
772   myWidgets[i2DPolygons][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
773   myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( 0 ) );
774   myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
775   myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
776   myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
777   myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
778   myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( 0 ) );
779   myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( 0 ) );
780   myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( 0 ) );
781   myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
782   myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( 0 ) );
783   myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
784   myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
785   myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( 0 ) );
786   myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( 0 ) );
787   myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
788   myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( 0 ) );
789   myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( 0 ) );
790   myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( 0 ) );
791   myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( 0 ) );
792   myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
793   myWidgets[iNb][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
794   myWidgets[iNb][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
795   myWidgets[iNb][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
796   myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
797 }
798
799 /*!
800   \brief Create info field
801   \return new info field
802 */
803 QLabel* SMESHGUI_MeshInfo::createField()
804 {
805   QLabel* lab = new QLabel( this );
806   lab->setFrameStyle( StyledPanel | Sunken );
807   lab->setAlignment( Qt::AlignCenter );
808   lab->setAutoFillBackground( true );
809   QPalette pal = lab->palette();
810   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
811   lab->setPalette( pal );
812   lab->setMinimumWidth( 70 );
813   return lab;
814 }
815
816 /*!
817   \brief Create horizontal rule.
818   \return new line object
819 */
820 QWidget* SMESHGUI_MeshInfo::createLine()
821 {
822   QFrame* line = new QFrame( this );
823   line->setFrameStyle( HLine | Sunken );
824   return line;
825 }
826
827 /*!
828   \brief Change widget font attributes (bold, italic, ...).
829   \param w widget
830   \param attr font attributes (XORed flags)
831   \param val value to be set to attributes
832 */
833 void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
834 {
835   if ( w && attr ) {
836     QFont f = w->font();
837     if ( attr & Bold   ) f.setBold( val );
838     if ( attr & Italic ) f.setItalic( val );
839     w->setFont( f );
840   }
841 }
842
843 /*!
844   \brief Show/hide group(s) of fields.
845   \param start beginning of the block
846   \param end end of the block
847   \param on visibility flag
848 */
849 void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
850 {
851   start = qMax( 0, start );
852   end   = qMin( end, (int)iElementsEnd );
853   for ( int i = start; i < end; i++ ) {
854     wlist wl = myWidgets[i];
855     foreach ( QWidget* w, wl ) w->setVisible( on );
856   }
857 }
858
859 void SMESHGUI_MeshInfo::saveInfo( QTextStream &out )
860 {
861   out << QString( 9, '-' ) << "\n";
862   out << tr( "BASE_INFO" ) << "\n";
863   out << QString( 9, '-' ) << "\n";
864   out <<                                   tr( "NAME_LAB" )         << "  " << ( myWidgets[iName][iSingle]->property( "text" ) ).toString() << "\n";
865   out <<                                   tr( "OBJECT_LAB" )       << "  " << ( myWidgets[iObject][iSingle]->property( "text" ) ).toString() << "\n";
866   out <<                                   tr( "NODES_LAB" )        << "  " << ( myWidgets[iNodes][iTotal]->property( "text" ) ).toString() << "\n";
867   out <<                                   tr( "ELEMENTS_LAB" )     << "\n";
868   out << QString( SPACING_INFO,   ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iNb][iTotal]->property( "text" ) ).toString() << "\n";
869   out << QString( SPACING_INFO,   ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[iNb][iLinear]->property( "text" ) ).toString() << "\n";
870   out << QString( SPACING_INFO,   ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" ) ).toString() << "\n";
871   out << QString( SPACING_INFO,   ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[iNb][iBiQuadratic]->property( "text" ) ).toString() << "\n";
872   out << QString( SPACING_INFO,   ' ' ) << tr( "0D_LAB" )           << "\n";
873   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i0D][iTotal]->property( "text" ) ).toString() << "\n";
874   out << QString( SPACING_INFO,   ' ' ) << tr( "BALL_LAB" )         << "\n";
875   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iBalls][iTotal]->property( "text" ) ).toString() << "\n";
876   out << QString( SPACING_INFO,   ' ' ) << tr( "1D_LAB" )           << "\n";
877   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i1D][iTotal]->property( "text" ) ).toString() << "\n";
878   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i1D][iLinear]->property( "text" ) ).toString() << "\n";
879   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" ) ).toString() << "\n";
880   out << QString( SPACING_INFO,   ' ' ) << tr( "2D_LAB" )           << "\n";
881   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2D][iTotal]->property( "text" ) ).toString() << "\n";
882   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2D][iLinear]->property( "text" ) ).toString() << "\n";
883   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" ) ).toString() << "\n";
884   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
885   out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" )    << "\n";
886   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" ) ).toString() << "\n";
887   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" ) ).toString() << "\n";
888   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" ) ).toString() << "\n";
889   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DTriangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
890   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" )  << "\n";
891   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" ) ).toString() << "\n";
892   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" ) ).toString() << "\n";
893   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" ) ).toString() << "\n";
894   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
895   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" )     << "\n";
896   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n";
897   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DPolygons][iLinear]->property( "text" ) ).toString() << "\n";
898   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DPolygons][iQuadratic]->property( "text" ) ).toString() << "\n";
899   out << QString( SPACING_INFO,   ' ' ) << tr( "3D_LAB" )           << "\n";
900   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n";
901   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n";
902   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" ) ).toString() << "\n";
903   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
904   out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n";
905   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" ) ).toString() << "\n";
906   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" ) ).toString() << "\n";
907   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
908   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" )  << "\n";
909   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" ) ).toString() << "\n";
910   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" ) ).toString() << "\n";
911   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
912   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iBiQuadratic]->property( "text" ) ).toString() << "\n";
913   out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" )     << "\n";
914   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" ) ).toString() << "\n";
915   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" ) ).toString() << "\n";
916   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" ) ).toString() << "\n";
917   out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" )       << "\n";
918   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" ) ).toString() << "\n";
919   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" ) ).toString() << "\n";
920   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" ) ).toString() << "\n";
921   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" )   << "\n";
922   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" ) ).toString() << "\n";
923   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" )  << "\n";
924   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" ) ).toString() << "\n" << "\n";
925 }
926
927 /*!
928   \class SMESHGUI_ElemInfo
929   \brief Base class for the mesh element information widget.
930 */
931
932 /*!
933   \brief Constructor
934   \param parent parent widget
935 */
936 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
937 : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
938 {
939   myFrame = new QWidget( this );
940   myExtra = new ExtraWidget( this );
941   QVBoxLayout* vbl = new QVBoxLayout( this );
942   vbl->setMargin( 0 );
943   vbl->setSpacing( 0 );
944   vbl->addWidget( myFrame );
945   vbl->addWidget( myExtra );
946   connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
947   connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
948   clear();
949 }
950
951 /*!
952   \brief Destructor
953 */
954 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
955 {
956 }
957
958 /*!
959   \brief Set mesh data source (actor)
960   \param actor mesh object actor
961 */
962 void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
963 {
964   if ( myActor != actor ) {
965     myActor = actor;
966     myIsElement = -1;
967     clear();
968   }
969 }
970
971 /*!
972   \brief Show mesh element information
973   \param id mesh node / element ID
974   \param isElem show mesh element information if \c true or mesh node information if \c false
975 */
976 void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
977 {
978   QSet<long> ids;
979   ids << id;
980   showInfo( ids, isElem );
981 }
982
983 /*!
984   \brief Show mesh element information
985   \param ids mesh nodes / elements identifiers
986   \param isElem show mesh element information if \c true or mesh node information if \c false
987 */
988 void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
989 {
990   QList<long> newIds = ids.toList();
991   qSort( newIds );
992   if ( myIDs == newIds && myIsElement == isElem ) return;
993
994   myIDs = newIds;
995   myIsElement = isElem;
996   myIndex = 0;
997   updateControls();
998   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
999 }
1000
1001 /*!
1002   \brief Clear mesh element information widget
1003 */
1004 void SMESHGUI_ElemInfo::clear()
1005 {
1006   myIDs.clear();
1007   myIndex = 0;
1008   clearInternal();
1009   updateControls();
1010 }
1011
1012 /*!
1013   \brief Get central area widget
1014   \return central widget
1015 */
1016 QWidget* SMESHGUI_ElemInfo::frame() const
1017 {
1018   return myFrame;
1019 }
1020
1021 /*!
1022   \brief Get actor
1023   \return actor being used
1024 */
1025 SMESH_Actor* SMESHGUI_ElemInfo::actor() const
1026 {
1027   return myActor;
1028 }
1029
1030 /*!
1031   \brief Get current info mode.
1032   \return \c true if mesh element information is shown or \c false if node information is shown
1033 */
1034 bool SMESHGUI_ElemInfo::isElements() const
1035 {
1036   return myIsElement;
1037 }
1038
1039 /*!
1040   \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
1041   \brief Show information on the specified nodes / elements
1042
1043   This function is to be redefined in sub-classes.
1044
1045   \param ids nodes / elements identifiers information is to be shown on
1046 */
1047
1048 /*!
1049   \brief Internal clean-up (reset widget)
1050 */
1051 void SMESHGUI_ElemInfo::clearInternal()
1052 {
1053 }
1054
1055 /*!
1056   \brief Get node connectivity
1057   \param node mesh node
1058   \return node connectivity map
1059 */
1060 SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
1061 {
1062   Connectivity elmap;
1063   if ( node ) {
1064     SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
1065     while ( it && it->more() ) {
1066       const SMDS_MeshElement* ne = it->next();
1067       elmap[ ne->GetType() ] << ne->GetID();
1068     }
1069   }
1070   return elmap;
1071 }
1072
1073 /*!
1074   \brief Format connectivity data to string representation
1075   \param connectivity connetivity map
1076   \param type element type
1077   \return string representation of the connectivity
1078 */
1079 QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
1080 {
1081   QStringList str;
1082   if ( connectivity.contains( type ) ) {
1083     QList<int> elements = connectivity[ type ];
1084     qSort( elements );
1085     foreach( int id, elements )
1086       str << QString::number( id );
1087   }
1088   return str.join( " " );
1089 }
1090
1091 /*!
1092   \brief Calculate gravity center of the mesh element
1093   \param element mesh element
1094 */
1095 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
1096 {
1097   XYZ xyz;
1098   if ( element ) {
1099     SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
1100     while ( nodeIt->more() ) {
1101       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1102       xyz.add( node->X(), node->Y(), node->Z() );
1103     }
1104     xyz.divide( element->NbNodes() );
1105   }
1106   return xyz;
1107 }
1108
1109 /*!
1110   \brief Calculate normal vector to the mesh face
1111   \param element mesh face
1112 */
1113 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::normal( const SMDS_MeshElement* element )
1114 {
1115   gp_XYZ n = SMESH::getNormale( dynamic_cast<const SMDS_MeshFace*>( element ) );
1116   return XYZ(n.X(), n.Y(), n.Z());
1117 }
1118
1119 /*!
1120   \brief This slot is called from "Show Previous" button click.
1121   Shows information on the previous group of the items.
1122 */
1123 void SMESHGUI_ElemInfo::showPrevious()
1124 {
1125   myIndex = qMax( 0, myIndex-1 );
1126   updateControls();
1127   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1128 }
1129
1130 /*!
1131   \brief This slot is called from "Show Next" button click.
1132   Shows information on the next group of the items.
1133 */
1134 void SMESHGUI_ElemInfo::showNext()
1135 {
1136   myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
1137   updateControls();
1138   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1139 }
1140
1141 /*!
1142   \brief Update widgets state
1143 */
1144 void SMESHGUI_ElemInfo::updateControls()
1145 {
1146   myExtra->updateControls( myIDs.count(), myIndex );
1147 }
1148
1149 /*!
1150   \class SMESHGUI_SimpleElemInfo
1151   \brief Represents mesh element information in the simple text area.
1152 */
1153
1154 /*!
1155   \brief Constructor
1156   \param parent parent widget
1157 */
1158 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
1159 : SMESHGUI_ElemInfo( parent )
1160 {
1161   myInfo = new QTextBrowser( frame() );
1162   QVBoxLayout* l = new QVBoxLayout( frame() );
1163   l->setMargin( 0 );
1164   l->addWidget( myInfo );
1165 }
1166
1167 /*!
1168   \brief Show mesh element information
1169   \param ids mesh nodes / elements identifiers
1170 */
1171 void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
1172 {
1173   clearInternal();
1174   
1175   if ( actor() ) {
1176     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1177     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1178     int cprecision = -1;
1179     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1180       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1181     foreach ( long id, ids ) {
1182       if ( !isElements() ) {
1183         //
1184         // show node info
1185         //
1186         const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
1187         if ( !node ) return;
1188
1189         // node ID
1190         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( id ) );
1191         // separator
1192         myInfo->append( "" );
1193         // coordinates
1194         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1195                         arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1196                         arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1197                         arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1198         // separator
1199         myInfo->append( "" );
1200         // connectivity
1201         Connectivity connectivity = nodeConnectivity( node );
1202         if ( !connectivity.isEmpty() ) {
1203           myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1204           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1205           if ( !con.isEmpty() )
1206             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1207           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1208           if ( !con.isEmpty() )
1209             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1210           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1211           if ( !con.isEmpty() )
1212             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ).arg( con ) );
1213           con = formatConnectivity( connectivity, SMDSAbs_Face );
1214           if ( !con.isEmpty() )
1215             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1216           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1217           if ( !con.isEmpty() )
1218             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1219         }
1220         else {
1221           myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1222         }
1223         // node position
1224         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1225         if ( !CORBA::is_nil( aMeshPtr ) ) {
1226           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1227           int shapeID = pos->shapeID;
1228           if ( shapeID > 0 ) {
1229             QString shapeType;
1230             double u = 0, v = 0;
1231             switch ( pos->shapeType ) {
1232             case GEOM::EDGE:
1233               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1234               if ( pos->params.length() == 1 )
1235                 u = pos->params[0];
1236               break;
1237             case GEOM::FACE:
1238               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1239               if ( pos->params.length() == 2 ) {
1240                u = pos->params[0];
1241                v = pos->params[1];
1242               }
1243               break;
1244             case GEOM::VERTEX:
1245               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1246               break;
1247             default:
1248               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1249               break;
1250             }
1251             // separator
1252             myInfo->append( "" );
1253             myInfo->append( QString( "<b>%1:" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ) );
1254             myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( shapeType ).arg( shapeID ) );
1255             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1256               myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "U_POSITION" ) ).
1257                               arg( QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1258               if ( pos->shapeType == GEOM::FACE ) {
1259                 myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "V_POSITION" ) ).
1260                                 arg( QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1261               }
1262             }
1263           }
1264         }
1265         // groups node belongs to
1266         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1267         if ( !CORBA::is_nil( aMesh ) ) {
1268           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1269           myInfo->append( "" ); // separator
1270           bool top_created = false;
1271           for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
1272             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1273             if ( CORBA::is_nil( aGrp ) ) continue;
1274             QString aName = aGrp->GetName();
1275             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1276               if ( !top_created ) {
1277                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1278                 top_created = true;
1279               }
1280               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1281               if ( grp_details ) {
1282                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1283                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1284                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1285                 
1286                 // type : group on geometry, standalone group, group on filter
1287                 if ( !CORBA::is_nil( aStdGroup ) ) {
1288                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1289                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1290                 }
1291                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1292                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1293                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1294                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1295                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1296                   if ( sobj ) {
1297                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1298                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1299                   }
1300                 }
1301                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1302                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1303                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1304                 }
1305                 
1306                 // size
1307                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1308                                 arg( QString::number( aGrp->Size() ) ) );
1309                 
1310                 // color
1311                 SALOMEDS::Color color = aGrp->GetColor();
1312                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1313                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1314               }
1315             }
1316           }
1317         }
1318       }
1319       else {
1320         //
1321         // show element info
1322         // 
1323         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1324         SMESH::Controls::NumericalFunctorPtr afunctor;
1325         if ( !e ) return;
1326         
1327         // Element ID && Type
1328         QString stype;
1329         switch( e->GetType() ) {
1330         case SMDSAbs_0DElement:
1331           stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1332         case SMDSAbs_Ball:
1333           stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1334         case SMDSAbs_Edge:
1335           stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1336         case SMDSAbs_Face:
1337           stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1338         case SMDSAbs_Volume:
1339           stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1340         default: 
1341           break;
1342         }
1343         if ( stype.isEmpty() ) return;
1344         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( stype ).arg( id ) );
1345         // separator
1346         myInfo->append( "" );
1347
1348         // Geometry type
1349         QString gtype;
1350         switch( e->GetEntityType() ) {
1351         case SMDSEntity_Triangle:
1352         case SMDSEntity_Quad_Triangle:
1353         case SMDSEntity_BiQuad_Triangle:
1354           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1355         case SMDSEntity_Quadrangle:
1356         case SMDSEntity_Quad_Quadrangle:
1357         case SMDSEntity_BiQuad_Quadrangle:
1358           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1359         case SMDSEntity_Polygon:
1360         case SMDSEntity_Quad_Polygon:
1361           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1362         case SMDSEntity_Tetra:
1363         case SMDSEntity_Quad_Tetra:
1364           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1365         case SMDSEntity_Pyramid:
1366         case SMDSEntity_Quad_Pyramid:
1367           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1368         case SMDSEntity_Hexa:
1369         case SMDSEntity_Quad_Hexa:
1370         case SMDSEntity_TriQuad_Hexa:
1371           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1372         case SMDSEntity_Penta:
1373         case SMDSEntity_Quad_Penta:
1374           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1375         case SMDSEntity_Hexagonal_Prism:
1376           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1377         case SMDSEntity_Polyhedra:
1378         case SMDSEntity_Quad_Polyhedra:
1379           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1380         default: 
1381           break;
1382         }
1383         if ( !gtype.isEmpty() )
1384           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" ) ).arg( gtype ) );
1385
1386         // Quadratic flag (any element except 0D)
1387         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1388           myInfo->append( QString( "<b>%1?</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ) );
1389         }
1390         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1391           // Ball diameter
1392           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() ));
1393         }
1394         // separator
1395         myInfo->append( "" );
1396
1397         // Connectivity
1398         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1399         for ( int idx = 1; nodeIt->more(); idx++ ) {
1400           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1401           // node number and ID
1402           myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
1403           // node coordinates
1404           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1405                           arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1406                           arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1407                           arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1408           // node connectivity
1409           Connectivity connectivity = nodeConnectivity( node );
1410           if ( !connectivity.isEmpty() ) {
1411             myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1412             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1413             if ( !con.isEmpty() )
1414               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1415             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1416             if ( !con.isEmpty() )
1417               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1418             con = formatConnectivity( connectivity, SMDSAbs_Face );
1419             if ( !con.isEmpty() )
1420               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1421             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1422             if ( !con.isEmpty() )
1423               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1424           }
1425           else {
1426             myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1427           }
1428         }
1429         // separator
1430         myInfo->append( "" );
1431
1432         // Controls
1433         myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" ) ) );
1434         //Length
1435         if ( e->GetType() == SMDSAbs_Edge ) {
1436           afunctor.reset( new SMESH::Controls::Length() );
1437           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1438           afunctor->SetPrecision( cprecision );
1439           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "LENGTH_EDGES" ) ).arg( afunctor->GetValue( id ) ) );  
1440         }
1441         if( e->GetType() == SMDSAbs_Face ) {
1442           //Area
1443           afunctor.reset(  new SMESH::Controls::Area() );
1444           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1445           afunctor->SetPrecision( cprecision );  
1446           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "AREA_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1447           //Taper
1448           afunctor.reset( new SMESH::Controls::Taper() );
1449           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1450           afunctor->SetPrecision( cprecision );
1451           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "TAPER_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1452           //AspectRatio2D
1453           afunctor.reset( new SMESH::Controls::AspectRatio() );
1454           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1455           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1456           //Minimum angle         
1457           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1458           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1459           afunctor->SetPrecision( cprecision );
1460           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1461           //Wraping angle        
1462           afunctor.reset( new SMESH::Controls::Warping() );
1463           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1464           afunctor->SetPrecision( cprecision );
1465           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1466           //Skew         
1467           afunctor.reset( new SMESH::Controls::Skew() );
1468           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1469           afunctor->SetPrecision( cprecision );
1470           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1471           //ElemDiam2D   
1472           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1473           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1474           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
1475         }
1476         if( e->GetType() == SMDSAbs_Volume ) {
1477           //AspectRatio3D
1478           afunctor.reset(  new SMESH::Controls::AspectRatio3D() );
1479           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1480           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1481           //Volume      
1482           afunctor.reset(  new SMESH::Controls::Volume() );
1483           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1484           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUME_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1485           //ElementDiameter3D    
1486           afunctor.reset(  new SMESH::Controls::Volume() );
1487           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1488           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" ) ).arg( afunctor->GetValue( id ) ) );
1489         }
1490         // separator
1491         myInfo->append( "" );
1492
1493         // Gravity center
1494         XYZ gc = gravityCenter( e );
1495         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1496         
1497         // Normal vector
1498         if( e->GetType() == SMDSAbs_Face ) {
1499           XYZ gc = normal( e );
1500           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1501         }
1502
1503         // Element position
1504         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1505           SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();    
1506           if ( !CORBA::is_nil( aMesh ) ) {
1507             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1508             int shapeID = pos.shapeID;
1509             if ( shapeID > 0 ) {
1510               myInfo->append( "" ); // separator
1511               QString shapeType;
1512               switch ( pos.shapeType ) {
1513               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1514               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1515               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1516               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1517               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1518               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1519               }
1520               myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ).arg( shapeType ).arg( shapeID ) );
1521             }
1522           }
1523         }
1524
1525         // Groups the element belongs to
1526         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1527         if ( !CORBA::is_nil( aMesh ) ) {
1528           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1529           myInfo->append( "" ); // separator
1530           bool top_created = false;
1531           for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
1532             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1533             if ( CORBA::is_nil( aGrp ) ) continue;
1534             QString aName = aGrp->GetName();
1535             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1536               if ( !top_created ) {
1537                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1538                 top_created = true;
1539               }
1540               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1541               if ( grp_details ) {
1542                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1543                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1544                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1545                 
1546                 // type : group on geometry, standalone group, group on filter
1547                 if ( !CORBA::is_nil( aStdGroup ) ) {
1548                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1549                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1550                 }
1551                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1552                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1553                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1554                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1555                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1556                   if ( sobj ) {
1557                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1558                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1559                   }
1560                 }
1561                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1562                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1563                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1564                 }
1565                 
1566                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1567                                 arg( QString::number( aGrp->Size() ) ) );
1568                 
1569                 // color
1570                 SALOMEDS::Color color = aGrp->GetColor();
1571                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1572                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1573               }
1574             }
1575           }
1576         }
1577       }
1578       // separator
1579       if ( ids.count() > 1 ) {
1580         myInfo->append( "" );
1581         myInfo->append( "------" );
1582         myInfo->append( "" );
1583       }
1584     }
1585   }
1586 }
1587
1588 /*!
1589   \brief Internal clean-up (reset widget)
1590 */
1591 void SMESHGUI_SimpleElemInfo::clearInternal()
1592 {
1593   myInfo->clear();
1594 }
1595
1596 void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out )
1597 {
1598   out << QString( 12, '-' ) << "\n";
1599   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
1600   out << QString( 12, '-' ) << "\n";
1601   out << myInfo->toPlainText();
1602   out << "\n";
1603 }
1604
1605
1606 /*!
1607   \class SMESHGUI_TreeElemInfo::ItemDelegate
1608   \brief Item delegate for tree mesh info widget
1609   \internal
1610 */
1611 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1612 {
1613 public:
1614   ItemDelegate( QObject* );
1615   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1616 };
1617
1618 /*!
1619   \brief Constructor
1620   \internal
1621 */
1622 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1623 {
1624 }
1625
1626 /*!
1627   \brief Create item editor widget
1628   \internal
1629 */
1630 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1631 {
1632   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1633   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1634   return w;
1635 }
1636
1637 /*!
1638   \class SMESHGUI_TreeElemInfo
1639   \brief Represents mesh element information in the tree-like form.
1640 */
1641
1642 /*!
1643   \brief Constructor
1644   \param parent parent widget
1645 */
1646 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1647 : SMESHGUI_ElemInfo( parent )
1648 {
1649   myInfo = new QTreeWidget( frame() );
1650   myInfo->setColumnCount( 2 );
1651   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1652   myInfo->header()->setStretchLastSection( true );
1653 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1654   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1655 #else
1656   myInfo->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
1657 #endif
1658   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1659   QVBoxLayout* l = new QVBoxLayout( frame() );
1660   l->setMargin( 0 );
1661   l->addWidget( myInfo );
1662   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
1663 }
1664
1665 /*!
1666   \brief Show mesh element information
1667   \param ids mesh nodes / elements identifiers
1668 */
1669 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1670 {
1671   clearInternal();
1672
1673   if ( actor() ) {
1674     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1675     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1676     int cprecision = -1;
1677     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1678       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1679     foreach ( long id, ids ) {
1680       if ( !isElements() ) {
1681         //
1682         // show node info
1683         //
1684         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1685         if ( !e ) return;
1686         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1687       
1688         // node ID
1689         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1690         nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ) );
1691         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1692         // coordinates
1693         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1694         coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1695         QTreeWidgetItem* xItem = createItem( coordItem );
1696         xItem->setText( 0, "X" );
1697         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1698         QTreeWidgetItem* yItem = createItem( coordItem );
1699         yItem->setText( 0, "Y" );
1700         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1701         QTreeWidgetItem* zItem = createItem( coordItem );
1702         zItem->setText( 0, "Z" );
1703         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1704         // connectivity
1705         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1706         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1707         Connectivity connectivity = nodeConnectivity( node );
1708         if ( !connectivity.isEmpty() ) {
1709           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1710           if ( !con.isEmpty() ) {
1711             QTreeWidgetItem* i = createItem( conItem );
1712             i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1713             i->setText( 1, con );
1714           }
1715           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1716           if ( !con.isEmpty() ) {
1717             QTreeWidgetItem* i = createItem( conItem );
1718             i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1719             i->setText( 1, con );
1720             i->setData( 1, TypeRole, NodeConnectivity );
1721           }
1722           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1723           if ( !con.isEmpty() ) {
1724             QTreeWidgetItem* i = createItem( conItem );
1725             i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1726             i->setText( 1, con );
1727             i->setData( 1, TypeRole, NodeConnectivity );
1728           }
1729           con = formatConnectivity( connectivity, SMDSAbs_Face );
1730           if ( !con.isEmpty() ) {
1731             QTreeWidgetItem* i = createItem( conItem );
1732             i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1733             i->setText( 1, con );
1734             i->setData( 1, TypeRole, NodeConnectivity );
1735           }
1736           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1737           if ( !con.isEmpty() ) {
1738             QTreeWidgetItem* i = createItem( conItem );
1739             i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1740             i->setText( 1, con );
1741             i->setData( 1, TypeRole, NodeConnectivity );
1742           }
1743         }
1744         else {
1745           conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ) );
1746         }
1747         // node position
1748         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1749         if ( !CORBA::is_nil( aMeshPtr ) ) {
1750           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1751           int shapeID = pos->shapeID;
1752           if ( shapeID > 0 ) {
1753             QString shapeType;
1754             double u = 0, v = 0;
1755             switch ( pos->shapeType ) {
1756             case GEOM::EDGE:
1757               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1758               if ( pos->params.length() == 1 )
1759                 u = pos->params[0];
1760               break;
1761             case GEOM::FACE:
1762               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1763               if ( pos->params.length() == 2 ) {
1764                 u = pos->params[0];
1765                 v = pos->params[1];
1766               }
1767               break;
1768             case GEOM::VERTEX:
1769               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1770               break;
1771             default:
1772               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1773               break;
1774             }
1775             QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
1776             posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") );
1777             posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
1778             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1779               QTreeWidgetItem* uItem = createItem( posItem );
1780               uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") );
1781               uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
1782               if ( pos->shapeType == GEOM::FACE ) {
1783                 QTreeWidgetItem* vItem = createItem( posItem );
1784                 vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") );
1785                 vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
1786               }
1787             }
1788           }
1789         }
1790         // groups node belongs to
1791         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1792         if ( !CORBA::is_nil( aMesh ) ) {
1793           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1794           QTreeWidgetItem* groupsItem = 0;
1795           for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
1796             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1797             if ( CORBA::is_nil( aGrp ) ) continue;
1798             QString aName = aGrp->GetName();
1799             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1800               if ( !groupsItem ) {
1801                 groupsItem = createItem( nodeItem, Bold );
1802                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1803               }
1804               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1805               it->setText( 0, aName.trimmed() );
1806               if ( grp_details ) {
1807                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1808                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1809                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1810                 
1811                 // type : group on geometry, standalone group, group on filter
1812                 QTreeWidgetItem* typeItem = createItem( it );
1813                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1814                 if ( !CORBA::is_nil( aStdGroup ) ) {
1815                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1816                 }
1817                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1818                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1819                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1820                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1821                   if ( sobj ) {
1822                     QTreeWidgetItem* gobjItem = createItem( typeItem );
1823                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
1824                     gobjItem->setText( 1, sobj->GetName().c_str() );
1825                   }
1826                 }
1827                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1828                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1829                 }
1830                 
1831                 // size
1832                 QTreeWidgetItem* sizeItem = createItem( it );
1833                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
1834                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
1835                 
1836                 // color
1837                 SALOMEDS::Color color = aGrp->GetColor();
1838                 QTreeWidgetItem* colorItem = createItem( it );
1839                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
1840                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1841               }
1842             }
1843           }
1844         }
1845       }
1846       else {
1847         //
1848         // show element info
1849         // 
1850         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1851         SMESH::Controls::NumericalFunctorPtr afunctor;
1852         if ( !e ) return;
1853         
1854         // element ID && type
1855         QString stype;
1856         switch( e->GetType() ) {
1857         case SMDSAbs_0DElement: stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1858         case SMDSAbs_Ball:      stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1859         case SMDSAbs_Edge:      stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1860         case SMDSAbs_Face:      stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1861         case SMDSAbs_Volume:    stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1862         default:;
1863         }
1864         if ( stype.isEmpty() ) return;
1865         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1866         elemItem->setText( 0, stype );
1867         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1868         // geometry type
1869         QString gtype;
1870         switch( e->GetEntityType() ) {
1871         case SMDSEntity_Triangle:
1872         case SMDSEntity_Quad_Triangle:
1873         case SMDSEntity_BiQuad_Triangle:
1874           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1875         case SMDSEntity_Quadrangle:
1876         case SMDSEntity_Quad_Quadrangle:
1877         case SMDSEntity_BiQuad_Quadrangle:
1878           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1879         case SMDSEntity_Polygon:
1880         case SMDSEntity_Quad_Polygon:
1881           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1882         case SMDSEntity_Tetra:
1883         case SMDSEntity_Quad_Tetra:
1884           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1885         case SMDSEntity_Pyramid:
1886         case SMDSEntity_Quad_Pyramid:
1887           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1888         case SMDSEntity_Hexa:
1889         case SMDSEntity_Quad_Hexa:
1890         case SMDSEntity_TriQuad_Hexa:
1891           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1892         case SMDSEntity_Penta:
1893         case SMDSEntity_Quad_Penta:
1894           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1895         case SMDSEntity_Hexagonal_Prism:
1896           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1897         case SMDSEntity_Polyhedra:
1898         case SMDSEntity_Quad_Polyhedra:
1899           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1900         default: 
1901           break;
1902         }
1903         if ( !gtype.isEmpty() ) {
1904           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1905           typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ) );
1906           typeItem->setText( 1, gtype );
1907         }
1908         // quadratic flag (for edges, faces and volumes)
1909         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1910           // quadratic flag
1911           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1912           quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ) );
1913           quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) );
1914         }
1915         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1916           // ball diameter
1917           QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
1918           diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) );
1919           diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
1920         }
1921         // connectivity
1922         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1923         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1924
1925
1926         if( e->GetGeomType() != SMDSGeom_POLYHEDRA ) {
1927           SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1928           for ( int idx = 1; nodeIt->more(); idx++ ) {
1929             const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1930             nodeInfo( node, idx, e->NbNodes(), conItem );
1931           }
1932         }
1933         else {
1934           const SMDS_VtkVolume* aVtkVolume = dynamic_cast<const SMDS_VtkVolume*>(e);
1935           SMDS_ElemIteratorPtr nodeIt = aVtkVolume->uniqueNodesIterator();
1936           QList<const SMDS_MeshElement*> uniqueNodes;
1937           while ( nodeIt->more() )
1938             uniqueNodes.append( nodeIt->next() );
1939
1940           SMDS_VolumeTool vtool( e );
1941           const int nbFaces = vtool.NbFaces();
1942           for( int face_id = 0; face_id < nbFaces; face_id++ ) {
1943             QTreeWidgetItem* faceItem = createItem( conItem, Bold );
1944             faceItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "FACE" ) ).arg( face_id + 1 ).arg( nbFaces ) );
1945             faceItem->setExpanded( true );
1946
1947             const SMDS_MeshNode** aNodeIds = vtool.GetFaceNodes( face_id );
1948             const int nbNodes = vtool.NbFaceNodes( face_id );
1949             for( int node_id = 0; node_id < nbNodes; node_id++ ) {
1950               const SMDS_MeshNode* node = aNodeIds[node_id];
1951               nodeInfo( node, uniqueNodes.indexOf(node) + 1, aVtkVolume->NbUniqueNodes(), faceItem );
1952             }
1953           }
1954         }
1955         //Controls
1956         QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
1957         cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ) );
1958         //Length
1959         if( e->GetType()==SMDSAbs_Edge){
1960           afunctor.reset( new SMESH::Controls::Length() );
1961           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1962           afunctor->SetPrecision( cprecision );
1963           QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
1964           lenItem->setText( 0, tr( "LENGTH_EDGES" ) );
1965           lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1966         }
1967         if( e->GetType() == SMDSAbs_Face ) {
1968           //Area
1969           afunctor.reset( new SMESH::Controls::Area() );
1970           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1971           afunctor->SetPrecision( cprecision );
1972           QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
1973           areaItem->setText( 0, tr( "AREA_ELEMENTS" ) );
1974           areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ) );
1975           //Taper
1976           if ( e->NbNodes() == 4 ) // see SMESH_Controls.cxx
1977           {
1978             afunctor.reset( new SMESH::Controls::Taper() );
1979             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1980             afunctor->SetPrecision( cprecision );
1981             QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
1982             taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ) );
1983             taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1984             //Wraping angle
1985             afunctor.reset( new SMESH::Controls::Warping() );
1986             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1987             afunctor->SetPrecision( cprecision );
1988             QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
1989             warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
1990             warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1991           }
1992           //AspectRatio2D
1993           if ( !e->IsPoly() )
1994           {
1995             afunctor.reset( new SMESH::Controls::AspectRatio() );
1996             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1997             QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
1998             ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
1999             ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2000           }
2001           //Minimum angle
2002           afunctor.reset( new SMESH::Controls::MinimumAngle() );
2003           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2004           afunctor->SetPrecision( cprecision );
2005           QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
2006           minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ) );
2007           minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2008           //Skew
2009           if ( e->NbNodes() == 3 || e->NbNodes() == 4 )
2010           {
2011             afunctor.reset( new SMESH::Controls::Skew() );
2012             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2013             afunctor->SetPrecision( cprecision );
2014             QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
2015             skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
2016             skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2017           }
2018           //ElemDiam2D
2019           if ( !e->IsPoly() )
2020           {
2021             afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
2022             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2023             QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
2024             diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
2025             diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2026           }
2027         }
2028         if( e->GetType() == SMDSAbs_Volume ) {
2029           if ( !e->IsPoly() )
2030           {
2031             //AspectRatio3D
2032             afunctor.reset( new SMESH::Controls::AspectRatio3D() );
2033             afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2034             QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
2035             ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
2036             ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2037           }
2038           //Volume
2039           afunctor.reset( new SMESH::Controls::Volume() );
2040           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2041           QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
2042           volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ) );
2043           volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2044           //ElementDiameter3D
2045           afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
2046           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2047           QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
2048           diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) );
2049           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2050         }
2051
2052         // gravity center
2053         XYZ gc = gravityCenter( e );
2054         QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
2055         gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) );
2056         QTreeWidgetItem* xItem = createItem( gcItem );
2057         xItem->setText( 0, "X" );
2058         xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2059         QTreeWidgetItem* yItem = createItem( gcItem );
2060         yItem->setText( 0, "Y" );
2061         yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2062         QTreeWidgetItem* zItem = createItem( gcItem );
2063         zItem->setText( 0, "Z" );
2064         zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2065
2066         // normal vector
2067         if( e->GetType() == SMDSAbs_Face ) {
2068           XYZ gc = normal( e );
2069           QTreeWidgetItem* nItem = createItem( elemItem, Bold );
2070           nItem->setText( 0, SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" ) );
2071           QTreeWidgetItem* xItem = createItem( nItem );
2072           xItem->setText( 0, "X" );
2073           xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2074           QTreeWidgetItem* yItem = createItem( nItem );
2075           yItem->setText( 0, "Y" );
2076           yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2077           QTreeWidgetItem* zItem = createItem( nItem );
2078           zItem->setText( 0, "Z" );
2079           zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2080         }
2081
2082         // element position
2083         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
2084         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
2085           if ( !CORBA::is_nil( aMesh ) ) {
2086             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
2087             int shapeID = pos.shapeID;
2088             if ( shapeID > 0 ) {
2089               QTreeWidgetItem* shItem = createItem( elemItem, Bold );
2090               QString shapeType;
2091               switch ( pos.shapeType ) {
2092               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
2093               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
2094               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
2095               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
2096               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
2097               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
2098               }
2099               shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ) );
2100               shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ) );
2101             }
2102           }
2103         }
2104         // groups element belongs to
2105         if ( !CORBA::is_nil( aMesh ) ) {
2106           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
2107           QTreeWidgetItem* groupsItem = 0;
2108           for ( CORBA::ULong i = 0; i < groups->length(); i++ ) {
2109             SMESH::SMESH_GroupBase_var aGrp = groups[i];
2110             if ( CORBA::is_nil( aGrp ) ) continue;
2111             QString aName = aGrp->GetName();
2112             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
2113               if ( !groupsItem ) {
2114                 groupsItem = createItem( elemItem, Bold );
2115                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
2116               }
2117               QTreeWidgetItem* it = createItem( groupsItem, Bold );
2118               it->setText( 0, aName.trimmed() );
2119               if ( grp_details ) {
2120                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
2121                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
2122                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
2123                 
2124                 // type : group on geometry, standalone group, group on filter
2125                 QTreeWidgetItem* typeItem = createItem( it );
2126                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
2127                 if ( !CORBA::is_nil( aStdGroup ) ) {
2128                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
2129                 }
2130                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
2131                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
2132                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2133                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2134                   if ( sobj ) {
2135                     QTreeWidgetItem* gobjItem = createItem( typeItem );
2136                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
2137                     gobjItem->setText( 1, sobj->GetName().c_str() );
2138                   }
2139                 }
2140                 else if ( !CORBA::is_nil( aFltGroup ) ) {
2141                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
2142                 }
2143                 
2144                 // size
2145                 QTreeWidgetItem* sizeItem = createItem( it );
2146                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
2147                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
2148                 
2149                 // color
2150                 SALOMEDS::Color color = aGrp->GetColor();
2151                 QTreeWidgetItem* colorItem = createItem( it );
2152                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
2153                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2154               }
2155             }
2156           }
2157         }
2158       }
2159     }
2160   }
2161 }
2162
2163 /*!
2164   \brief Show node information
2165   \param node mesh node for showing
2166   \param index index of current node
2167   \param nbNodes number of unique nodes in element
2168   \param parentItem parent item of tree
2169 */
2170 void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* node, int index,
2171                                       int nbNodes, QTreeWidgetItem* parentItem )
2172 {
2173   int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
2174   // node number and ID
2175   QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
2176   nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( index ).arg( nbNodes ) );
2177   nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
2178   nodeItem->setData( 1, TypeRole, ElemConnectivity );
2179   nodeItem->setData( 1, IdRole, node->GetID() );
2180   nodeItem->setExpanded( false );
2181   // node coordinates
2182   QTreeWidgetItem* coordItem = createItem( nodeItem );
2183   coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
2184   QTreeWidgetItem* xItem = createItem( coordItem );
2185   xItem->setText( 0, "X" );
2186   xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2187   QTreeWidgetItem* yItem = createItem( coordItem );
2188   yItem->setText( 0, "Y" );
2189   yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2190   QTreeWidgetItem* zItem = createItem( coordItem );
2191   zItem->setText( 0, "Z" );
2192   zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2193   // node connectivity
2194   QTreeWidgetItem* nconItem = createItem( nodeItem );
2195   nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
2196   Connectivity connectivity = nodeConnectivity( node );
2197   if ( !connectivity.isEmpty() ) {
2198     QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
2199     if ( !con.isEmpty() ) {
2200       QTreeWidgetItem* i = createItem( nconItem );
2201       i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
2202       i->setText( 1, con );
2203     }
2204     con = formatConnectivity( connectivity, SMDSAbs_Edge );
2205     if ( !con.isEmpty() ) {
2206       QTreeWidgetItem* i = createItem( nconItem );
2207       i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
2208       i->setText( 1, con );
2209       i->setData( 1, TypeRole, NodeConnectivity );
2210     }
2211     con = formatConnectivity( connectivity, SMDSAbs_Ball );
2212     if ( !con.isEmpty() ) {
2213       QTreeWidgetItem* i = createItem( nconItem );
2214       i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
2215       i->setText( 1, con );
2216       i->setData( 1, TypeRole, NodeConnectivity );
2217     }
2218     con = formatConnectivity( connectivity, SMDSAbs_Face );
2219     if ( !con.isEmpty() ) {
2220       QTreeWidgetItem* i = createItem( nconItem );
2221       i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
2222       i->setText( 1, con );
2223       i->setData( 1, TypeRole, NodeConnectivity );
2224     }
2225     con = formatConnectivity( connectivity, SMDSAbs_Volume );
2226     if ( !con.isEmpty() ) {
2227       QTreeWidgetItem* i = createItem( nconItem );
2228       i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
2229       i->setText( 1, con );
2230       i->setData( 1, TypeRole, NodeConnectivity );
2231     }
2232   }
2233 }
2234 /*!
2235   \brief Internal clean-up (reset widget)
2236 */
2237 void SMESHGUI_TreeElemInfo::clearInternal()
2238 {
2239   myInfo->clear();
2240   myInfo->repaint();
2241 }
2242
2243 /*!
2244   \brief Create new tree item.
2245   \param parent parent tree widget item
2246   \param flags item flag
2247   \return new tree widget item
2248 */
2249 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
2250 {
2251   QTreeWidgetItem* item;
2252   if ( parent )
2253     item = new QTreeWidgetItem( parent );
2254   else
2255     item = new QTreeWidgetItem( myInfo );
2256
2257   item->setFlags( item->flags() | Qt::ItemIsEditable );
2258
2259   QFont f = item->font( 0 );
2260   f.setBold( true );
2261   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
2262     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2263       item->setFont( i, f );
2264   }
2265
2266   item->setExpanded( true );
2267   return item;
2268 }
2269
2270 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2271 {
2272   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2273   if ( widgets.isEmpty() ) return;
2274   QTreeWidgetItem* aTreeItem = widgets.first();
2275   int type = aTreeItem->data( 1, TypeRole ).toInt();
2276   int id   = aTreeItem->data( 1, IdRole ).toInt();
2277   QMenu menu;
2278   QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ) );
2279   if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a )
2280     emit( itemInfo( id ) );
2281   else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a )
2282     emit( itemInfo( aTreeItem->text( 1 ) ) );
2283 }
2284
2285 void  SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
2286 {
2287   if ( theItem ) {
2288     int type = theItem->data( 1, TypeRole ).toInt();
2289     int id   = theItem->data( 1, IdRole ).toInt();
2290     if ( type == ElemConnectivity && id > 0 )
2291       emit( itemInfo( id ) );
2292     else if ( type == NodeConnectivity )
2293       emit( itemInfo( theItem->text( 1 ) ) );
2294   }
2295 }
2296
2297 void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
2298 {
2299   out << QString( 12, '-' ) << "\n";
2300   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
2301   out << QString( 12, '-' ) << "\n";
2302
2303   QTreeWidgetItemIterator it( myInfo );
2304   while ( *it ) {
2305     if ( !( *it )->text(0).isEmpty() ) {
2306       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2307       if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1);
2308       out << "\n";
2309     }
2310     ++it;
2311   }
2312   out << "\n";
2313 }
2314
2315 /*!
2316   \class GrpComputor
2317   \brief Mesh information computer
2318   \internal
2319   
2320   The class is created for different computation operation. Currently it is used
2321   to compute number of underlying nodes for the groups.
2322 */
2323
2324 /*!
2325   \brief Contructor
2326 */
2327 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp,
2328                           QTreeWidgetItem*           item,
2329                           QObject*                   parent,
2330                           bool                       toComputeSize)
2331   : QObject( parent ), myItem( item ), myToComputeSize( toComputeSize )
2332 {
2333   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
2334 }
2335
2336 /*!
2337   \brief Compute function
2338 */
2339 void GrpComputor::compute()
2340 {
2341   if ( !CORBA::is_nil( myGroup ) && myItem ) {
2342     SUIT_OverrideCursor wc;
2343     QTreeWidgetItem* item = myItem;
2344     myItem = 0;
2345     int nb = myToComputeSize ? myGroup->Size() : myGroup->GetNumberOfNodes();
2346     item->treeWidget()->removeItemWidget( item, 1 );
2347     item->setText( 1, QString::number( nb ));
2348   }
2349 }
2350
2351 /*!
2352   \class SMESHGUI_AddInfo
2353   \brief The wigdet shows additional information on the mesh object.
2354 */
2355
2356 /*!
2357   \brief Constructor
2358   \param parent parent widget
2359 */
2360 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2361 : QTreeWidget( parent )
2362 {
2363   setColumnCount( 2 );
2364   header()->setStretchLastSection( true );
2365 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
2366   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2367 #else
2368   header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2369 #endif
2370   header()->hide();
2371 }
2372
2373 /*!
2374   \brief Destructor
2375 */
2376 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2377 {
2378 }
2379
2380 /*!
2381   \brief Show additional information on the selected object
2382   \param obj object being processed (mesh, sub-mesh, group, ID source)
2383 */
2384 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2385 {
2386   setProperty( "group_index", 0 );
2387   setProperty( "submesh_index",  0 );
2388   myComputors.clear();
2389   clear();
2390
2391   if ( CORBA::is_nil( obj ) ) return;
2392
2393   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2394   if ( !sobj ) return;
2395
2396   // name
2397   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2398   nameItem->setText( 0, tr( "NAME" ) );
2399   nameItem->setText( 1, sobj->GetName().c_str() );
2400   
2401   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2402   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2403   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2404   
2405   if ( !aMesh->_is_nil() )
2406     meshInfo( aMesh, nameItem );
2407   else if ( !aSubMesh->_is_nil() )
2408     subMeshInfo( aSubMesh, nameItem );
2409   else if ( !aGroup->_is_nil() )
2410     groupInfo( aGroup.in(), nameItem );
2411 }
2412
2413 /*!
2414   \brief Create new tree item.
2415   \param parent parent tree widget item
2416   \param flags item flag
2417   \return new tree widget item
2418 */
2419 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2420 {
2421   QTreeWidgetItem* item;
2422
2423   if ( parent )
2424     item = new QTreeWidgetItem( parent );
2425   else
2426     item = new QTreeWidgetItem( this );
2427
2428   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2429
2430   QFont f = item->font( 0 );
2431   f.setBold( true );
2432   for ( int i = 0; i < columnCount(); i++ ) {
2433     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2434       item->setFont( i, f );
2435   }
2436
2437   item->setExpanded( true );
2438   return item;
2439 }
2440
2441 /*!
2442   \brief Show mesh info
2443   \param mesh mesh object
2444   \param parent parent tree item
2445 */
2446 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2447 {
2448   // type
2449   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2450   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2451   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2452   typeItem->setText( 0, tr( "TYPE" ) );
2453   if ( !CORBA::is_nil( shape ) ) {
2454     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2455     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2456     if ( sobj ) {
2457       QTreeWidgetItem* gobjItem = createItem( typeItem );
2458       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2459       gobjItem->setText( 1, sobj->GetName().c_str() );
2460     }
2461   }
2462   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2463     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2464     QTreeWidgetItem* fileItem = createItem( typeItem );
2465     fileItem->setText( 0, tr( "FILE_NAME" ) );
2466     fileItem->setText( 1, (char*)inf->fileName );
2467   }
2468   else {
2469     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2470   }
2471   
2472   // groups
2473   myGroups = mesh->GetGroups();
2474   showGroups();
2475
2476   // sub-meshes
2477   mySubMeshes = mesh->GetSubMeshes();
2478   showSubMeshes();
2479 }
2480
2481 /*!
2482   \brief Show sub-mesh info
2483   \param subMesh sub-mesh object
2484   \param parent parent tree item
2485 */
2486 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2487 {
2488   bool isShort = parent->parent() != 0;
2489
2490   if ( !isShort ) {
2491     // parent mesh
2492     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2493     if ( sobj ) {
2494       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2495       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2496       nameItem->setText( 1, sobj->GetName().c_str() );
2497     }
2498   }
2499   
2500   // shape
2501   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2502   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2503   if ( sobj ) {
2504     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2505     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2506     gobjItem->setText( 1, sobj->GetName().c_str() );
2507   }
2508 }
2509
2510 /*!
2511   \brief Show group info
2512   \param grp mesh group object
2513   \param parent parent tree item
2514 */
2515 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2516 {
2517   bool isShort = parent->parent() != 0;
2518
2519   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2520   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2521   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2522
2523   if ( !isShort ) {
2524     // parent mesh
2525     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2526     if ( sobj ) {
2527       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2528       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2529       nameItem->setText( 1, sobj->GetName().c_str() );
2530     }
2531   }
2532
2533   // type : group on geometry, standalone group, group on filter
2534   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2535   typeItem->setText( 0, tr( "TYPE" ) );
2536   if ( !CORBA::is_nil( aStdGroup ) ) {
2537     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2538   }
2539   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2540     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2541     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2542     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2543     if ( sobj ) {
2544       QTreeWidgetItem* gobjItem = createItem( typeItem );
2545       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2546       gobjItem->setText( 1, sobj->GetName().c_str() );
2547     }
2548   }
2549   else if ( !CORBA::is_nil( aFltGroup ) ) {
2550     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2551   }
2552
2553   if ( !isShort ) {
2554     // entity type
2555     QString etype = tr( "UNKNOWN" );
2556     switch( grp->GetType() ) {
2557     case SMESH::NODE:
2558       etype = tr( "NODE" );
2559       break;
2560     case SMESH::EDGE:
2561       etype = tr( "EDGE" );
2562       break;
2563     case SMESH::FACE:
2564       etype = tr( "FACE" );
2565       break;
2566     case SMESH::VOLUME:
2567       etype = tr( "VOLUME" );
2568       break;
2569     case SMESH::ELEM0D:
2570       etype = tr( "0DELEM" );
2571       break;
2572     case SMESH::BALL:
2573       etype = tr( "BALL" );
2574       break;
2575     default:
2576       break;
2577     }
2578     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2579     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2580     etypeItem->setText( 1, etype );
2581   }
2582
2583   SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2584   bool            meshLoaded = mesh->IsLoaded();
2585
2586   // size. Don't call grp->Size() for GroupOnFilter - issue IPAL52831
2587   int groupSize = -1;
2588   if ( grp->IsNodeInfoAvailable() || CORBA::is_nil( aFltGroup ))
2589     groupSize = grp->Size();
2590
2591   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2592   sizeItem->setText( 0, tr( "SIZE" ) );
2593   if ( groupSize > -1 ) {
2594     sizeItem->setText( 1, QString::number( groupSize ) );
2595   }
2596   else {
2597     QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2598     setItemWidget( sizeItem, 1, btn );
2599     GrpComputor* comp = new GrpComputor( grp, sizeItem, this, /*size=*/true );
2600     connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2601     myComputors.append( comp );
2602     if ( !meshLoaded )
2603       connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2604   }
2605
2606   // color
2607   SALOMEDS::Color color = grp->GetColor();
2608   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2609   colorItem->setText( 0, tr( "COLOR" ) );
2610   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2611
2612   // nb of underlying nodes
2613   if ( grp->GetType() != SMESH::NODE) {
2614     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2615     nodesItem->setText( 0, tr( "NB_NODES" ) );
2616     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2617     bool toShowNodes = groupSize >= 0 ? ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || groupSize <= nbNodesLimit ) : false;
2618     if ( toShowNodes && meshLoaded ) {
2619       // already calculated and up-to-date
2620       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2621     }
2622     else {
2623       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2624       setItemWidget( nodesItem, 1, btn );
2625       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2626       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2627       myComputors.append( comp );
2628       if ( !meshLoaded )
2629         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2630     }
2631   }
2632 }
2633
2634 void SMESHGUI_AddInfo::showGroups()
2635 {
2636   myComputors.clear();
2637
2638   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2639   if ( !parent ) return;
2640
2641   int idx = property( "group_index" ).toInt();
2642
2643   QTreeWidgetItem* itemGroups = 0;
2644   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2645     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2646       itemGroups = parent->child( i );
2647       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2648       if ( extra )
2649         extra->updateControls( myGroups->length(), idx );
2650       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2651     }
2652   }
2653
2654   QMap<int, QTreeWidgetItem*> grpItems;
2655   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2656     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2657     if ( CORBA::is_nil( grp ) ) continue;
2658     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2659     if ( !grpSObj ) continue;
2660
2661     int grpType = grp->GetType();
2662
2663     if ( !itemGroups ) {
2664       // create top-level groups container item
2665       itemGroups = createItem( parent, Bold | All );
2666       itemGroups->setText( 0, tr( "GROUPS" ) );
2667       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2668
2669       // total number of groups > 10, show extra widgets for info browsing
2670       if ((int) myGroups->length() > MAXITEMS ) {
2671         ExtraWidget* extra = new ExtraWidget( this, true );
2672         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2673         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2674         setItemWidget( itemGroups, 1, extra );
2675         extra->updateControls( myGroups->length(), idx );
2676       }
2677     }
2678
2679     if ( grpItems.find( grpType ) == grpItems.end() ) {
2680       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2681       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2682       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2683     }
2684   
2685     // group name
2686     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2687     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2688
2689     // group info
2690     groupInfo( grp.in(), grpNameItem );
2691   }
2692 }
2693
2694 void SMESHGUI_AddInfo::showSubMeshes()
2695 {
2696   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2697   if ( !parent ) return;
2698
2699   int idx = property( "submesh_index" ).toInt();
2700
2701   QTreeWidgetItem* itemSubMeshes = 0;
2702   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2703     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2704       itemSubMeshes = parent->child( i );
2705       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2706       if ( extra )
2707         extra->updateControls( mySubMeshes->length(), idx );
2708       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2709     }
2710   }
2711
2712   QMap<int, QTreeWidgetItem*> smItems;
2713   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2714     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2715     if ( CORBA::is_nil( sm ) ) continue;
2716     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2717     if ( !smSObj ) continue;
2718     
2719     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2720     if ( CORBA::is_nil(gobj ) ) continue;
2721     
2722     int smType = gobj->GetShapeType();
2723     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2724
2725     if ( !itemSubMeshes ) {
2726       itemSubMeshes = createItem( parent, Bold | All );
2727       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2728       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2729
2730       // total number of sub-meshes > 10, show extra widgets for info browsing
2731       if ((int) mySubMeshes->length() > MAXITEMS ) {
2732         ExtraWidget* extra = new ExtraWidget( this, true );
2733         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2734         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2735         setItemWidget( itemSubMeshes, 1, extra );
2736         extra->updateControls( mySubMeshes->length(), idx );
2737       }
2738     }
2739          
2740     if ( smItems.find( smType ) == smItems.end() ) {
2741       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2742       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2743       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2744     }
2745     
2746     // submesh name
2747     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2748     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2749     
2750     // submesh info
2751     subMeshInfo( sm.in(), smNameItem );
2752   }
2753 }
2754
2755 /*!
2756  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2757  */
2758 void SMESHGUI_AddInfo::changeLoadToCompute()
2759 {
2760   for ( int i = 0; i < myComputors.count(); ++i )
2761   {
2762     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2763     {
2764       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2765         btn->setText( tr("COMPUTE") );
2766     }
2767   }
2768 }
2769
2770 void SMESHGUI_AddInfo::showPreviousGroups()
2771 {
2772   int idx = property( "group_index" ).toInt();
2773   setProperty( "group_index", idx-1 );
2774   showGroups();
2775 }
2776
2777 void SMESHGUI_AddInfo::showNextGroups()
2778 {
2779   int idx = property( "group_index" ).toInt();
2780   setProperty( "group_index", idx+1 );
2781   showGroups();
2782 }
2783
2784 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2785 {
2786   int idx = property( "submesh_index" ).toInt();
2787   setProperty( "submesh_index", idx-1 );
2788   showSubMeshes();
2789 }
2790
2791 void SMESHGUI_AddInfo::showNextSubMeshes()
2792 {
2793   int idx = property( "submesh_index" ).toInt();
2794   setProperty( "submesh_index", idx+1 );
2795   showSubMeshes();
2796 }
2797
2798 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2799 {
2800   out << QString( 15, '-')       << "\n";
2801   out << tr( "ADDITIONAL_INFO" ) << "\n";
2802   out << QString( 15, '-' )      << "\n";
2803   QTreeWidgetItemIterator it( this );
2804   while ( *it ) {
2805     if ( !( ( *it )->text(0) ).isEmpty() ) {
2806       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2807       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2808         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2809       }
2810       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2811       out << "\n";
2812     }
2813     ++it;
2814   }
2815   out << "\n";
2816 }
2817
2818 /*!
2819   \class SMESHGUI_MeshInfoDlg
2820   \brief Mesh information dialog box
2821 */
2822
2823 /*!
2824   \brief Constructor
2825   \param parent parent widget
2826   \param page specifies the dialog page to be shown at the start-up
2827 */
2828 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2829 : QDialog( parent ), myActor( 0 )
2830 {
2831   setModal( false );
2832   setAttribute( Qt::WA_DeleteOnClose, true );
2833   setWindowTitle( tr( "MESH_INFO" ) );
2834   setSizeGripEnabled( true );
2835
2836   myTabWidget = new QTabWidget( this );
2837
2838   // base info 
2839
2840   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2841   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2842
2843   // elem info 
2844   
2845   QWidget* w = new QWidget( myTabWidget );
2846
2847   myMode = new QButtonGroup( this );
2848   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2849   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2850   myMode->button( NodeMode )->setChecked( true );
2851   myID = new QLineEdit( w );
2852   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2853
2854   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2855   mode = qMin( 1, qMax( 0, mode ) );
2856   
2857   if ( mode == 0 ) 
2858     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2859   else
2860     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2861
2862   QGridLayout* elemLayout = new QGridLayout( w );
2863   elemLayout->setMargin( MARGIN );
2864   elemLayout->setSpacing( SPACING );
2865   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );