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