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