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