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