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