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