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