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