Salome HOME
0023064: [CEA 1471] Create and support quadratic polygons in SMESH
[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, QTreeWidgetItem* item, QObject* parent )
2262   : QObject( parent ), myItem( item )
2263 {
2264   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
2265 }
2266
2267 /*!
2268   \brief Compute function
2269 */
2270 void GrpComputor::compute()
2271 {
2272   if ( !CORBA::is_nil( myGroup ) && myItem ) {
2273     QTreeWidgetItem* item = myItem;
2274     myItem = 0;
2275     int nbNodes = myGroup->GetNumberOfNodes();
2276     item->treeWidget()->removeItemWidget( item, 1 );
2277     item->setText( 1, QString::number( nbNodes ));
2278   }
2279 }
2280
2281 /*!
2282   \class SMESHGUI_AddInfo
2283   \brief The wigdet shows additional information on the mesh object.
2284 */
2285
2286 /*!
2287   \brief Constructor
2288   \param parent parent widget
2289 */
2290 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2291 : QTreeWidget( parent )
2292 {
2293   setColumnCount( 2 );
2294   header()->setStretchLastSection( true );
2295   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2296   header()->hide();
2297 }
2298
2299 /*!
2300   \brief Destructor
2301 */
2302 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2303 {
2304 }
2305
2306 /*!
2307   \brief Show additional information on the selected object
2308   \param obj object being processed (mesh, sub-mesh, group, ID source)
2309 */
2310 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2311 {
2312   setProperty( "group_index", 0 );
2313   setProperty( "submesh_index",  0 );
2314   myComputors.clear();
2315   clear();
2316
2317   if ( CORBA::is_nil( obj ) ) return;
2318
2319   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2320   if ( !sobj ) return;
2321
2322   // name
2323   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2324   nameItem->setText( 0, tr( "NAME" ) );
2325   nameItem->setText( 1, sobj->GetName().c_str() );
2326   
2327   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2328   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2329   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2330   
2331   if ( !aMesh->_is_nil() )
2332     meshInfo( aMesh, nameItem );
2333   else if ( !aSubMesh->_is_nil() )
2334     subMeshInfo( aSubMesh, nameItem );
2335   else if ( !aGroup->_is_nil() )
2336     groupInfo( aGroup.in(), nameItem );
2337 }
2338
2339 /*!
2340   \brief Create new tree item.
2341   \param parent parent tree widget item
2342   \param flags item flag
2343   \return new tree widget item
2344 */
2345 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2346 {
2347   QTreeWidgetItem* item;
2348
2349   if ( parent )
2350     item = new QTreeWidgetItem( parent );
2351   else
2352     item = new QTreeWidgetItem( this );
2353
2354   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2355
2356   QFont f = item->font( 0 );
2357   f.setBold( true );
2358   for ( int i = 0; i < columnCount(); i++ ) {
2359     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2360       item->setFont( i, f );
2361   }
2362
2363   item->setExpanded( true );
2364   return item;
2365 }
2366
2367 /*!
2368   \brief Show mesh info
2369   \param mesh mesh object
2370   \param parent parent tree item
2371 */
2372 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2373 {
2374   // type
2375   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2376   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2377   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2378   typeItem->setText( 0, tr( "TYPE" ) );
2379   if ( !CORBA::is_nil( shape ) ) {
2380     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2381     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2382     if ( sobj ) {
2383       QTreeWidgetItem* gobjItem = createItem( typeItem );
2384       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2385       gobjItem->setText( 1, sobj->GetName().c_str() );
2386     }
2387   }
2388   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2389     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2390     QTreeWidgetItem* fileItem = createItem( typeItem );
2391     fileItem->setText( 0, tr( "FILE_NAME" ) );
2392     fileItem->setText( 1, (char*)inf->fileName );
2393   }
2394   else {
2395     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2396   }
2397   
2398   // groups
2399   myGroups = mesh->GetGroups();
2400   showGroups();
2401
2402   // sub-meshes
2403   mySubMeshes = mesh->GetSubMeshes();
2404   showSubMeshes();
2405 }
2406
2407 /*!
2408   \brief Show sub-mesh info
2409   \param subMesh sub-mesh object
2410   \param parent parent tree item
2411 */
2412 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2413 {
2414   bool isShort = parent->parent() != 0;
2415
2416   if ( !isShort ) {
2417     // parent mesh
2418     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2419     if ( sobj ) {
2420       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2421       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2422       nameItem->setText( 1, sobj->GetName().c_str() );
2423     }
2424   }
2425   
2426   // shape
2427   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2428   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2429   if ( sobj ) {
2430     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2431     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2432     gobjItem->setText( 1, sobj->GetName().c_str() );
2433   }
2434 }
2435
2436 /*!
2437   \brief Show group info
2438   \param grp mesh group object
2439   \param parent parent tree item
2440 */
2441 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2442 {
2443   bool isShort = parent->parent() != 0;
2444
2445   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2446   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2447   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2448
2449   if ( !isShort ) {
2450     // parent mesh
2451     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2452     if ( sobj ) {
2453       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2454       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2455       nameItem->setText( 1, sobj->GetName().c_str() );
2456     }
2457   }
2458
2459   // type : group on geometry, standalone group, group on filter
2460   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2461   typeItem->setText( 0, tr( "TYPE" ) );
2462   if ( !CORBA::is_nil( aStdGroup ) ) {
2463     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2464   }
2465   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2466     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2467     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2468     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2469     if ( sobj ) {
2470       QTreeWidgetItem* gobjItem = createItem( typeItem );
2471       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2472       gobjItem->setText( 1, sobj->GetName().c_str() );
2473     }
2474   }
2475   else if ( !CORBA::is_nil( aFltGroup ) ) {
2476     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2477   }
2478
2479   if ( !isShort ) {
2480     // entity type
2481     QString etype = tr( "UNKNOWN" );
2482     switch( grp->GetType() ) {
2483     case SMESH::NODE:
2484       etype = tr( "NODE" );
2485       break;
2486     case SMESH::EDGE:
2487       etype = tr( "EDGE" );
2488       break;
2489     case SMESH::FACE:
2490       etype = tr( "FACE" );
2491       break;
2492     case SMESH::VOLUME:
2493       etype = tr( "VOLUME" );
2494       break;
2495     case SMESH::ELEM0D:
2496       etype = tr( "0DELEM" );
2497       break;
2498     case SMESH::BALL:
2499       etype = tr( "BALL" );
2500       break;
2501     default:
2502       break;
2503     }
2504     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2505     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2506     etypeItem->setText( 1, etype );
2507   }
2508
2509   // size
2510   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2511   sizeItem->setText( 0, tr( "SIZE" ) );
2512   sizeItem->setText( 1, QString::number( grp->Size() ) );
2513
2514   // color
2515   SALOMEDS::Color color = grp->GetColor();
2516   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2517   colorItem->setText( 0, tr( "COLOR" ) );
2518   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2519
2520   // nb of underlying nodes
2521   if ( grp->GetType() != SMESH::NODE) {
2522     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2523     nodesItem->setText( 0, tr( "NB_NODES" ) );
2524     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2525     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2526     bool meshLoaded = mesh->IsLoaded();
2527     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
2528     if ( toShowNodes && meshLoaded ) {
2529       // already calculated and up-to-date
2530       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2531     }
2532     else {
2533       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2534       setItemWidget( nodesItem, 1, btn );
2535       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2536       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2537       myComputors.append( comp );
2538       if ( !meshLoaded )
2539         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2540     }
2541   }
2542 }
2543
2544 void SMESHGUI_AddInfo::showGroups()
2545 {
2546   myComputors.clear();
2547
2548   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2549   if ( !parent ) return;
2550
2551   int idx = property( "group_index" ).toInt();
2552
2553   QTreeWidgetItem* itemGroups = 0;
2554   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2555     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2556       itemGroups = parent->child( i );
2557       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2558       if ( extra )
2559         extra->updateControls( myGroups->length(), idx );
2560       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2561     }
2562   }
2563
2564   QMap<int, QTreeWidgetItem*> grpItems;
2565   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2566     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2567     if ( CORBA::is_nil( grp ) ) continue;
2568     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2569     if ( !grpSObj ) continue;
2570
2571     int grpType = grp->GetType();
2572
2573     if ( !itemGroups ) {
2574       // create top-level groups container item
2575       itemGroups = createItem( parent, Bold | All );
2576       itemGroups->setText( 0, tr( "GROUPS" ) );
2577       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2578
2579       // total number of groups > 10, show extra widgets for info browsing
2580       if ( myGroups->length() > MAXITEMS ) {
2581         ExtraWidget* extra = new ExtraWidget( this, true );
2582         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2583         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2584         setItemWidget( itemGroups, 1, extra );
2585         extra->updateControls( myGroups->length(), idx );
2586       }
2587     }
2588
2589     if ( grpItems.find( grpType ) == grpItems.end() ) {
2590       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2591       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2592       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2593     }
2594   
2595     // group name
2596     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2597     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2598
2599     // group info
2600     groupInfo( grp.in(), grpNameItem );
2601   }
2602 }
2603
2604 void SMESHGUI_AddInfo::showSubMeshes()
2605 {
2606   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2607   if ( !parent ) return;
2608
2609   int idx = property( "submesh_index" ).toInt();
2610
2611   QTreeWidgetItem* itemSubMeshes = 0;
2612   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2613     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2614       itemSubMeshes = parent->child( i );
2615       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2616       if ( extra )
2617         extra->updateControls( mySubMeshes->length(), idx );
2618       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2619     }
2620   }
2621
2622   QMap<int, QTreeWidgetItem*> smItems;
2623   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2624     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2625     if ( CORBA::is_nil( sm ) ) continue;
2626     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2627     if ( !smSObj ) continue;
2628     
2629     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2630     if ( CORBA::is_nil(gobj ) ) continue;
2631     
2632     int smType = gobj->GetShapeType();
2633     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2634
2635     if ( !itemSubMeshes ) {
2636       itemSubMeshes = createItem( parent, Bold | All );
2637       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2638       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2639
2640       // total number of sub-meshes > 10, show extra widgets for info browsing
2641       if ( mySubMeshes->length() > MAXITEMS ) {
2642         ExtraWidget* extra = new ExtraWidget( this, true );
2643         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2644         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2645         setItemWidget( itemSubMeshes, 1, extra );
2646         extra->updateControls( mySubMeshes->length(), idx );
2647       }
2648     }
2649          
2650     if ( smItems.find( smType ) == smItems.end() ) {
2651       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2652       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2653       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2654     }
2655     
2656     // submesh name
2657     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2658     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2659     
2660     // submesh info
2661     subMeshInfo( sm.in(), smNameItem );
2662   }
2663 }
2664
2665 /*!
2666  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2667  */
2668 void SMESHGUI_AddInfo::changeLoadToCompute()
2669 {
2670   for ( int i = 0; i < myComputors.count(); ++i )
2671   {
2672     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2673     {
2674       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2675         btn->setText( tr("COMPUTE") );
2676     }
2677   }
2678 }
2679
2680 void SMESHGUI_AddInfo::showPreviousGroups()
2681 {
2682   int idx = property( "group_index" ).toInt();
2683   setProperty( "group_index", idx-1 );
2684   showGroups();
2685 }
2686
2687 void SMESHGUI_AddInfo::showNextGroups()
2688 {
2689   int idx = property( "group_index" ).toInt();
2690   setProperty( "group_index", idx+1 );
2691   showGroups();
2692 }
2693
2694 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2695 {
2696   int idx = property( "submesh_index" ).toInt();
2697   setProperty( "submesh_index", idx-1 );
2698   showSubMeshes();
2699 }
2700
2701 void SMESHGUI_AddInfo::showNextSubMeshes()
2702 {
2703   int idx = property( "submesh_index" ).toInt();
2704   setProperty( "submesh_index", idx+1 );
2705   showSubMeshes();
2706 }
2707
2708 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2709 {
2710   out << QString( 15, '-')       << "\n";
2711   out << tr( "ADDITIONAL_INFO" ) << "\n";
2712   out << QString( 15, '-' )      << "\n";
2713   QTreeWidgetItemIterator it( this );
2714   while ( *it ) {
2715     if ( !( ( *it )->text(0) ).isEmpty() ) {
2716       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2717       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2718         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2719       }
2720       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2721       out << "\n";
2722     }
2723     ++it;
2724   }
2725   out << "\n";
2726 }
2727
2728 /*!
2729   \class SMESHGUI_MeshInfoDlg
2730   \brief Mesh information dialog box
2731 */
2732
2733 /*!
2734   \brief Constructor
2735   \param parent parent widget
2736   \param page specifies the dialog page to be shown at the start-up
2737 */
2738 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2739 : QDialog( parent ), myActor( 0 )
2740 {
2741   setModal( false );
2742   setAttribute( Qt::WA_DeleteOnClose, true );
2743   setWindowTitle( tr( "MESH_INFO" ) );
2744   setSizeGripEnabled( true );
2745
2746   myTabWidget = new QTabWidget( this );
2747
2748   // base info 
2749
2750   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2751   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2752
2753   // elem info 
2754   
2755   QWidget* w = new QWidget( myTabWidget );
2756
2757   myMode = new QButtonGroup( this );
2758   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2759   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2760   myMode->button( NodeMode )->setChecked( true );
2761   myID = new QLineEdit( w );
2762   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2763
2764   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2765   mode = qMin( 1, qMax( 0, mode ) );
2766   
2767   if ( mode == 0 ) 
2768     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2769   else
2770     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2771
2772   QGridLayout* elemLayout = new QGridLayout( w );
2773   elemLayout->setMargin( MARGIN );
2774   elemLayout->setSpacing( SPACING );
2775   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2776   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2777   elemLayout->addWidget( myID, 0, 2 );
2778   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2779   
2780   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2781
2782   // additional info
2783
2784   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2785   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2786
2787   // controls info
2788
2789   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
2790   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
2791
2792   // buttons
2793
2794   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2795   okBtn->setAutoDefault( true );
2796   okBtn->setDefault( true );
2797   okBtn->setFocus();
2798   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2799   dumpBtn->setAutoDefault( true );
2800   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2801   helpBtn->setAutoDefault( true );
2802
2803   QHBoxLayout* btnLayout = new QHBoxLayout;
2804   btnLayout->setSpacing( SPACING );
2805   btnLayout->setMargin( 0 );
2806
2807   btnLayout->addWidget( okBtn );
2808   btnLayout->addWidget( dumpBtn );
2809   btnLayout->addStretch( 10 );
2810   btnLayout->addWidget( helpBtn );
2811
2812   QVBoxLayout* l = new QVBoxLayout ( this );
2813   l->setMargin( MARGIN );
2814   l->setSpacing( SPACING );
2815   l->addWidget( myTabWidget );
2816   l->addLayout( btnLayout );
2817
2818   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2819
2820   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2821   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2822   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2823   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2824   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2825   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2826   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2827   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2828   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2829   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2830
2831   updateSelection();
2832 }
2833
2834 /*!
2835   \brief Destructor
2836 */
2837 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2838 {
2839 }
2840
2841 /*!
2842   \brief Show mesh information
2843   \param IO interactive object
2844 */
2845 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2846 {
2847   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2848   if ( !CORBA::is_nil( obj ) ) {
2849     myBaseInfo->showInfo( obj );
2850     myAddInfo->showInfo( obj );
2851     myCtrlInfo->showInfo( obj );
2852
2853     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2854     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2855     QString ID;
2856     int nb = 0;
2857     if ( myActor && selector ) {
2858       nb = myMode->checkedId() == NodeMode ? 
2859         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2860         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2861     }
2862     myElemInfo->setSource( myActor ) ;
2863     if ( nb > 0 ) {
2864       myID->setText( ID.trimmed() );
2865       QSet<long> ids;
2866       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2867       foreach ( ID, idTxt )
2868         ids << ID.trimmed().toLong();
2869       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2870     }
2871     else {
2872       myID->clear();
2873       myElemInfo->clear();
2874     }
2875   }
2876 }
2877
2878 /*!
2879   \brief Perform clean-up actions on the dialog box closing.
2880 */
2881 void SMESHGUI_MeshInfoDlg::reject()
2882 {
2883   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2884   selMgr->clearFilters();
2885   SMESH::SetPointRepresentation( false );
2886   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2887     aViewWindow->SetSelectionMode( ActorSelection );
2888   QDialog::reject();
2889 }
2890
2891 /*!
2892   \brief Process keyboard event
2893   \param e key press event
2894 */
2895 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2896 {
2897   QDialog::keyPressEvent( e );
2898   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2899     e->accept();
2900     help();
2901   }
2902 }
2903
2904 /*!
2905   \brief Reactivate dialog box, when mouse pointer goes into it.
2906 */
2907 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2908 {
2909   //activate();
2910 }
2911
2912 /*!
2913   \brief Setup selection mode depending on the current dialog box state.
2914 */
2915 void SMESHGUI_MeshInfoDlg::updateSelection()
2916 {
2917   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2918
2919   disconnect( selMgr, 0, this, 0 );
2920   selMgr->clearFilters();
2921
2922   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo || myTabWidget->currentIndex() == CtrlInfo ) {
2923     SMESH::SetPointRepresentation( false );
2924     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2925       aViewWindow->SetSelectionMode( ActorSelection );
2926   }
2927   else {
2928     if ( myMode->checkedId() == NodeMode ) {
2929       SMESH::SetPointRepresentation( true );
2930       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2931         aViewWindow->SetSelectionMode( NodeSelection );
2932     }
2933     else {
2934       SMESH::SetPointRepresentation( false );
2935       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2936         aViewWindow->SetSelectionMode( CellSelection );
2937     }
2938   }
2939
2940   QString oldID = myID->text().trimmed();
2941   SMESH_Actor* oldActor = myActor;
2942   myID->clear();
2943   
2944   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2945   updateInfo();
2946   
2947   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
2948     myID->setText( oldID );
2949     idChanged();
2950   }
2951 }
2952
2953 /*!
2954   \brief Show help page
2955 */
2956 void SMESHGUI_MeshInfoDlg::help()
2957 {
2958   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
2959                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
2960                        "mesh_infos_page.html#mesh_element_info_anchor" );
2961 }
2962
2963 /*!
2964   \brief Show mesh information
2965 */
2966 void SMESHGUI_MeshInfoDlg::updateInfo()
2967 {
2968   SUIT_OverrideCursor wc;
2969
2970   SALOME_ListIO selected;
2971   SMESHGUI::selectionMgr()->selectedObjects( selected );
2972
2973   if ( selected.Extent() == 1 ) {
2974     Handle(SALOME_InteractiveObject) IO = selected.First();
2975     showInfo( IO );
2976   }
2977 //   else {
2978 //     myBaseInfo->clear();
2979 //     myElemInfo->clear();
2980 //     myAddInfo->clear();
2981 //   }
2982 }
2983
2984 /*!
2985   \brief Activate dialog box
2986 */
2987 void SMESHGUI_MeshInfoDlg::activate()
2988 {
2989   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
2990   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
2991   myTabWidget->setEnabled( true );
2992   updateSelection();
2993 }
2994
2995 /*!
2996   \brief Deactivate dialog box
2997 */
2998 void SMESHGUI_MeshInfoDlg::deactivate()
2999 {
3000   myTabWidget->setEnabled( false );
3001   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3002 }
3003
3004 /*!
3005   \brief Called when users switches between node / element modes.
3006 */
3007 void SMESHGUI_MeshInfoDlg::modeChanged()
3008 {
3009   myID->clear();
3010   updateSelection();
3011 }
3012
3013 /*!
3014   \brief Caled when users prints mesh element ID in the corresponding field.
3015 */
3016 void SMESHGUI_MeshInfoDlg::idChanged()
3017 {
3018   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
3019   if ( myActor && selector ) {
3020     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
3021     TColStd_MapOfInteger ID;
3022     QSet<long> ids;
3023     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3024     foreach ( QString tid, idTxt ) {
3025       long id = tid.trimmed().toLong();
3026       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
3027         myActor->GetObject()->GetMesh()->FindElement( id ) :
3028         myActor->GetObject()->GetMesh()->FindNode( id );
3029       if ( e ) {
3030         ID.Add( id );
3031         ids << id;
3032       }
3033     }
3034     selector->AddOrRemoveIndex( IO, ID, false );
3035     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
3036       aViewWindow->highlight( IO, true, true );
3037       aViewWindow->Repaint();
3038     }
3039     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
3040   }
3041 }
3042
3043 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
3044 {
3045   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
3046     myMode->button( NodeMode )->click();
3047     myID->setText( QString::number( id ) );
3048   }
3049 }
3050
3051 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
3052 {
3053   if ( !theStr.isEmpty() ) {
3054     myMode->button( ElemMode )->click();
3055     myID->setText( theStr );
3056   }
3057 }
3058
3059 void SMESHGUI_MeshInfoDlg::dump()
3060 {
3061   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3062   if ( !app ) return;
3063   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3064   if ( !appStudy ) return;
3065   _PTR( Study ) aStudy = appStudy->studyDS();
3066
3067   QStringList aFilters;
3068   aFilters.append( tr( "TEXT_FILES" ) );
3069
3070   bool anIsBase = true;
3071   bool anIsElem = true;
3072   bool anIsAdd  = true;
3073   bool anIsCtrl = true;
3074
3075   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
3076     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
3077     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
3078     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
3079     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
3080   }
3081
3082   DumpFileDlg fd( this );
3083   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3084   fd.setFilters( aFilters );
3085   fd.myBaseChk->setChecked( anIsBase );
3086   fd.myElemChk->setChecked( anIsElem );
3087   fd.myAddChk ->setChecked( anIsAdd );
3088   fd.myCtrlChk->setChecked( anIsCtrl );
3089   if ( fd.exec() == QDialog::Accepted )
3090   {
3091     QString aFileName = fd.selectedFile();
3092
3093     bool toBase = fd.myBaseChk->isChecked();
3094     bool toElem = fd.myElemChk->isChecked();
3095     bool toAdd  = fd.myAddChk->isChecked();
3096     bool toCtrl = fd.myCtrlChk->isChecked();
3097
3098     if ( !aFileName.isEmpty() ) {
3099       QFileInfo aFileInfo( aFileName );
3100       if ( aFileInfo.isDir() )
3101         return;
3102  
3103       QFile aFile( aFileName );
3104       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3105         return;
3106       
3107       QTextStream out( &aFile );
3108       
3109       if ( toBase ) myBaseInfo->saveInfo( out );
3110       if ( toElem ) myElemInfo->saveInfo( out );
3111       if ( toAdd )  myAddInfo ->saveInfo( out );
3112       if ( toCtrl ) myCtrlInfo->saveInfo( out );
3113     }
3114   }
3115 }
3116
3117 /*!
3118   \class SMESHGUI_CtrlInfo
3119   \brief Class for the mesh controls information widget.
3120 */
3121
3122 /*!
3123   \brief Constructor
3124   \param parent parent widget
3125 */
3126 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
3127   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
3128 {
3129   setFrameStyle( StyledPanel | Sunken );
3130
3131   myMainLayout = new QGridLayout( this );
3132   myMainLayout->setMargin( MARGIN );
3133   myMainLayout->setSpacing( SPACING );
3134
3135   // name
3136   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
3137   QLabel* aName = createField();
3138   aName->setMinimumWidth( 150 );
3139   myWidgets << aName;
3140
3141   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3142   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3143
3144   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3145
3146   // nodes info
3147   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3148   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3149   QLabel* aNodesFree = createField();
3150   myWidgets << aNodesFree;
3151   myPredicates << aFilterMgr->CreateFreeNodes();
3152   //
3153   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3154   QLabel* aNodesDouble = createField();
3155   myWidgets << aNodesDouble;
3156   myPredicates << aFilterMgr->CreateEqualNodes();
3157   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3158   myToleranceWidget = new SMESHGUI_SpinBox( this );
3159   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3160   myToleranceWidget->setAcceptNames( false );
3161   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3162
3163   // edges info
3164   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3165   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3166   QLabel* anEdgesDouble = createField();
3167   myWidgets << anEdgesDouble;
3168   myPredicates << aFilterMgr->CreateEqualEdges();
3169
3170   // faces info
3171   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3172   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3173   QLabel* aFacesDouble = createField();
3174   myWidgets << aFacesDouble;
3175   myPredicates << aFilterMgr->CreateEqualFaces();
3176   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3177   QLabel* aFacesOver = createField();
3178   myWidgets << aFacesOver;
3179   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3180   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3181   myPlot = createPlot( this );
3182   myAspectRatio = aFilterMgr->CreateAspectRatio();
3183  
3184   // volumes info
3185   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3186   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3187   QLabel* aVolumesDouble = createField();
3188   myWidgets << aVolumesDouble;
3189   myPredicates << aFilterMgr->CreateEqualVolumes();
3190   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3191   QLabel* aVolumesOver = createField();
3192   myWidgets << aVolumesOver;
3193   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3194   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3195   myPlot3D = createPlot( this );
3196   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3197
3198   QToolButton* aFreeNodesBtn = new QToolButton( this );
3199   aFreeNodesBtn->setIcon(aComputeIcon);
3200   myButtons << aFreeNodesBtn;       //0
3201
3202   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3203   aDoubleNodesBtn->setIcon(aComputeIcon);
3204   myButtons << aDoubleNodesBtn;     //1
3205
3206   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3207   aDoubleEdgesBtn->setIcon(aComputeIcon);
3208   myButtons << aDoubleEdgesBtn;     //2
3209
3210   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3211   aDoubleFacesBtn->setIcon(aComputeIcon);
3212   myButtons << aDoubleFacesBtn;     //3
3213
3214   QToolButton* aOverContFacesBtn = new QToolButton( this );
3215   aOverContFacesBtn->setIcon(aComputeIcon);
3216   myButtons << aOverContFacesBtn;   //4
3217
3218   QToolButton* aComputeFaceBtn = new QToolButton( this );
3219   aComputeFaceBtn->setIcon(aComputeIcon);
3220   myButtons << aComputeFaceBtn;     //5
3221
3222   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3223   aDoubleVolumesBtn->setIcon(aComputeIcon);
3224   myButtons << aDoubleVolumesBtn;   //6
3225
3226   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3227   aOverContVolumesBtn->setIcon(aComputeIcon);
3228   myButtons << aOverContVolumesBtn; //7
3229
3230   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3231   aComputeVolumeBtn->setIcon(aComputeIcon);
3232   myButtons << aComputeVolumeBtn;   //8
3233
3234   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3235   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3236   connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3237   connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3238   connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3239   connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3240   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3241   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3242   connect( aOverContVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3243   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3244
3245   setFontAttributes( aNameLab );
3246   setFontAttributes( aNodesLab );
3247   setFontAttributes( anEdgesLab );
3248   setFontAttributes( aFacesLab );
3249   setFontAttributes( aVolumesLab );
3250
3251   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3252   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3253   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3254   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3255   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3256   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3257   myMainLayout->addWidget( aNodesDoubleLab,    3, 0 );       //6
3258   myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
3259   myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
3260   myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
3261   myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
3262   myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
3263   myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
3264   myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
3265   myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
3266   myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
3267   myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
3268   myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
3269   myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
3270   myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
3271   myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
3272   myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
3273   myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
3274   myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
3275   myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
3276   myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
3277   myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
3278   myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
3279   myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
3280   myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
3281   myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
3282   myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
3283   myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
3284   myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
3285   myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
3286  
3287   myMainLayout->setColumnStretch(  0,  0 );
3288   myMainLayout->setColumnStretch(  1,  5 );
3289   myMainLayout->setRowStretch   ( 11,  5 );
3290   myMainLayout->setRowStretch   ( 16,  5 );
3291   myMainLayout->setRowStretch   ( 17,  1 );
3292
3293   clearInternal();
3294 }
3295
3296 /*!
3297   \brief Destructor
3298 */
3299 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3300 {}
3301
3302 /*!
3303   \brief Change widget font attributes (bold, ...).
3304   \param w widget
3305   \param attr font attributes (XORed flags)
3306 */
3307 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3308 {
3309   if ( w ) {
3310     QFont f = w->font();
3311     f.setBold( true );
3312     w->setFont( f );
3313   }
3314 }
3315
3316 /*!
3317   \brief Create info field
3318   \return new info field
3319 */
3320 QLabel* SMESHGUI_CtrlInfo::createField()
3321 {
3322   QLabel* lab = new QLabel( this );
3323   lab->setFrameStyle( StyledPanel | Sunken );
3324   lab->setAlignment( Qt::AlignCenter );
3325   lab->setAutoFillBackground( true );
3326   QPalette pal = lab->palette();
3327   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
3328   lab->setPalette( pal );
3329   lab->setMinimumWidth( 60 );
3330   return lab;
3331 }
3332
3333 /*!
3334   \brief Create QwtPlot
3335   \return new QwtPlot
3336 */
3337 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3338 {
3339   QwtPlot* aPlot = new QwtPlot( parent );
3340   aPlot->setMinimumSize( 100, 100 );
3341   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3342   xFont.setPointSize( 5 );
3343   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3344   yFont.setPointSize( 5 );
3345   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3346   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3347   aPlot->replot();
3348   return aPlot;
3349 }
3350
3351 /*!
3352   \brief Show controls information on the selected object
3353 */
3354 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3355 {
3356   clearInternal();
3357
3358   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3359   if ( myObject->_is_nil() ) return;
3360
3361   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3362     myWidgets[0]->setText( aSO->GetName().c_str() );
3363
3364   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3365   if ( mesh->_is_nil() ) return;
3366
3367   const bool meshLoaded = mesh->IsLoaded();
3368   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3369     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3370     for ( int i = 0; i < myButtons.count(); ++i )
3371       myButtons[i]->setEnabled( true );
3372
3373   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3374   if ( ! &nbElemsByType.in() ) return;
3375
3376   const CORBA::Long ctrlLimit =
3377     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3378
3379   // nodes info
3380   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3381   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3382                                 nbElemsByType[ SMESH::FACE ] +
3383                                 nbElemsByType[ SMESH::VOLUME ] );
3384   if ( nbNodes + nbElems > 0 ) {
3385     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3386       // free nodes
3387       computeFreeNodesInfo();
3388       // double nodes
3389       if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
3390         computeDoubleNodesInfo();
3391     }
3392     else {
3393       myButtons[0]->setEnabled( true );
3394       myButtons[1]->setEnabled( true );
3395     }
3396   }
3397   else {
3398     for( int i=2; i<=10; i++)
3399       myMainLayout->itemAt(i)->widget()->setVisible( false );
3400   }
3401
3402   // edges info
3403   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3404     // double edges
3405     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3406       computeDoubleEdgesInfo();
3407     else
3408       myButtons[2]->setEnabled( true );
3409   }
3410   else {
3411     for( int i=11; i<=14; i++)
3412       myMainLayout->itemAt(i)->widget()->setVisible( false );
3413   }
3414  
3415   // faces info
3416   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3417     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3418       // double faces
3419       computeDoubleFacesInfo();
3420       // over constrained faces
3421       computeOverConstrainedFacesInfo();
3422       // aspect Ratio histogram
3423       computeAspectRatio();
3424     }
3425     else {
3426       myButtons[3]->setEnabled( true );
3427       myButtons[4]->setEnabled( true );
3428       myButtons[5]->setEnabled( true );
3429     }
3430 #ifdef DISABLE_PLOT2DVIEWER
3431     myMainLayout->setRowStretch(11,0);
3432     for( int i=22; i<=24; i++)
3433       myMainLayout->itemAt(i)->widget()->setVisible( false );
3434 #endif
3435   }
3436   else {
3437     myMainLayout->setRowStretch(11,0);
3438     for( int i=15; i<=24; i++)
3439       myMainLayout->itemAt(i)->widget()->setVisible( false );
3440   }
3441
3442   // volumes info
3443   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3444     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3445       // double volumes
3446       computeDoubleVolumesInfo();
3447       // over constrained volumes
3448       computeOverConstrainedVolumesInfo();
3449       // aspect Ratio 3D histogram
3450       computeAspectRatio3D();
3451      }
3452      else {
3453        myButtons[6]->setEnabled( true );
3454        myButtons[7]->setEnabled( true );
3455        myButtons[8]->setEnabled( true );
3456      }
3457 #ifdef DISABLE_PLOT2DVIEWER
3458     myMainLayout->setRowStretch(16,0);
3459     for( int i=32; i<=34; i++)
3460       myMainLayout->itemAt(i)->widget()->setVisible( false );
3461 #endif
3462   }
3463   else {
3464     myMainLayout->setRowStretch(16,0);
3465     for( int i=25; i<=34; i++)
3466       myMainLayout->itemAt(i)->widget()->setVisible( false );
3467   }
3468 }
3469
3470 //================================================================================
3471 /*!
3472  * \brief Computes and shows nb of elements satisfying a given predicate
3473  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3474  *  \param [in] iBut - index of one of myButtons to disable
3475  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3476  */
3477 //================================================================================
3478
3479 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3480 {
3481   myButtons[ iBut ]->setEnabled( false );
3482   myWidgets[ iWdg ]->setText( "" );
3483   if ( myObject->_is_nil() ) return;
3484
3485   SUIT_OverrideCursor wc;
3486
3487   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3488   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3489   {
3490     mesh->Load();
3491     this->showInfo( myObject ); // try to show all values
3492     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3493       return; // <ft> predicate already computed
3494   }
3495   // look for a predicate of type <ft>
3496   for ( int i = 0; i < myPredicates.count(); ++i )
3497     if ( myPredicates[i]->GetFunctorType() == ft )
3498     {
3499       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3500       myWidgets[ iWdg ]->setText( QString::number( nb ));
3501     }
3502 }
3503
3504 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3505 {
3506   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3507 }
3508
3509 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3510 {
3511   computeNb( SMESH::FT_EqualNodes, 1, 2 );
3512 }
3513
3514 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3515 {
3516   computeNb( SMESH::FT_EqualEdges, 2, 3 );
3517 }
3518
3519 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3520 {
3521   computeNb( SMESH::FT_EqualFaces, 3, 4 );
3522 }
3523
3524 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3525 {
3526   computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
3527 }
3528
3529 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3530 {
3531   computeNb( SMESH::FT_EqualVolumes, 6, 6 );
3532 }
3533
3534 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3535 {
3536   computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
3537 }
3538
3539 void SMESHGUI_CtrlInfo::computeAspectRatio()
3540 {
3541 #ifndef DISABLE_PLOT2DVIEWER
3542   myButtons[5]->setEnabled( false );
3543
3544   if ( myObject->_is_nil() ) return;
3545
3546   SUIT_OverrideCursor wc;
3547
3548   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3549   if ( aHistogram && !aHistogram->isEmpty() ) {
3550     QwtPlotItem* anItem = aHistogram->createPlotItem();
3551     anItem->attach( myPlot );
3552     myPlot->replot();
3553   }
3554   delete aHistogram;
3555 #endif
3556 }
3557
3558 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3559 {
3560 #ifndef DISABLE_PLOT2DVIEWER
3561   myButtons[8]->setEnabled( false );
3562
3563   if ( myObject->_is_nil() ) return;
3564
3565   SUIT_OverrideCursor wc;
3566
3567   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3568   if ( aHistogram && !aHistogram->isEmpty() ) {
3569     QwtPlotItem* anItem = aHistogram->createPlotItem();
3570     anItem->attach( myPlot3D );
3571     myPlot3D->replot();
3572   }
3573   delete aHistogram;
3574 #endif
3575 }
3576
3577 /*!
3578   \brief Internal clean-up (reset widget)
3579 */
3580 void SMESHGUI_CtrlInfo::clearInternal()
3581 {
3582   for( int i=0; i<=34; i++)
3583     myMainLayout->itemAt(i)->widget()->setVisible( true );
3584   for( int i=0; i<=8; i++)
3585     myButtons[i]->setEnabled( false );
3586   myPlot->detachItems();
3587   myPlot3D->detachItems();
3588   myPlot->replot();
3589   myPlot3D->replot();
3590   myWidgets[0]->setText( QString() );
3591   for ( int i = 1; i < myWidgets.count(); i++ )
3592     myWidgets[i]->setText( "" );
3593   myMainLayout->setRowStretch(11,5);
3594   myMainLayout->setRowStretch(16,5);
3595 }
3596
3597 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3598 {
3599   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3600   myButtons[1]->setEnabled( true );
3601   myWidgets[2]->setText("");
3602 }
3603
3604 #ifndef DISABLE_PLOT2DVIEWER
3605 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3606 {
3607   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3608   if ( mesh->_is_nil() ) return 0;
3609   if ( !mesh->IsLoaded() )
3610     mesh->Load();
3611   aNumFun->SetMesh( mesh );
3612
3613   CORBA::Long cprecision = 6;
3614   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
3615     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3616   aNumFun->SetPrecision( cprecision );
3617
3618   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3619
3620   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3621                                                                   /*isLogarithmic=*/false,
3622                                                                   myObject );
3623   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3624   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3625   if ( &histogramVar.in() )
3626   {
3627     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3628       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3629     if ( histogramVar->length() >= 2 )
3630       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3631   }
3632   return aHistogram;
3633 }
3634 #endif
3635
3636 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3637   out << QString( 20, '-' ) << "\n";
3638   out << tr( "CTRL_INFO"  ) << "\n";
3639   out << QString( 20, '-' ) << "\n";
3640   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3641   out <<                                 tr( "NODES_INFO" )                     << "\n";
3642   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3643   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3644   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3645   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3646   out <<                                 tr( "FACES_INFO" )                     << "\n";
3647   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3648   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3649   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3650   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3651   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3652 }
3653
3654 /*!
3655   \class SMESHGUI_CtrlInfoDlg
3656   \brief Controls information dialog box
3657 */
3658
3659 /*!
3660   \brief Constructor
3661   \param parent parent widget
3662   \param page specifies the dialog page to be shown at the start-up
3663 */
3664 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3665 : QDialog( parent )
3666 {
3667   setAttribute( Qt::WA_DeleteOnClose, true );
3668   setWindowTitle( tr( "CTRL_INFO" ) );
3669   setMinimumSize( 400, 600 );
3670
3671   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3672   
3673   // buttons
3674   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3675   okBtn->setAutoDefault( true );
3676   okBtn->setDefault( true );
3677   okBtn->setFocus();
3678   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3679   dumpBtn->setAutoDefault( true );
3680   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3681   helpBtn->setAutoDefault( true );
3682
3683   QHBoxLayout* btnLayout = new QHBoxLayout;
3684   btnLayout->setSpacing( SPACING );
3685   btnLayout->setMargin( 0 );
3686
3687   btnLayout->addWidget( okBtn );
3688   btnLayout->addWidget( dumpBtn );
3689   btnLayout->addStretch( 10 );
3690   btnLayout->addWidget( helpBtn );
3691
3692   QVBoxLayout* l = new QVBoxLayout ( this );
3693   l->setMargin( MARGIN );
3694   l->setSpacing( SPACING );
3695   l->addWidget( myCtrlInfo );
3696   l->addLayout( btnLayout );
3697
3698   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
3699   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3700   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3701   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3702   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
3703
3704   updateSelection();
3705 }
3706
3707 /*!
3708   \brief Destructor
3709 */
3710 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3711 {
3712 }
3713
3714 /*!
3715   \brief Show controls information
3716   \param IO interactive object
3717 */
3718 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3719 {  
3720   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ) )
3721     myCtrlInfo->showInfo( obj );
3722 }
3723
3724 /*!
3725   \brief Perform clean-up actions on the dialog box closing.
3726 */
3727 void SMESHGUI_CtrlInfoDlg::reject()
3728 {
3729   SMESH::SetPointRepresentation( false );
3730   QDialog::reject();
3731 }
3732
3733 /*!
3734   \brief Setup selection mode depending on the current dialog box state.
3735 */
3736 void SMESHGUI_CtrlInfoDlg::updateSelection()
3737 {
3738   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3739   disconnect( selMgr, 0, this, 0 );
3740   SMESH::SetPointRepresentation( false );  
3741   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3742   updateInfo();  
3743 }
3744
3745 /*!
3746   \brief Show mesh information
3747 */
3748 void SMESHGUI_CtrlInfoDlg::updateInfo()
3749 {
3750   SUIT_OverrideCursor wc;
3751
3752   SALOME_ListIO selected;
3753   SMESHGUI::selectionMgr()->selectedObjects( selected );
3754
3755   if ( selected.Extent() == 1 ) {
3756     Handle(SALOME_InteractiveObject) IO = selected.First();
3757     showInfo( IO );
3758   }
3759 }
3760
3761 /*!
3762   \brief Activate dialog box
3763 */
3764 void SMESHGUI_CtrlInfoDlg::activate()
3765 {
3766   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3767   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3768   updateSelection();
3769 }
3770
3771 /*!
3772   \brief Deactivate dialog box
3773 */
3774 void SMESHGUI_CtrlInfoDlg::deactivate()
3775 {
3776   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3777 }
3778
3779 /*!
3780  * \brief Dump contents into a file
3781  */
3782 void SMESHGUI_CtrlInfoDlg::dump()
3783 {
3784   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3785   if ( !app ) return;
3786   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3787   if ( !appStudy ) return;
3788   _PTR( Study ) aStudy = appStudy->studyDS();
3789
3790   QStringList aFilters;
3791   aFilters.append( tr( "TEXT_FILES" ) );
3792
3793   DumpFileDlg fd( this );
3794   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3795   fd.setFilters( aFilters );
3796   fd.myBaseChk->hide();
3797   fd.myElemChk->hide();
3798   fd.myAddChk ->hide();
3799   fd.myCtrlChk->hide();
3800   if ( fd.exec() == QDialog::Accepted )
3801   {
3802     QString aFileName = fd.selectedFile();
3803     if ( !aFileName.isEmpty() ) {
3804       QFileInfo aFileInfo( aFileName );
3805       if ( aFileInfo.isDir() )
3806         return;
3807  
3808       QFile aFile( aFileName );
3809       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3810         return;
3811       
3812       QTextStream out( &aFile );
3813       myCtrlInfo->saveInfo( out );
3814     }
3815   }
3816 }
3817
3818 /*!
3819  * \brief Show help
3820  */
3821 void SMESHGUI_CtrlInfoDlg::help()
3822 {
3823   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
3824 }