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