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