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