Salome HOME
Merge multi-study removal branch.
[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   QStringList aFilters;
3220   aFilters.append( tr( "TEXT_FILES" ));
3221
3222   bool anIsBase = true;
3223   bool anIsElem = true;
3224   bool anIsAdd  = true;
3225   bool anIsCtrl = true;
3226
3227   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
3228     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
3229     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
3230     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
3231     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
3232   }
3233
3234   DumpFileDlg fd( this );
3235   fd.setWindowTitle( tr( "SAVE_INFO" ));
3236   fd.setNameFilters( aFilters );
3237   fd.myBaseChk->setChecked( anIsBase );
3238   fd.myElemChk->setChecked( anIsElem );
3239   fd.myAddChk ->setChecked( anIsAdd );
3240   fd.myCtrlChk->setChecked( anIsCtrl );
3241   if ( fd.exec() == QDialog::Accepted )
3242   {
3243     QString aFileName = fd.selectedFile();
3244
3245     bool toBase = fd.myBaseChk->isChecked();
3246     bool toElem = fd.myElemChk->isChecked();
3247     bool toAdd  = fd.myAddChk->isChecked();
3248     bool toCtrl = fd.myCtrlChk->isChecked();
3249
3250     if ( !aFileName.isEmpty() ) {
3251       QFileInfo aFileInfo( aFileName );
3252       if ( aFileInfo.isDir() )
3253         return;
3254  
3255       QFile aFile( aFileName );
3256       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ))
3257         return;
3258       
3259       QTextStream out( &aFile );
3260       
3261       if ( toBase ) myBaseInfo->saveInfo( out );
3262       if ( toElem ) myElemInfo->saveInfo( out );
3263       if ( toAdd )  myAddInfo ->saveInfo( out );
3264       if ( toCtrl ) myCtrlInfo->saveInfo( out );
3265     }
3266   }
3267 }
3268
3269 /*!
3270   \class SMESHGUI_CtrlInfo
3271   \brief Class for the mesh controls information widget.
3272 */
3273
3274 /*!
3275   \brief Constructor
3276   \param parent parent widget
3277 */
3278 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
3279   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
3280 {
3281   setFrameStyle( StyledPanel | Sunken );
3282
3283   myMainLayout = new QGridLayout( this );
3284   myMainLayout->setMargin( MARGIN );
3285   myMainLayout->setSpacing( SPACING );
3286
3287   // name
3288   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
3289   QLabel* aName = createField();
3290   aName->setMinimumWidth( 150 );
3291   myWidgets << aName;
3292
3293   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3294   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" )) );
3295
3296   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3297
3298   // nodes info
3299   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3300   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3301   QLabel* aNodesFree = createField();
3302   myWidgets << aNodesFree;
3303   myPredicates << aFilterMgr->CreateFreeNodes();
3304   //
3305   QLabel* aNodesNbConnLab = new QLabel( tr( "MAX_NODE_CONNECTIVITY" ), this );
3306   QLabel* aNodesNbConn = createField();
3307   myWidgets << aNodesNbConn;
3308   myNodeConnFunctor = aFilterMgr->CreateNodeConnectivityNumber();
3309   //
3310   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3311   QLabel* aNodesDouble = createField();
3312   myWidgets << aNodesDouble;
3313   myPredicates << aFilterMgr->CreateEqualNodes();
3314   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3315   myToleranceWidget = new SMESHGUI_SpinBox( this );
3316   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3317   myToleranceWidget->setAcceptNames( false );
3318   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ));
3319
3320   // edges info
3321   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3322   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3323   QLabel* anEdgesDouble = createField();
3324   myWidgets << anEdgesDouble;
3325   myPredicates << aFilterMgr->CreateEqualEdges();
3326
3327   // faces info
3328   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3329   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3330   QLabel* aFacesDouble = createField();
3331   myWidgets << aFacesDouble;
3332   myPredicates << aFilterMgr->CreateEqualFaces();
3333   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3334   QLabel* aFacesOver = createField();
3335   myWidgets << aFacesOver;
3336   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3337   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3338   myPlot = createPlot( this );
3339   myAspectRatio = aFilterMgr->CreateAspectRatio();
3340  
3341   // volumes info
3342   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3343   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3344   QLabel* aVolumesDouble = createField();
3345   myWidgets << aVolumesDouble;
3346   myPredicates << aFilterMgr->CreateEqualVolumes();
3347   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3348   QLabel* aVolumesOver = createField();
3349   myWidgets << aVolumesOver;
3350   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3351   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3352   myPlot3D = createPlot( this );
3353   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3354
3355   QToolButton* aFreeNodesBtn = new QToolButton( this );
3356   aFreeNodesBtn->setIcon(aComputeIcon);
3357   myButtons << aFreeNodesBtn;       //0
3358
3359   QToolButton* aNodesNbConnBtn = new QToolButton( this );
3360   aNodesNbConnBtn->setIcon(aComputeIcon);
3361   myButtons << aNodesNbConnBtn;     //1
3362
3363   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3364   aDoubleNodesBtn->setIcon(aComputeIcon);
3365   myButtons << aDoubleNodesBtn;     //2
3366
3367   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3368   aDoubleEdgesBtn->setIcon(aComputeIcon);
3369   myButtons << aDoubleEdgesBtn;     //3
3370
3371   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3372   aDoubleFacesBtn->setIcon(aComputeIcon);
3373   myButtons << aDoubleFacesBtn;     //4
3374
3375   QToolButton* aOverContFacesBtn = new QToolButton( this );
3376   aOverContFacesBtn->setIcon(aComputeIcon);
3377   myButtons << aOverContFacesBtn;   //5
3378
3379   QToolButton* aComputeFaceBtn = new QToolButton( this );
3380   aComputeFaceBtn->setIcon(aComputeIcon);
3381   myButtons << aComputeFaceBtn;     //6
3382
3383   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3384   aDoubleVolumesBtn->setIcon(aComputeIcon);
3385   myButtons << aDoubleVolumesBtn;   //7
3386
3387   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3388   aOverContVolumesBtn->setIcon(aComputeIcon);
3389   myButtons << aOverContVolumesBtn; //8
3390
3391   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3392   aComputeVolumeBtn->setIcon(aComputeIcon);
3393   myButtons << aComputeVolumeBtn;   //9
3394
3395   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ));
3396   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ));
3397   connect( aFreeNodesBtn,     SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ));
3398   connect( aNodesNbConnBtn,   SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ));
3399   connect( aDoubleNodesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ));
3400   connect( aDoubleEdgesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ));
3401   connect( aDoubleFacesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ));
3402   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ));
3403   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ));
3404   connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ));
3405   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3406
3407   setFontAttributes( aNameLab );
3408   setFontAttributes( aNodesLab );
3409   setFontAttributes( anEdgesLab );
3410   setFontAttributes( aFacesLab );
3411   setFontAttributes( aVolumesLab );
3412
3413   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3414   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3415   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3416   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3417   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3418   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3419   myMainLayout->addWidget( aNodesNbConnLab,    3, 0 );       //6
3420   myMainLayout->addWidget( aNodesNbConn,       3, 1 );       //7
3421   myMainLayout->addWidget( aNodesNbConnBtn,    3, 2 );       //8
3422   myMainLayout->addWidget( aNodesDoubleLab,    4, 0 );       //9
3423   myMainLayout->addWidget( aNodesDouble,       4, 1 );       //10
3424   myMainLayout->addWidget( aDoubleNodesBtn,    4, 2 );       //11
3425   myMainLayout->addWidget( aToleranceLab,      5, 0 );       //12
3426   myMainLayout->addWidget( myToleranceWidget,  5, 1 );       //13
3427   myMainLayout->addWidget( anEdgesLab,         6, 0, 1, 3 ); //14
3428   myMainLayout->addWidget( anEdgesDoubleLab,   7, 0 );       //15
3429   myMainLayout->addWidget( anEdgesDouble,      7, 1 );       //16
3430   myMainLayout->addWidget( aDoubleEdgesBtn,    7, 2 );       //17
3431   myMainLayout->addWidget( aFacesLab,          8, 0, 1, 3 ); //18
3432   myMainLayout->addWidget( aFacesDoubleLab,    9, 0 );       //19
3433   myMainLayout->addWidget( aFacesDouble,       9, 1 );       //20
3434   myMainLayout->addWidget( aDoubleFacesBtn,    9, 2 );       //21
3435   myMainLayout->addWidget( aFacesOverLab,      10, 0 );      //22
3436   myMainLayout->addWidget( aFacesOver,         10, 1 );      //23
3437   myMainLayout->addWidget( aOverContFacesBtn,  10, 2 );      //24
3438   myMainLayout->addWidget( anAspectRatioLab,   11, 0 );      //25
3439   myMainLayout->addWidget( aComputeFaceBtn,    11, 2 );      //26
3440   myMainLayout->addWidget( myPlot,             12, 0, 1, 3 );//27
3441   myMainLayout->addWidget( aVolumesLab,        13, 0, 1, 3 );//28
3442   myMainLayout->addWidget( aVolumesDoubleLab,  14, 0 );      //29
3443   myMainLayout->addWidget( aVolumesDouble,     14, 1 );      //30
3444   myMainLayout->addWidget( aDoubleVolumesBtn,  14, 2 );      //31
3445   myMainLayout->addWidget( aVolumesOverLab,    15, 0 );      //32
3446   myMainLayout->addWidget( aVolumesOver,       15, 1 );      //33
3447   myMainLayout->addWidget( aOverContVolumesBtn,15, 2 );      //34
3448   myMainLayout->addWidget( anAspectRatio3DLab, 16, 0 );      //35
3449   myMainLayout->addWidget( aComputeVolumeBtn,  16, 2 );      //36
3450   myMainLayout->addWidget( myPlot3D,           17, 0, 1, 3 );//37
3451  
3452   myMainLayout->setColumnStretch(  0,  0 );
3453   myMainLayout->setColumnStretch(  1,  5 );
3454   myMainLayout->setRowStretch   ( 11,  5 );
3455   myMainLayout->setRowStretch   ( 16,  5 );
3456   myMainLayout->setRowStretch   ( 17,  1 );
3457
3458   clearInternal();
3459 }
3460
3461 /*!
3462   \brief Destructor
3463 */
3464 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3465 {}
3466
3467 /*!
3468   \brief Change widget font attributes (bold, ...).
3469   \param w widget
3470   \param attr font attributes (XORed flags)
3471 */
3472 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3473 {
3474   if ( w ) {
3475     QFont f = w->font();
3476     f.setBold( true );
3477     w->setFont( f );
3478   }
3479 }
3480
3481 /*!
3482   \brief Create info field
3483   \return new info field
3484 */
3485 QLabel* SMESHGUI_CtrlInfo::createField()
3486 {
3487   QLabel* lab = new QLabel( this );
3488   lab->setFrameStyle( StyledPanel | Sunken );
3489   lab->setAlignment( Qt::AlignCenter );
3490   lab->setAutoFillBackground( true );
3491   QPalette pal = lab->palette();
3492   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ));
3493   lab->setPalette( pal );
3494   lab->setMinimumWidth( 60 );
3495   return lab;
3496 }
3497
3498 /*!
3499   \brief Create QwtPlot
3500   \return new QwtPlot
3501 */
3502 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3503 {
3504   QwtPlot* aPlot = new QwtPlot( parent );
3505   aPlot->setMinimumSize( 100, 100 );
3506   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3507   xFont.setPointSize( 5 );
3508   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3509   yFont.setPointSize( 5 );
3510   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3511   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3512   aPlot->replot();
3513   return aPlot;
3514 }
3515
3516 /*!
3517   \brief Show controls information on the selected object
3518 */
3519 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3520 {
3521   clearInternal();
3522
3523   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3524   if ( myObject->_is_nil() ) return;
3525
3526   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3527     myWidgets[0]->setText( aSO->GetName().c_str() );
3528
3529   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3530   if ( mesh->_is_nil() ) return;
3531
3532   const bool meshLoaded = mesh->IsLoaded();
3533   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3534     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3535     for ( int i = 0; i < myButtons.count(); ++i )
3536       myButtons[i]->setEnabled( true );
3537
3538   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3539   if ( ! &nbElemsByType.in() ) return;
3540
3541   const CORBA::Long ctrlLimit =
3542     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3543
3544   // nodes info
3545   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3546   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3547                                 nbElemsByType[ SMESH::FACE ] +
3548                                 nbElemsByType[ SMESH::VOLUME ] );
3549   if ( nbNodes + nbElems > 0 ) {
3550     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3551       // free nodes
3552       computeFreeNodesInfo();
3553       computeNodesNbConnInfo();
3554       // double nodes
3555       if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
3556         computeDoubleNodesInfo();
3557     }
3558     else {
3559       myButtons[0]->setEnabled( true );
3560       myButtons[1]->setEnabled( true );
3561       myButtons[2]->setEnabled( true );
3562     }
3563   }
3564   else {
3565     for( int i=2; i<=11; i++)
3566       myMainLayout->itemAt(i)->widget()->setVisible( false );
3567   }
3568
3569   // edges info
3570   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3571     // double edges
3572     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3573       computeDoubleEdgesInfo();
3574     else
3575       myButtons[3]->setEnabled( true );
3576   }
3577   else {
3578     for( int i=11; i<=14; i++)
3579       myMainLayout->itemAt(i)->widget()->setVisible( false );
3580   }
3581  
3582   // faces info
3583   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3584     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3585       // double faces
3586       computeDoubleFacesInfo();
3587       // over constrained faces
3588       computeOverConstrainedFacesInfo();
3589       // aspect Ratio histogram
3590       computeAspectRatio();
3591     }
3592     else {
3593       myButtons[4]->setEnabled( true );
3594       myButtons[5]->setEnabled( true );
3595       myButtons[6]->setEnabled( true );
3596     }
3597 #ifdef DISABLE_PLOT2DVIEWER
3598     myMainLayout->setRowStretch(12,0);
3599     for( int i=25; i<=27; i++)
3600       myMainLayout->itemAt(i)->widget()->setVisible( false );
3601 #endif
3602   }
3603   else {
3604     myMainLayout->setRowStretch(12,0);
3605     for( int i=18; i<=27; i++)
3606       myMainLayout->itemAt(i)->widget()->setVisible( false );
3607   }
3608
3609   // volumes info
3610   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3611     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3612       // double volumes
3613       computeDoubleVolumesInfo();
3614       // over constrained volumes
3615       computeOverConstrainedVolumesInfo();
3616       // aspect Ratio 3D histogram
3617       computeAspectRatio3D();
3618      }
3619      else {
3620        myButtons[7]->setEnabled( true );
3621        myButtons[8]->setEnabled( true );
3622        myButtons[9]->setEnabled( true );
3623      }
3624 #ifdef DISABLE_PLOT2DVIEWER
3625     myMainLayout->setRowStretch(17,0);
3626     for( int i=35; i<=37; i++)
3627       myMainLayout->itemAt(i)->widget()->setVisible( false );
3628 #endif
3629   }
3630   else {
3631     myMainLayout->setRowStretch(17,0);
3632     for( int i=28; i<=37; i++)
3633       myMainLayout->itemAt(i)->widget()->setVisible( false );
3634   }
3635 }
3636
3637 //================================================================================
3638 /*!
3639  * \brief Computes and shows nb of elements satisfying a given predicate
3640  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3641  *  \param [in] iBut - index of one of myButtons to disable
3642  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3643  */
3644 //================================================================================
3645
3646 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3647 {
3648   myButtons[ iBut ]->setEnabled( false );
3649   myWidgets[ iWdg ]->setText( "" );
3650   if ( myObject->_is_nil() ) return;
3651
3652   SUIT_OverrideCursor wc;
3653
3654   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3655   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3656   {
3657     mesh->Load();
3658     this->showInfo( myObject ); // try to show all values
3659     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3660       return; // <ft> predicate already computed
3661   }
3662   // look for a predicate of type <ft>
3663   for ( int i = 0; i < myPredicates.count(); ++i )
3664     if ( myPredicates[i]->GetFunctorType() == ft )
3665     {
3666       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3667       myWidgets[ iWdg ]->setText( QString::number( nb ));
3668     }
3669 }
3670
3671 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3672 {
3673   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3674 }
3675
3676 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3677 {
3678   computeNb( SMESH::FT_EqualNodes, 2, 3 );
3679 }
3680
3681 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3682 {
3683   computeNb( SMESH::FT_EqualEdges, 3, 4 );
3684 }
3685
3686 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3687 {
3688   computeNb( SMESH::FT_EqualFaces, 4, 5 );
3689 }
3690
3691 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3692 {
3693   computeNb( SMESH::FT_OverConstrainedFace, 5, 6 );
3694 }
3695
3696 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3697 {
3698   computeNb( SMESH::FT_EqualVolumes, 7, 7 );
3699 }
3700
3701 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3702 {
3703   computeNb( SMESH::FT_OverConstrainedVolume, 8, 8 );
3704 }
3705
3706 void SMESHGUI_CtrlInfo::computeNodesNbConnInfo()
3707 {
3708   myButtons[ 1 ]->setEnabled( false );
3709   myWidgets[ 2 ]->setText( "" );
3710   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3711   if ( mesh->_is_nil() ) return;
3712   if ( !mesh->IsLoaded() )
3713   {
3714     mesh->Load();
3715     this->showInfo( myObject ); // try to show all values
3716     if ( !myWidgets[ 2 ]->text().isEmpty() )
3717       return; // already computed
3718   }
3719   myNodeConnFunctor->SetMesh( mesh );
3720   SMESH::Histogram_var histogram =
3721     myNodeConnFunctor->GetLocalHistogram( 1, /*isLogarithmic=*/false, myObject );
3722
3723   myWidgets[ 2 ]->setText( QString::number( histogram[0].max ));
3724 }
3725
3726 void SMESHGUI_CtrlInfo::computeAspectRatio()
3727 {
3728 #ifndef DISABLE_PLOT2DVIEWER
3729   myButtons[6]->setEnabled( false );
3730
3731   if ( myObject->_is_nil() ) return;
3732
3733   SUIT_OverrideCursor wc;
3734
3735   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3736   if ( aHistogram && !aHistogram->isEmpty() ) {
3737     QwtPlotItem* anItem = aHistogram->createPlotItem();
3738     anItem->attach( myPlot );
3739     myPlot->replot();
3740   }
3741   delete aHistogram;
3742 #endif
3743 }
3744
3745 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3746 {
3747 #ifndef DISABLE_PLOT2DVIEWER
3748   myButtons[9]->setEnabled( false );
3749
3750   if ( myObject->_is_nil() ) return;
3751
3752   SUIT_OverrideCursor wc;
3753
3754   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3755   if ( aHistogram && !aHistogram->isEmpty() ) {
3756     QwtPlotItem* anItem = aHistogram->createPlotItem();
3757     anItem->attach( myPlot3D );
3758     myPlot3D->replot();
3759   }
3760   delete aHistogram;
3761 #endif
3762 }
3763
3764 /*!
3765   \brief Internal clean-up (reset widget)
3766 */
3767 void SMESHGUI_CtrlInfo::clearInternal()
3768 {
3769   for( int i=0; i<=35; i++)
3770     myMainLayout->itemAt(i)->widget()->setVisible( true );
3771   for( int i=0; i<=9; i++)
3772     myButtons[i]->setEnabled( false );
3773   myPlot->detachItems();
3774   myPlot3D->detachItems();
3775   myPlot->replot();
3776   myPlot3D->replot();
3777   myWidgets[0]->setText( QString() );
3778   for ( int i = 1; i < myWidgets.count(); i++ )
3779     myWidgets[i]->setText( "" );
3780   myMainLayout->setRowStretch(11,5);
3781   myMainLayout->setRowStretch(16,5);
3782 }
3783
3784 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3785 {
3786   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3787   myButtons[1]->setEnabled( true );
3788   myWidgets[2]->setText("");
3789 }
3790
3791 #ifndef DISABLE_PLOT2DVIEWER
3792 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3793 {
3794   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3795   if ( mesh->_is_nil() ) return 0;
3796   if ( !mesh->IsLoaded() )
3797     mesh->Load();
3798   aNumFun->SetMesh( mesh );
3799
3800   CORBA::Long cprecision = 6;
3801   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false )) 
3802     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3803   aNumFun->SetPrecision( cprecision );
3804
3805   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3806
3807   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3808                                                                   /*isLogarithmic=*/false,
3809                                                                   myObject );
3810   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3811   aHistogram->setColor( palette().color( QPalette::Highlight ));
3812   if ( &histogramVar.in() )
3813   {
3814     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3815       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3816     if ( histogramVar->length() >= 2 )
3817       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3818   }
3819   return aHistogram;
3820 }
3821 #endif
3822
3823 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3824   out << QString( 20, '-' ) << "\n";
3825   out << tr( "CTRL_INFO"  ) << "\n";
3826   out << QString( 20, '-' ) << "\n";
3827   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3828   out <<                                 tr( "NODES_INFO" )                     << "\n";
3829   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3830   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3831   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3832   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3833   out <<                                 tr( "FACES_INFO" )                     << "\n";
3834   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3835   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3836   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3837   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3838   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3839 }
3840
3841 /*!
3842   \class SMESHGUI_CtrlInfoDlg
3843   \brief Controls information dialog box
3844 */
3845
3846 /*!
3847   \brief Constructor
3848   \param parent parent widget
3849 */
3850 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3851 : QDialog( parent )
3852 {
3853   setAttribute( Qt::WA_DeleteOnClose, true );
3854   setWindowTitle( tr( "CTRL_INFO" ));
3855   setMinimumSize( 400, 600 );
3856
3857   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3858   
3859   // buttons
3860   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3861   okBtn->setAutoDefault( true );
3862   okBtn->setDefault( true );
3863   okBtn->setFocus();
3864   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3865   dumpBtn->setAutoDefault( true );
3866   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3867   helpBtn->setAutoDefault( true );
3868
3869   QHBoxLayout* btnLayout = new QHBoxLayout;
3870   btnLayout->setSpacing( SPACING );
3871   btnLayout->setMargin( 0 );
3872
3873   btnLayout->addWidget( okBtn );
3874   btnLayout->addWidget( dumpBtn );
3875   btnLayout->addStretch( 10 );
3876   btnLayout->addWidget( helpBtn );
3877
3878   QVBoxLayout* l = new QVBoxLayout ( this );
3879   l->setMargin( MARGIN );
3880   l->setSpacing( SPACING );
3881   l->addWidget( myCtrlInfo );
3882   l->addLayout( btnLayout );
3883
3884   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ));
3885   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ));
3886   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ));
3887   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ));
3888   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ));
3889
3890   updateSelection();
3891 }
3892
3893 /*!
3894   \brief Destructor
3895 */
3896 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3897 {
3898 }
3899
3900 /*!
3901   \brief Show controls information
3902   \param IO interactive object
3903 */
3904 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3905 {  
3906   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ))
3907     myCtrlInfo->showInfo( obj );
3908 }
3909
3910 /*!
3911   \brief Perform clean-up actions on the dialog box closing.
3912 */
3913 void SMESHGUI_CtrlInfoDlg::reject()
3914 {
3915   SMESH::SetPointRepresentation( false );
3916   QDialog::reject();
3917 }
3918
3919 /*!
3920   \brief Setup selection mode depending on the current dialog box state.
3921 */
3922 void SMESHGUI_CtrlInfoDlg::updateSelection()
3923 {
3924   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3925   disconnect( selMgr, 0, this, 0 );
3926   SMESH::SetPointRepresentation( false );  
3927   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
3928   updateInfo();  
3929 }
3930
3931 /*!
3932   \brief Show mesh information
3933 */
3934 void SMESHGUI_CtrlInfoDlg::updateInfo()
3935 {
3936   SUIT_OverrideCursor wc;
3937
3938   SALOME_ListIO selected;
3939   SMESHGUI::selectionMgr()->selectedObjects( selected );
3940
3941   if ( selected.Extent() == 1 ) {
3942     Handle(SALOME_InteractiveObject) IO = selected.First();
3943     showInfo( IO );
3944   }
3945 }
3946
3947 /*!
3948   \brief Activate dialog box
3949 */
3950 void SMESHGUI_CtrlInfoDlg::activate()
3951 {
3952   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3953   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3954   updateSelection();
3955 }
3956
3957 /*!
3958   \brief Deactivate dialog box
3959 */
3960 void SMESHGUI_CtrlInfoDlg::deactivate()
3961 {
3962   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ));
3963 }
3964
3965 /*!
3966  * \brief Dump contents into a file
3967  */
3968 void SMESHGUI_CtrlInfoDlg::dump()
3969 {
3970   QStringList aFilters;
3971   aFilters.append( tr( "TEXT_FILES" ));
3972
3973   DumpFileDlg fd( this );
3974   fd.setWindowTitle( tr( "SAVE_INFO" ));
3975   fd.setNameFilters( aFilters );
3976   fd.myBaseChk->hide();
3977   fd.myElemChk->hide();
3978   fd.myAddChk ->hide();
3979   fd.myCtrlChk->hide();
3980   if ( fd.exec() == QDialog::Accepted )
3981   {
3982     QString aFileName = fd.selectedFile();
3983     if ( !aFileName.isEmpty() ) {
3984       QFileInfo aFileInfo( aFileName );
3985       if ( aFileInfo.isDir() )
3986         return;
3987  
3988       QFile aFile( aFileName );
3989       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ))
3990         return;
3991       
3992       QTextStream out( &aFile );
3993       myCtrlInfo->saveInfo( out );
3994     }
3995   }
3996 }
3997
3998 /*!
3999  * \brief Show help
4000  */
4001 void SMESHGUI_CtrlInfoDlg::help()
4002 {
4003   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
4004 }