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