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