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