Salome HOME
Merge from V6_main 11/02/2013
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2012  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];
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_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] ) );
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         // geometry type
1232         QString gtype;
1233         switch( e->GetEntityType() ) {
1234         case SMDSEntity_Triangle:
1235         case SMDSEntity_Quad_Triangle:
1236           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1237         case SMDSEntity_Quadrangle:
1238         case SMDSEntity_Quad_Quadrangle:
1239         case SMDSEntity_BiQuad_Quadrangle:
1240           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1241         case SMDSEntity_Polygon:
1242         case SMDSEntity_Quad_Polygon:
1243           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1244         case SMDSEntity_Tetra:
1245         case SMDSEntity_Quad_Tetra:
1246           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1247         case SMDSEntity_Pyramid:
1248         case SMDSEntity_Quad_Pyramid:
1249           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1250         case SMDSEntity_Hexa:
1251         case SMDSEntity_Quad_Hexa:
1252         case SMDSEntity_TriQuad_Hexa:
1253           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1254         case SMDSEntity_Penta:
1255         case SMDSEntity_Quad_Penta:
1256           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1257         case SMDSEntity_Hexagonal_Prism:
1258           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1259         case SMDSEntity_Polyhedra:
1260         case SMDSEntity_Quad_Polyhedra:
1261           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1262         default: 
1263           break;
1264         }
1265         if ( !gtype.isEmpty() )
1266           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" ) ).arg( gtype ) );
1267         // quadratic flag and gravity center (any element except 0D)
1268         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1269           // quadratic flag
1270           myInfo->append( QString( "<b>%1?</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ) );
1271           // separator
1272           myInfo->append( "" );
1273           // gravity center
1274           XYZ gc = gravityCenter( e );
1275           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1276         }
1277         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1278           // ball diameter
1279           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() ));
1280         }
1281         // separator
1282         myInfo->append( "" );
1283         // connectivity
1284         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1285         for ( int idx = 1; nodeIt->more(); idx++ ) {
1286           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1287           // node number and ID
1288           myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
1289           // node coordinates
1290           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1291                           arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1292                           arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1293                           arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1294           // node connectivity
1295           Connectivity connectivity = nodeConnectivity( node );
1296           if ( !connectivity.isEmpty() ) {
1297             myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1298             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1299             if ( !con.isEmpty() )
1300               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1301             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1302             if ( !con.isEmpty() )
1303               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1304             con = formatConnectivity( connectivity, SMDSAbs_Face );
1305             if ( !con.isEmpty() )
1306               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1307             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1308             if ( !con.isEmpty() )
1309               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1310           }
1311           else {
1312             myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1313           }
1314         }
1315         // separator
1316         myInfo->append( "" );
1317         //controls
1318         myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" ) ) );
1319         //Length
1320         if ( e->GetType() == SMDSAbs_Edge ) {    
1321           afunctor.reset( new SMESH::Controls::Length() );
1322           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1323           afunctor->SetPrecision( cprecision );
1324           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "LENGTH_EDGES" ) ).arg( afunctor->GetValue( id ) ) );  
1325         }
1326         if( e->GetType() == SMDSAbs_Face ) {
1327           //Area                         
1328           afunctor.reset(  new SMESH::Controls::Area() );
1329           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1330           afunctor->SetPrecision( cprecision );  
1331           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "AREA_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1332           //Taper        
1333           afunctor.reset( new SMESH::Controls::Taper() );
1334           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1335           afunctor->SetPrecision( cprecision );
1336           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "TAPER_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1337           //AspectRatio2D        
1338           afunctor.reset( new SMESH::Controls::AspectRatio() );
1339           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1340           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1341           //Minimum angle         
1342           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1343           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1344           afunctor->SetPrecision( cprecision );
1345           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1346           //Wraping angle        
1347           afunctor.reset( new SMESH::Controls::Warping() );
1348           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1349           afunctor->SetPrecision( cprecision );
1350           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1351           //Skew         
1352           afunctor.reset( new SMESH::Controls::Skew() );
1353           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1354           afunctor->SetPrecision( cprecision );
1355           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1356           //ElemDiam2D   
1357           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1358           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1359           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
1360         }
1361         if( e->GetType() == SMDSAbs_Volume ) {
1362           //AspectRatio3D
1363           afunctor.reset(  new SMESH::Controls::AspectRatio3D() );
1364           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1365           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1366           //Volume      
1367           afunctor.reset(  new SMESH::Controls::Volume() );
1368           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1369           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUME_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1370           //ElementDiameter3D    
1371           afunctor.reset(  new SMESH::Controls::Volume() );
1372           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1373           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" ) ).arg( afunctor->GetValue( id ) ) );
1374         }
1375         // element position
1376         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1377           SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();    
1378           if ( !CORBA::is_nil( aMesh ) ) {
1379             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1380             int shapeID = pos.shapeID;
1381             if ( shapeID > 0 ) {
1382               myInfo->append( "" ); // separator
1383               QString shapeType;
1384               switch ( pos.shapeType ) {
1385               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1386               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1387               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1388               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1389               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1390               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1391               }
1392               myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ).arg( shapeType ).arg( shapeID ) );
1393             }
1394           }
1395         }
1396         // groups element belongs to
1397         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1398         if ( !CORBA::is_nil( aMesh ) ) {
1399           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1400           myInfo->append( "" ); // separator
1401           bool top_created = false;
1402           for ( int i = 0; i < groups->length(); i++ ) {
1403             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1404             if ( CORBA::is_nil( aGrp ) ) continue;
1405             QString aName = aGrp->GetName();
1406             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1407               if ( !top_created ) {
1408                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1409                 top_created = true;
1410               }
1411               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1412               if ( grp_details ) {
1413                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1414                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1415                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1416                 
1417                 // type : group on geometry, standalone group, group on filter
1418                 if ( !CORBA::is_nil( aStdGroup ) ) {
1419                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1420                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1421                 }
1422                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1423                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1424                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1425                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1426                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1427                   if ( sobj ) {
1428                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1429                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1430                   }
1431                 }
1432                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1433                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1434                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1435                 }
1436                 
1437                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1438                                 arg( QString::number( aGrp->Size() ) ) );
1439                 
1440                 // color
1441                 SALOMEDS::Color color = aGrp->GetColor();
1442                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1443                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1444               }
1445             }
1446           }
1447         }
1448       }
1449       // separator
1450       if ( ids.count() > 1 ) {
1451         myInfo->append( "" );
1452         myInfo->append( "------" );
1453         myInfo->append( "" );
1454       }
1455     }
1456   }
1457 }
1458
1459 /*!
1460   \brief Internal clean-up (reset widget)
1461 */
1462 void SMESHGUI_SimpleElemInfo::clearInternal()
1463 {
1464   myInfo->clear();
1465 }
1466
1467 void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out )
1468 {
1469   out << QString( 12, '-' ) << "\n";
1470   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
1471   out << QString( 12, '-' ) << "\n";
1472   out << myInfo->toPlainText();
1473   out << "\n";
1474 }
1475
1476
1477 /*!
1478   \class SMESHGUI_TreeElemInfo::ItemDelegate
1479   \brief Item delegate for tree mesh info widget
1480   \internal
1481 */
1482 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1483 {
1484 public:
1485   ItemDelegate( QObject* );
1486   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1487 };
1488
1489 /*!
1490   \brief Constructor
1491   \internal
1492 */
1493 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1494 {
1495 }
1496
1497 /*!
1498   \brief Create item editor widget
1499   \internal
1500 */
1501 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1502 {
1503   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1504   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1505   return w;
1506 }
1507
1508 /*!
1509   \class SMESHGUI_TreeElemInfo
1510   \brief Represents mesh element information in the tree-like form.
1511 */
1512
1513 /*!
1514   \brief Constructor
1515   \param parent parent widget
1516 */
1517 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1518 : SMESHGUI_ElemInfo( parent )
1519 {
1520   myInfo = new QTreeWidget( frame() );
1521   myInfo->setColumnCount( 2 );
1522   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1523   myInfo->header()->setStretchLastSection( true );
1524   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1525   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1526   QVBoxLayout* l = new QVBoxLayout( frame() );
1527   l->setMargin( 0 );
1528   l->addWidget( myInfo );
1529   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
1530 }
1531
1532 /*!
1533   \brief Show mesh element information
1534   \param ids mesh nodes / elements identifiers
1535 */
1536 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1537 {
1538   clearInternal();
1539
1540   if ( actor() ) {
1541     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1542     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1543     int cprecision = -1;
1544     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1545       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1546     foreach ( long id, ids ) {
1547       if ( !isElements() ) {
1548         //
1549         // show node info
1550         //
1551         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1552         if ( !e ) return;
1553         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1554       
1555         // node ID
1556         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1557         nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ) );
1558         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1559         // coordinates
1560         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1561         coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1562         QTreeWidgetItem* xItem = createItem( coordItem );
1563         xItem->setText( 0, "X" );
1564         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1565         QTreeWidgetItem* yItem = createItem( coordItem );
1566         yItem->setText( 0, "Y" );
1567         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1568         QTreeWidgetItem* zItem = createItem( coordItem );
1569         zItem->setText( 0, "Z" );
1570         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1571         // connectivity
1572         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1573         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1574         Connectivity connectivity = nodeConnectivity( node );
1575         if ( !connectivity.isEmpty() ) {
1576           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1577           if ( !con.isEmpty() ) {
1578             QTreeWidgetItem* i = createItem( conItem );
1579             i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1580             i->setText( 1, con );
1581           }
1582           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1583           if ( !con.isEmpty() ) {
1584             QTreeWidgetItem* i = createItem( conItem );
1585             i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1586             i->setText( 1, con );
1587             i->setData( 1, TypeRole, NodeConnectivity );
1588           }
1589           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1590           if ( !con.isEmpty() ) {
1591             QTreeWidgetItem* i = createItem( conItem );
1592             i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1593             i->setText( 1, con );
1594             i->setData( 1, TypeRole, NodeConnectivity );
1595           }
1596           con = formatConnectivity( connectivity, SMDSAbs_Face );
1597           if ( !con.isEmpty() ) {
1598             QTreeWidgetItem* i = createItem( conItem );
1599             i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1600             i->setText( 1, con );
1601             i->setData( 1, TypeRole, NodeConnectivity );
1602           }
1603           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1604           if ( !con.isEmpty() ) {
1605             QTreeWidgetItem* i = createItem( conItem );
1606             i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1607             i->setText( 1, con );
1608             i->setData( 1, TypeRole, NodeConnectivity );
1609           }
1610         }
1611         else {
1612           conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ) );
1613         }
1614         // node position
1615         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1616         if ( !CORBA::is_nil( aMeshPtr ) ) {
1617           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1618           int shapeID = pos->shapeID;
1619           if ( shapeID > 0 ) {
1620             QString shapeType;
1621             double u, v;
1622             switch ( pos->shapeType ) {
1623             case GEOM::EDGE:
1624               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1625               if ( pos->params.length() == 1 )
1626                 u = pos->params[0];
1627               break;
1628             case GEOM::FACE:
1629               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1630               if ( pos->params.length() == 2 ) {
1631                 u = pos->params[0];
1632                 v = pos->params[1];
1633               }
1634               break;
1635             case GEOM::VERTEX:
1636               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1637               break;
1638             default:
1639               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1640               break;
1641             }
1642             QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
1643             posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") );
1644             posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
1645             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1646               QTreeWidgetItem* uItem = createItem( posItem );
1647               uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") );
1648               uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
1649               if ( pos->shapeType == GEOM::FACE ) {
1650                 QTreeWidgetItem* vItem = createItem( posItem );
1651                 vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") );
1652                 vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
1653               }
1654             }
1655           }
1656         }
1657         // groups node belongs to
1658         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1659         if ( !CORBA::is_nil( aMesh ) ) {
1660           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1661           QTreeWidgetItem* groupsItem = 0;
1662           for ( int i = 0; i < groups->length(); i++ ) {
1663             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1664             if ( CORBA::is_nil( aGrp ) ) continue;
1665             QString aName = aGrp->GetName();
1666             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1667               if ( !groupsItem ) {
1668                 groupsItem = createItem( nodeItem, Bold );
1669                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1670               }
1671               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1672               it->setText( 0, aName.trimmed() );
1673               if ( grp_details ) {
1674                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1675                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1676                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1677                 
1678                 // type : group on geometry, standalone group, group on filter
1679                 QTreeWidgetItem* typeItem = createItem( it );
1680                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1681                 if ( !CORBA::is_nil( aStdGroup ) ) {
1682                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1683                 }
1684                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1685                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1686                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1687                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1688                   if ( sobj ) {
1689                     QTreeWidgetItem* gobjItem = createItem( typeItem );
1690                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
1691                     gobjItem->setText( 1, sobj->GetName().c_str() );
1692                   }
1693                 }
1694                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1695                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1696                 }
1697                 
1698                 // size
1699                 QTreeWidgetItem* sizeItem = createItem( it );
1700                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
1701                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
1702                 
1703                 // color
1704                 SALOMEDS::Color color = aGrp->GetColor();
1705                 QTreeWidgetItem* colorItem = createItem( it );
1706                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
1707                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1708               }
1709             }
1710           }
1711         }
1712       }
1713       else {
1714         //
1715         // show element info
1716         // 
1717         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1718         SMESH::Controls::NumericalFunctorPtr afunctor;
1719         if ( !e ) return;
1720         
1721         // element ID && type
1722         QString stype;
1723         switch( e->GetType() ) {
1724         case SMDSAbs_0DElement:
1725           stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1726         case SMDSAbs_Ball:
1727           stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1728         case SMDSAbs_Edge:
1729           stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1730         case SMDSAbs_Face:
1731           stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1732         case SMDSAbs_Volume:
1733           stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1734         default: 
1735           break;
1736         }
1737         if ( stype.isEmpty() ) return;
1738         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1739         elemItem->setText( 0, stype );
1740         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1741         // geometry type
1742         QString gtype;
1743         switch( e->GetEntityType() ) {
1744         case SMDSEntity_Triangle:
1745         case SMDSEntity_Quad_Triangle:
1746           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1747         case SMDSEntity_Quadrangle:
1748         case SMDSEntity_Quad_Quadrangle:
1749         case SMDSEntity_BiQuad_Quadrangle:
1750           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1751         case SMDSEntity_Polygon:
1752         case SMDSEntity_Quad_Polygon:
1753           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1754         case SMDSEntity_Tetra:
1755         case SMDSEntity_Quad_Tetra:
1756           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1757         case SMDSEntity_Pyramid:
1758         case SMDSEntity_Quad_Pyramid:
1759           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1760         case SMDSEntity_Hexa:
1761         case SMDSEntity_Quad_Hexa:
1762         case SMDSEntity_TriQuad_Hexa:
1763           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1764         case SMDSEntity_Penta:
1765         case SMDSEntity_Quad_Penta:
1766           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1767         case SMDSEntity_Hexagonal_Prism:
1768           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1769         case SMDSEntity_Polyhedra:
1770         case SMDSEntity_Quad_Polyhedra:
1771           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1772         default: 
1773           break;
1774         }
1775         if ( !gtype.isEmpty() ) {
1776           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1777           typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ) );
1778           typeItem->setText( 1, gtype );
1779         }
1780         // quadratic flag and gravity center (any element except 0D)
1781         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1782           // quadratic flag
1783           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1784           quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ) );
1785           quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) );
1786           // gravity center
1787           XYZ gc = gravityCenter( e );
1788           QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
1789           gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) );
1790           QTreeWidgetItem* xItem = createItem( gcItem );
1791           xItem->setText( 0, "X" );
1792           xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1793           QTreeWidgetItem* yItem = createItem( gcItem );
1794           yItem->setText( 0, "Y" );
1795           yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1796           QTreeWidgetItem* zItem = createItem( gcItem );
1797           zItem->setText( 0, "Z" );
1798           zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1799         }
1800         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1801           // ball diameter
1802           QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
1803           diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) );
1804           diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
1805         }
1806         // connectivity
1807         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1808         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1809         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1810         for ( int idx = 1; nodeIt->more(); idx++ ) {
1811           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1812           // node number and ID
1813           QTreeWidgetItem* nodeItem = createItem( conItem, Bold );
1814           nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) );
1815           nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
1816           nodeItem->setData( 1, TypeRole, ElemConnectivity );
1817           nodeItem->setData( 1, IdRole, node->GetID() );
1818           nodeItem->setExpanded( false );
1819           // node coordinates
1820           QTreeWidgetItem* coordItem = createItem( nodeItem );
1821           coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1822           QTreeWidgetItem* xItem = createItem( coordItem );
1823           xItem->setText( 0, "X" );
1824           xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1825           QTreeWidgetItem* yItem = createItem( coordItem );
1826           yItem->setText( 0, "Y" );
1827           yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1828           QTreeWidgetItem* zItem = createItem( coordItem );
1829           zItem->setText( 0, "Z" );
1830           zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1831           // node connectivity
1832           QTreeWidgetItem* nconItem = createItem( nodeItem );
1833           nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1834           Connectivity connectivity = nodeConnectivity( node );
1835           if ( !connectivity.isEmpty() ) {
1836             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1837             if ( !con.isEmpty() ) {
1838               QTreeWidgetItem* i = createItem( nconItem );
1839               i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1840               i->setText( 1, con );
1841             }
1842             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1843             if ( !con.isEmpty() ) {
1844               QTreeWidgetItem* i = createItem( nconItem );
1845               i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1846               i->setText( 1, con );
1847               i->setData( 1, TypeRole, NodeConnectivity );
1848             }
1849             con = formatConnectivity( connectivity, SMDSAbs_Ball );
1850             if ( !con.isEmpty() ) {
1851               QTreeWidgetItem* i = createItem( nconItem );
1852               i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1853               i->setText( 1, con );
1854               i->setData( 1, TypeRole, NodeConnectivity );
1855             }
1856             con = formatConnectivity( connectivity, SMDSAbs_Face );
1857             if ( !con.isEmpty() ) {
1858               QTreeWidgetItem* i = createItem( nconItem );
1859               i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1860               i->setText( 1, con );
1861               i->setData( 1, TypeRole, NodeConnectivity );
1862             }
1863             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1864             if ( !con.isEmpty() ) {
1865               QTreeWidgetItem* i = createItem( nconItem );
1866               i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1867               i->setText( 1, con );
1868               i->setData( 1, TypeRole, NodeConnectivity );
1869             }
1870           }
1871         }
1872         //Controls
1873         QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
1874         cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ) );
1875         //Length
1876         if( e->GetType()==SMDSAbs_Edge){         
1877           afunctor.reset( new SMESH::Controls::Length() );
1878           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1879           afunctor->SetPrecision( cprecision );
1880           QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
1881           lenItem->setText( 0, tr( "LENGTH_EDGES" ) );
1882           lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );         
1883         }
1884         if( e->GetType() == SMDSAbs_Face ) {
1885           //Area         
1886           afunctor.reset( new SMESH::Controls::Area() );        
1887           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1888           afunctor->SetPrecision( cprecision );
1889           QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
1890           areaItem->setText( 0, tr( "AREA_ELEMENTS" ) );
1891           areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ) );         
1892           //Taper
1893           afunctor.reset( new SMESH::Controls::Taper() );
1894           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1895           afunctor->SetPrecision( cprecision );
1896           QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
1897           taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ) );
1898           taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1899           //AspectRatio2D
1900           afunctor.reset( new SMESH::Controls::AspectRatio() );
1901           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1902           QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
1903           ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
1904           ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1905           //Minimum angle
1906           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1907           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1908           afunctor->SetPrecision( cprecision );
1909           QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
1910           minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ) );
1911           minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1912           //Wraping angle       
1913           afunctor.reset( new SMESH::Controls::Warping() );
1914           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1915           afunctor->SetPrecision( cprecision );
1916           QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
1917           warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
1918           warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );        
1919           //Skew          
1920           afunctor.reset( new SMESH::Controls::Skew() );
1921           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1922           afunctor->SetPrecision( cprecision );
1923           QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
1924           skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
1925           skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1926           //ElemDiam2D    
1927           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1928           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1929           QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
1930           diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
1931           diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1932         }
1933         if( e->GetType() == SMDSAbs_Volume ) {
1934           //AspectRatio3D       
1935           afunctor.reset( new SMESH::Controls::AspectRatio3D() );
1936           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1937           QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
1938           ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
1939           ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1940           //Volume
1941           afunctor.reset( new SMESH::Controls::Volume() );
1942           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1943           QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
1944           volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ) );
1945           volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
1946           //ElementDiameter3D   
1947           afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
1948           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1949           QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
1950           diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) );
1951           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );     
1952         }
1953         // element position
1954         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1955           SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();    
1956           if ( !CORBA::is_nil( aMesh ) ) {
1957             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1958             int shapeID = pos.shapeID;
1959             if ( shapeID > 0 ) {
1960               QTreeWidgetItem* shItem = createItem( elemItem, Bold );
1961               QString shapeType;
1962               switch ( pos.shapeType ) {
1963               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1964               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1965               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1966               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1967               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1968               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1969               }
1970               shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ) );
1971               shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ) );
1972             }
1973           }
1974         }
1975         // groups element belongs to
1976         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1977         if ( !CORBA::is_nil( aMesh ) ) {
1978           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1979           QTreeWidgetItem* groupsItem = 0;
1980           for ( int i = 0; i < groups->length(); i++ ) {
1981             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1982             if ( CORBA::is_nil( aGrp ) ) continue;
1983             QString aName = aGrp->GetName();
1984             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1985               if ( !groupsItem ) {
1986                 groupsItem = createItem( elemItem, Bold );
1987                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1988               }
1989               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1990               it->setText( 0, aName.trimmed() );
1991               if ( grp_details ) {
1992                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1993                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1994                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1995                 
1996                 // type : group on geometry, standalone group, group on filter
1997                 QTreeWidgetItem* typeItem = createItem( it );
1998                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1999                 if ( !CORBA::is_nil( aStdGroup ) ) {
2000                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
2001                 }
2002                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
2003                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
2004                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2005                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2006                   if ( sobj ) {
2007                     QTreeWidgetItem* gobjItem = createItem( typeItem );
2008                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
2009                     gobjItem->setText( 1, sobj->GetName().c_str() );
2010                   }
2011                 }
2012                 else if ( !CORBA::is_nil( aFltGroup ) ) {
2013                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
2014                 }
2015                 
2016                 // size
2017                 QTreeWidgetItem* sizeItem = createItem( it );
2018                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
2019                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
2020                 
2021                 // color
2022                 SALOMEDS::Color color = aGrp->GetColor();
2023                 QTreeWidgetItem* colorItem = createItem( it );
2024                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
2025                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2026               }
2027             }
2028           }
2029         }
2030       }
2031     }
2032   }
2033 }
2034
2035 /*!
2036   \brief Internal clean-up (reset widget)
2037 */
2038 void SMESHGUI_TreeElemInfo::clearInternal()
2039 {
2040   myInfo->clear();
2041   myInfo->repaint();
2042 }
2043
2044 /*!
2045   \brief Create new tree item.
2046   \param parent parent tree widget item
2047   \param flags item flag
2048   \return new tree widget item
2049 */
2050 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
2051 {
2052   QTreeWidgetItem* item;
2053   if ( parent )
2054     item = new QTreeWidgetItem( parent );
2055   else
2056     item = new QTreeWidgetItem( myInfo );
2057
2058   item->setFlags( item->flags() | Qt::ItemIsEditable );
2059
2060   QFont f = item->font( 0 );
2061   f.setBold( true );
2062   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
2063     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2064       item->setFont( i, f );
2065   }
2066
2067   item->setExpanded( true );
2068   return item;
2069 }
2070
2071 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2072 {
2073   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2074   if ( widgets.isEmpty() ) return;
2075   QTreeWidgetItem* aTreeItem = widgets.first();
2076   int type = aTreeItem->data( 1, TypeRole ).toInt();
2077   int id   = aTreeItem->data( 1, IdRole ).toInt();
2078   QMenu menu;
2079   QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ) );
2080   if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a )
2081     emit( itemInfo( id ) );
2082   else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a )
2083     emit( itemInfo( aTreeItem->text( 1 ) ) );
2084 }
2085
2086 void  SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
2087 {
2088   if ( theItem ) {
2089     int type = theItem->data( 1, TypeRole ).toInt();
2090     int id   = theItem->data( 1, IdRole ).toInt();
2091     if ( type == ElemConnectivity && id > 0 )
2092       emit( itemInfo( id ) );
2093     else if ( type == NodeConnectivity )
2094       emit( itemInfo( theItem->text( 1 ) ) );
2095   }
2096 }
2097
2098 void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
2099 {
2100   out << QString( 12, '-' ) << "\n";
2101   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
2102   out << QString( 12, '-' ) << "\n";
2103
2104   QTreeWidgetItemIterator it( myInfo );
2105   while ( *it ) {
2106     if ( !( *it )->text(0).isEmpty() ) {
2107       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2108       if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1);
2109       out << "\n";
2110     }
2111     ++it;
2112   }
2113   out << "\n";
2114 }
2115
2116 /*!
2117   \class GrpComputor
2118   \brief Mesh information computer
2119   \internal
2120   
2121   The class is created for different computation operation. Currently it is used
2122   to compute number of underlying nodes for the groups.
2123 */
2124
2125 /*!
2126   \brief Contructor
2127 */
2128 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
2129   : QObject( parent ), myItem( item )
2130 {
2131   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
2132 }
2133
2134 /*!
2135   \brief Compute function
2136 */
2137 void GrpComputor::compute()
2138 {
2139   if ( !CORBA::is_nil( myGroup ) && myItem ) {
2140     QTreeWidgetItem* item = myItem;
2141     myItem = 0;
2142     int nbNodes = myGroup->GetNumberOfNodes();
2143     item->treeWidget()->removeItemWidget( item, 1 );
2144     item->setText( 1, QString::number( nbNodes ));
2145   }
2146 }
2147
2148 /*!
2149   \class SMESHGUI_AddInfo
2150   \brief The wigdet shows additional information on the mesh object.
2151 */
2152
2153 /*!
2154   \brief Constructor
2155   \param parent parent widget
2156 */
2157 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2158 : QTreeWidget( parent )
2159 {
2160   setColumnCount( 2 );
2161   header()->setStretchLastSection( true );
2162   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2163   header()->hide();
2164 }
2165
2166 /*!
2167   \brief Destructor
2168 */
2169 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2170 {
2171 }
2172
2173 /*!
2174   \brief Show additional information on the selected object
2175   \param obj object being processed (mesh, sub-mesh, group, ID source)
2176 */
2177 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2178 {
2179   setProperty( "group_index", 0 );
2180   setProperty( "submesh_index",  0 );
2181   myComputors.clear();
2182   clear();
2183
2184   if ( CORBA::is_nil( obj ) ) return;
2185
2186   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2187   if ( !sobj ) return;
2188
2189   // name
2190   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2191   nameItem->setText( 0, tr( "NAME" ) );
2192   nameItem->setText( 1, sobj->GetName().c_str() );
2193   
2194   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2195   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2196   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2197   
2198   if ( !aMesh->_is_nil() )
2199     meshInfo( aMesh, nameItem );
2200   else if ( !aSubMesh->_is_nil() )
2201     subMeshInfo( aSubMesh, nameItem );
2202   else if ( !aGroup->_is_nil() )
2203     groupInfo( aGroup.in(), nameItem );
2204 }
2205
2206 /*!
2207   \brief Create new tree item.
2208   \param parent parent tree widget item
2209   \param flags item flag
2210   \return new tree widget item
2211 */
2212 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2213 {
2214   QTreeWidgetItem* item;
2215
2216   if ( parent )
2217     item = new QTreeWidgetItem( parent );
2218   else
2219     item = new QTreeWidgetItem( this );
2220
2221   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2222
2223   QFont f = item->font( 0 );
2224   f.setBold( true );
2225   for ( int i = 0; i < columnCount(); i++ ) {
2226     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2227       item->setFont( i, f );
2228   }
2229
2230   item->setExpanded( true );
2231   return item;
2232 }
2233
2234 /*!
2235   \brief Show mesh info
2236   \param mesh mesh object
2237   \param parent parent tree item
2238 */
2239 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2240 {
2241   // type
2242   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2243   SALOME_MED::MedFileInfo* inf = mesh->GetMEDFileInfo();
2244   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2245   typeItem->setText( 0, tr( "TYPE" ) );
2246   if ( !CORBA::is_nil( shape ) ) {
2247     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2248     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2249     if ( sobj ) {
2250       QTreeWidgetItem* gobjItem = createItem( typeItem );
2251       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2252       gobjItem->setText( 1, sobj->GetName().c_str() );
2253     }
2254   }
2255   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2256     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2257     QTreeWidgetItem* fileItem = createItem( typeItem );
2258     fileItem->setText( 0, tr( "FILE_NAME" ) );
2259     fileItem->setText( 1, (char*)inf->fileName );
2260   }
2261   else {
2262     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2263   }
2264   
2265   // groups
2266   myGroups = mesh->GetGroups();
2267   showGroups();
2268
2269   // sub-meshes
2270   mySubMeshes = mesh->GetSubMeshes();
2271   showSubMeshes();
2272 }
2273
2274 /*!
2275   \brief Show sub-mesh info
2276   \param subMesh sub-mesh object
2277   \param parent parent tree item
2278 */
2279 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2280 {
2281   bool isShort = parent->parent() != 0;
2282
2283   if ( !isShort ) {
2284     // parent mesh
2285     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2286     if ( sobj ) {
2287       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2288       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2289       nameItem->setText( 1, sobj->GetName().c_str() );
2290     }
2291   }
2292   
2293   // shape
2294   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2295   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2296   if ( sobj ) {
2297     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2298     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2299     gobjItem->setText( 1, sobj->GetName().c_str() );
2300   }
2301 }
2302
2303 /*!
2304   \brief Show group info
2305   \param grp mesh group object
2306   \param parent parent tree item
2307 */
2308 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2309 {
2310   bool isShort = parent->parent() != 0;
2311
2312   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2313   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2314   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2315
2316   if ( !isShort ) {
2317     // parent mesh
2318     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2319     if ( sobj ) {
2320       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2321       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2322       nameItem->setText( 1, sobj->GetName().c_str() );
2323     }
2324   }
2325
2326   // type : group on geometry, standalone group, group on filter
2327   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2328   typeItem->setText( 0, tr( "TYPE" ) );
2329   if ( !CORBA::is_nil( aStdGroup ) ) {
2330     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2331   }
2332   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2333     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2334     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2335     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2336     if ( sobj ) {
2337       QTreeWidgetItem* gobjItem = createItem( typeItem );
2338       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2339       gobjItem->setText( 1, sobj->GetName().c_str() );
2340     }
2341   }
2342   else if ( !CORBA::is_nil( aFltGroup ) ) {
2343     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2344   }
2345
2346   if ( !isShort ) {
2347     // entity type
2348     QString etype = tr( "UNKNOWN" );
2349     switch( grp->GetType() ) {
2350     case SMESH::NODE:
2351       etype = tr( "NODE" );
2352       break;
2353     case SMESH::EDGE:
2354       etype = tr( "EDGE" );
2355       break;
2356     case SMESH::FACE:
2357       etype = tr( "FACE" );
2358       break;
2359     case SMESH::VOLUME:
2360       etype = tr( "VOLUME" );
2361       break;
2362     case SMESH::ELEM0D:
2363       etype = tr( "0DELEM" );
2364       break;
2365     case SMESH::BALL:
2366       etype = tr( "BALL" );
2367       break;
2368     default:
2369       break;
2370     }
2371     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2372     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2373     etypeItem->setText( 1, etype );
2374   }
2375
2376   // size
2377   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2378   sizeItem->setText( 0, tr( "SIZE" ) );
2379   sizeItem->setText( 1, QString::number( grp->Size() ) );
2380
2381   // color
2382   SALOMEDS::Color color = grp->GetColor();
2383   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2384   colorItem->setText( 0, tr( "COLOR" ) );
2385   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2386
2387   // nb of underlying nodes
2388   if ( grp->GetType() != SMESH::NODE) {
2389     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2390     nodesItem->setText( 0, tr( "NB_NODES" ) );
2391     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2392     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2393     bool meshLoaded = mesh->IsLoaded();
2394     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
2395     if ( toShowNodes && meshLoaded ) {
2396       // already calculated and up-to-date
2397       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2398     }
2399     else {
2400       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2401       setItemWidget( nodesItem, 1, btn );
2402       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2403       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2404       myComputors.append( comp );
2405       if ( !meshLoaded )
2406         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2407     }
2408   }
2409 }
2410
2411 void SMESHGUI_AddInfo::showGroups()
2412 {
2413   myComputors.clear();
2414
2415   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2416   if ( !parent ) return;
2417
2418   int idx = property( "group_index" ).toInt();
2419
2420   QTreeWidgetItem* itemGroups = 0;
2421   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2422     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2423       itemGroups = parent->child( i );
2424       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2425       if ( extra )
2426         extra->updateControls( myGroups->length(), idx );
2427       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2428     }
2429   }
2430
2431   QMap<int, QTreeWidgetItem*> grpItems;
2432   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2433     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2434     if ( CORBA::is_nil( grp ) ) continue;
2435     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2436     if ( !grpSObj ) continue;
2437
2438     int grpType = grp->GetType();
2439
2440     if ( !itemGroups ) {
2441       // create top-level groups container item
2442       itemGroups = createItem( parent, Bold | All );
2443       itemGroups->setText( 0, tr( "GROUPS" ) );
2444       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2445
2446       // total number of groups > 10, show extra widgets for info browsing
2447       if ( myGroups->length() > MAXITEMS ) {
2448         ExtraWidget* extra = new ExtraWidget( this, true );
2449         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2450         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2451         setItemWidget( itemGroups, 1, extra );
2452         extra->updateControls( myGroups->length(), idx );
2453       }
2454     }
2455
2456     if ( grpItems.find( grpType ) == grpItems.end() ) {
2457       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2458       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2459       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2460     }
2461   
2462     // group name
2463     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2464     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2465
2466     // group info
2467     groupInfo( grp.in(), grpNameItem );
2468   }
2469 }
2470
2471 void SMESHGUI_AddInfo::showSubMeshes()
2472 {
2473   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2474   if ( !parent ) return;
2475
2476   int idx = property( "submesh_index" ).toInt();
2477
2478   QTreeWidgetItem* itemSubMeshes = 0;
2479   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2480     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2481       itemSubMeshes = parent->child( i );
2482       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2483       if ( extra )
2484         extra->updateControls( mySubMeshes->length(), idx );
2485       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2486     }
2487   }
2488
2489   QMap<int, QTreeWidgetItem*> smItems;
2490   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2491     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2492     if ( CORBA::is_nil( sm ) ) continue;
2493     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2494     if ( !smSObj ) continue;
2495     
2496     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2497     if ( CORBA::is_nil(gobj ) ) continue;
2498     
2499     int smType = gobj->GetShapeType();
2500     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2501
2502     if ( !itemSubMeshes ) {
2503       itemSubMeshes = createItem( parent, Bold | All );
2504       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2505       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2506
2507       // total number of sub-meshes > 10, show extra widgets for info browsing
2508       if ( mySubMeshes->length() > MAXITEMS ) {
2509         ExtraWidget* extra = new ExtraWidget( this, true );
2510         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2511         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2512         setItemWidget( itemSubMeshes, 1, extra );
2513         extra->updateControls( mySubMeshes->length(), idx );
2514       }
2515     }
2516          
2517     if ( smItems.find( smType ) == smItems.end() ) {
2518       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2519       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2520       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2521     }
2522     
2523     // submesh name
2524     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2525     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2526     
2527     // submesh info
2528     subMeshInfo( sm.in(), smNameItem );
2529   }
2530 }
2531
2532 /*!
2533  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2534  */
2535 void SMESHGUI_AddInfo::changeLoadToCompute()
2536 {
2537   for ( int i = 0; i < myComputors.count(); ++i )
2538   {
2539     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2540     {
2541       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2542         btn->setText( tr("COMPUTE") );
2543     }
2544   }
2545 }
2546
2547 void SMESHGUI_AddInfo::showPreviousGroups()
2548 {
2549   int idx = property( "group_index" ).toInt();
2550   setProperty( "group_index", idx-1 );
2551   showGroups();
2552 }
2553
2554 void SMESHGUI_AddInfo::showNextGroups()
2555 {
2556   int idx = property( "group_index" ).toInt();
2557   setProperty( "group_index", idx+1 );
2558   showGroups();
2559 }
2560
2561 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2562 {
2563   int idx = property( "submesh_index" ).toInt();
2564   setProperty( "submesh_index", idx-1 );
2565   showSubMeshes();
2566 }
2567
2568 void SMESHGUI_AddInfo::showNextSubMeshes()
2569 {
2570   int idx = property( "submesh_index" ).toInt();
2571   setProperty( "submesh_index", idx+1 );
2572   showSubMeshes();
2573 }
2574
2575 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2576 {
2577   out << QString( 15, '-')       << "\n";
2578   out << tr( "ADDITIONAL_INFO" ) << "\n";
2579   out << QString( 15, '-' )      << "\n";
2580   QTreeWidgetItemIterator it( this );
2581   while ( *it ) {
2582     if ( !( ( *it )->text(0) ).isEmpty() ) {
2583       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2584       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2585         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2586       }
2587       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2588       out << "\n";
2589     }
2590     ++it;
2591   }
2592   out << "\n";
2593 }
2594
2595 /*!
2596   \class SMESHGUI_MeshInfoDlg
2597   \brief Mesh information dialog box
2598 */
2599
2600 /*!
2601   \brief Constructor
2602   \param parent parent widget
2603   \param page specifies the dialog page to be shown at the start-up
2604 */
2605 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2606 : QDialog( parent ), myActor( 0 )
2607 {
2608   setModal( false );
2609   setAttribute( Qt::WA_DeleteOnClose, true );
2610   setWindowTitle( tr( "MESH_INFO" ) );
2611   setSizeGripEnabled( true );
2612
2613   myTabWidget = new QTabWidget( this );
2614
2615   // base info 
2616
2617   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2618   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2619
2620   // elem info 
2621   
2622   QWidget* w = new QWidget( myTabWidget );
2623
2624   myMode = new QButtonGroup( this );
2625   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2626   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2627   myMode->button( NodeMode )->setChecked( true );
2628   myID = new QLineEdit( w );
2629   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2630
2631   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2632   mode = qMin( 1, qMax( 0, mode ) );
2633   
2634   if ( mode == 0 ) 
2635     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2636   else
2637     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2638
2639   QGridLayout* elemLayout = new QGridLayout( w );
2640   elemLayout->setMargin( MARGIN );
2641   elemLayout->setSpacing( SPACING );
2642   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2643   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2644   elemLayout->addWidget( myID, 0, 2 );
2645   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2646   
2647   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2648
2649   // additional info
2650
2651   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2652   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2653
2654   // buttons
2655
2656   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2657   okBtn->setAutoDefault( true );
2658   okBtn->setDefault( true );
2659   okBtn->setFocus();
2660   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2661   dumpBtn->setAutoDefault( true );
2662   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2663   helpBtn->setAutoDefault( true );
2664
2665   QHBoxLayout* btnLayout = new QHBoxLayout;
2666   btnLayout->setSpacing( SPACING );
2667   btnLayout->setMargin( 0 );
2668
2669   btnLayout->addWidget( okBtn );
2670   btnLayout->addWidget( dumpBtn );
2671   btnLayout->addStretch( 10 );
2672   btnLayout->addWidget( helpBtn );
2673
2674   QVBoxLayout* l = new QVBoxLayout ( this );
2675   l->setMargin( MARGIN );
2676   l->setSpacing( SPACING );
2677   l->addWidget( myTabWidget );
2678   l->addLayout( btnLayout );
2679
2680   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2681
2682   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2683   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2684   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2685   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2686   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2687   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2688   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2689   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2690   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2691   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2692
2693   updateSelection();
2694 }
2695
2696 /*!
2697   \brief Destructor
2698 */
2699 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2700 {
2701 }
2702
2703 /*!
2704   \brief Show mesh information
2705   \param IO interactive object
2706 */
2707 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2708 {
2709   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2710   if ( !CORBA::is_nil( obj ) ) {
2711     myBaseInfo->showInfo( obj );
2712     myAddInfo->showInfo( obj );
2713
2714     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2715     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2716     QString ID;
2717     int nb = 0;
2718     if ( myActor && selector ) {
2719       nb = myMode->checkedId() == NodeMode ? 
2720         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2721         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2722     }
2723     myElemInfo->setSource( myActor ) ;
2724     if ( nb > 0 ) {
2725       myID->setText( ID.trimmed() );
2726       QSet<long> ids;
2727       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2728       foreach ( ID, idTxt )
2729         ids << ID.trimmed().toLong();
2730       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2731     }
2732     else {
2733       myID->clear();
2734       myElemInfo->clear();
2735     }
2736   }
2737 }
2738
2739 /*!
2740   \brief Perform clean-up actions on the dialog box closing.
2741 */
2742 void SMESHGUI_MeshInfoDlg::reject()
2743 {
2744   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2745   selMgr->clearFilters();
2746   SMESH::SetPointRepresentation( false );
2747   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2748     aViewWindow->SetSelectionMode( ActorSelection );
2749   QDialog::reject();
2750 }
2751
2752 /*!
2753   \brief Process keyboard event
2754   \param e key press event
2755 */
2756 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2757 {
2758   QDialog::keyPressEvent( e );
2759   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2760     e->accept();
2761     help();
2762   }
2763 }
2764
2765 /*!
2766   \brief Reactivate dialog box, when mouse pointer goes into it.
2767 */
2768 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2769 {
2770   //activate();
2771 }
2772
2773 /*!
2774   \brief Setup selection mode depending on the current dialog box state.
2775 */
2776 void SMESHGUI_MeshInfoDlg::updateSelection()
2777 {
2778   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2779
2780   disconnect( selMgr, 0, this, 0 );
2781   selMgr->clearFilters();
2782
2783   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) {
2784     SMESH::SetPointRepresentation( false );
2785     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2786       aViewWindow->SetSelectionMode( ActorSelection );
2787   }
2788   else {
2789     if ( myMode->checkedId() == NodeMode ) {
2790       SMESH::SetPointRepresentation( true );
2791       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2792         aViewWindow->SetSelectionMode( NodeSelection );
2793     }
2794     else {
2795       SMESH::SetPointRepresentation( false );
2796       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2797         aViewWindow->SetSelectionMode( CellSelection );
2798     }
2799   }
2800
2801   QString oldID = myID->text().trimmed();
2802   SMESH_Actor* oldActor = myActor;
2803   myID->clear();
2804   
2805   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2806   updateInfo();
2807   
2808   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
2809     myID->setText( oldID );
2810     idChanged();
2811   }
2812 }
2813
2814 /*!
2815   \brief Show help page
2816 */
2817 void SMESHGUI_MeshInfoDlg::help()
2818 {
2819   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
2820                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
2821                        "mesh_infos_page.html#mesh_element_info_anchor" );
2822 }
2823
2824 /*!
2825   \brief Show mesh information
2826 */
2827 void SMESHGUI_MeshInfoDlg::updateInfo()
2828 {
2829   SUIT_OverrideCursor wc;
2830
2831   SALOME_ListIO selected;
2832   SMESHGUI::selectionMgr()->selectedObjects( selected );
2833
2834   if ( selected.Extent() == 1 ) {
2835     Handle(SALOME_InteractiveObject) IO = selected.First();
2836     showInfo( IO );
2837   }
2838 //   else {
2839 //     myBaseInfo->clear();
2840 //     myElemInfo->clear();
2841 //     myAddInfo->clear();
2842 //   }
2843 }
2844
2845 /*!
2846   \brief Activate dialog box
2847 */
2848 void SMESHGUI_MeshInfoDlg::activate()
2849 {
2850   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
2851   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
2852   myTabWidget->setEnabled( true );
2853   updateSelection();
2854 }
2855
2856 /*!
2857   \brief Deactivate dialog box
2858 */
2859 void SMESHGUI_MeshInfoDlg::deactivate()
2860 {
2861   myTabWidget->setEnabled( false );
2862   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2863 }
2864
2865 /*!
2866   \brief Called when users switches between node / element modes.
2867 */
2868 void SMESHGUI_MeshInfoDlg::modeChanged()
2869 {
2870   myID->clear();
2871   updateSelection();
2872 }
2873
2874 /*!
2875   \brief Caled when users prints mesh element ID in the corresponding field.
2876 */
2877 void SMESHGUI_MeshInfoDlg::idChanged()
2878 {
2879   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2880   if ( myActor && selector ) {
2881     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
2882     TColStd_MapOfInteger ID;
2883     QSet<long> ids;
2884     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
2885     foreach ( QString tid, idTxt ) {
2886       long id = tid.trimmed().toLong();
2887       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
2888         myActor->GetObject()->GetMesh()->FindElement( id ) :
2889         myActor->GetObject()->GetMesh()->FindNode( id );
2890       if ( e ) {
2891         ID.Add( id );
2892         ids << id;
2893       }
2894     }
2895     selector->AddOrRemoveIndex( IO, ID, false );
2896     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
2897       aViewWindow->highlight( IO, true, true );
2898       aViewWindow->Repaint();
2899     }
2900     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2901   }
2902 }
2903
2904 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
2905 {
2906   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
2907     myMode->button( NodeMode )->click();
2908     myID->setText( QString::number( id ) );
2909   }
2910 }
2911
2912 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
2913 {
2914   if ( !theStr.isEmpty() ) {
2915     myMode->button( ElemMode )->click();
2916     myID->setText( theStr );
2917   }
2918 }
2919
2920 void SMESHGUI_MeshInfoDlg::dump()
2921 {
2922   SUIT_Application* app = SUIT_Session::session()->activeApplication();
2923   if ( !app ) return;
2924   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
2925   if ( !appStudy ) return;
2926   _PTR( Study ) aStudy = appStudy->studyDS();
2927
2928   QStringList aFilters;
2929   aFilters.append( tr( "TEXT_FILES" ) );
2930
2931   bool anIsBase = true;
2932   bool anIsElem = true;
2933   bool anIsAdd  = true;
2934
2935   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
2936     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
2937     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
2938     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
2939   }
2940
2941   DumpFileDlg fd( this );
2942   fd.setWindowTitle( tr( "SAVE_INFO" ) );
2943   fd.setFilters( aFilters );
2944   fd.myBaseChk->setChecked( anIsBase );
2945   fd.myElemChk->setChecked( anIsElem );
2946   fd.myAddChk ->setChecked( anIsAdd );
2947   if ( fd.exec() == QDialog::Accepted )
2948   {
2949     QString aFileName = fd.selectedFile();
2950
2951     bool toBase = fd.myBaseChk->isChecked();
2952     bool toElem = fd.myElemChk->isChecked();
2953     bool toAdd  = fd.myAddChk->isChecked();
2954
2955     if ( !aFileName.isEmpty() ) {
2956       QFileInfo aFileInfo( aFileName );
2957       if ( aFileInfo.isDir() )
2958         return;
2959  
2960       QFile aFile( aFileName );
2961       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
2962         return;
2963       
2964       QTextStream out( &aFile );
2965       
2966       if ( toBase ) myBaseInfo->saveInfo( out );
2967       if ( toElem ) myElemInfo->saveInfo( out );
2968       if ( toAdd )  myAddInfo ->saveInfo( out );
2969     }
2970   }
2971 }