Salome HOME
e29e6be6dfa3ce8029baa4ae129c068984e553f5
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2015  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, or (at your option) any later version.
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 "SMDSAbs_ElementType.hxx"
28 #include "SMDS_BallElement.hxx"
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_Mesh.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMESHDS_Mesh.hxx"
34 #include "SMESHGUI.h"
35 #include "SMESHGUI_FilterUtils.h"
36 #include "SMESHGUI_IdValidator.h"
37 #include "SMESHGUI_SpinBox.h"
38 #include "SMESHGUI_Utils.h"
39 #include "SMESHGUI_VTKUtils.h"
40 #include "SMESH_Actor.h"
41
42 #include <LightApp_SelectionMgr.h>
43 #include <SUIT_FileDlg.h>
44 #include <SUIT_OverrideCursor.h>
45 #include <SUIT_ResourceMgr.h>
46 #include <SUIT_Session.h>
47 #include <SVTK_ViewWindow.h>
48
49 #include <SALOMEDSClient_Study.hxx>
50 #include <SalomeApp_Study.h>
51
52 #include <QApplication>
53 #include <QButtonGroup>
54 #include <QCheckBox>
55 #include <QContextMenuEvent>
56 #include <QGridLayout>
57 #include <QHBoxLayout>
58 #include <QHeaderView>
59 #include <QItemDelegate>
60 #include <QKeyEvent>
61 #include <QLabel>
62 #include <QLineEdit>
63 #include <QMenu>
64 #include <QPushButton>
65 #include <QToolButton>
66 #include <QRadioButton>
67 #include <QTextStream>
68 #include <QTabWidget>
69 #include <QTextBrowser>
70 #include <QVBoxLayout>
71
72 #include "utilities.h"
73
74 #include <SALOMEconfig.h>
75 #include CORBA_SERVER_HEADER(GEOM_Gen)
76
77 namespace {
78
79 const int SPACING      = 6;
80 const int MARGIN       = 9;
81 const int MAXITEMS     = 10;
82 const int GROUPS_ID    = 100;
83 const int SUBMESHES_ID = 200;
84 const int SPACING_INFO = 2;
85
86 enum InfoRole {
87   TypeRole = Qt::UserRole + 10,
88   IdRole,
89 };
90
91 enum InfoType {
92   NodeConnectivity = 100,
93   ElemConnectivity,
94 };
95 } // namesapce
96
97 /*!
98   \class ExtraWidget
99   \internal
100 */
101 class ExtraWidget : public QWidget
102 {
103 public:
104   ExtraWidget( QWidget*, bool = false );
105   ~ExtraWidget();
106
107   void updateControls( int, int, int = MAXITEMS );
108
109 public:
110   QLabel*      current;
111   QPushButton* prev;
112   QPushButton* next;
113   bool         brief;
114 };
115
116 ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b )
117 {
118   current = new QLabel( this );
119   current->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
120   prev = new QPushButton( tr( "<<" ), this );
121   next = new QPushButton( tr( ">>" ), this );
122   QHBoxLayout* hbl = new QHBoxLayout( this );
123   hbl->setContentsMargins( 0, SPACING, 0, 0 );
124   hbl->setSpacing( SPACING );
125   hbl->addStretch();
126   hbl->addWidget( current );
127   hbl->addWidget( prev );
128   hbl->addWidget( next );
129 }
130
131 ExtraWidget::~ExtraWidget()
132 {
133 }
134
135 void ExtraWidget::updateControls( int total, int index, int blockSize )
136 {
137   setVisible( total > blockSize );
138   QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" );
139   current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total ) ).arg( total ) );
140   prev->setEnabled( index > 0 );
141   next->setEnabled( (index+1)*blockSize < total );
142 }
143
144 /*!
145   \class DumpFileDlg
146   \brief Customization of standard "Save file" dialog box for dump info operation
147   \internal
148 */
149
150 class DumpFileDlg : public SUIT_FileDlg
151 {
152 public:
153   DumpFileDlg( QWidget* parent );
154
155   QCheckBox* myBaseChk;
156   QCheckBox* myElemChk;
157   QCheckBox* myAddChk;
158   QCheckBox* myCtrlChk;
159 };
160
161 /*!
162   \brief Constructor
163   \internal
164 */
165 DumpFileDlg::DumpFileDlg( QWidget* parent ) : SUIT_FileDlg( parent, false, true, true )
166 {
167   QGridLayout* grid = ::qobject_cast<QGridLayout *>( layout() );
168   if ( grid ) {
169     QWidget* hB = new QWidget( this );
170     myBaseChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB );
171     myElemChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB );
172     myAddChk  = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ),  hB );
173     myCtrlChk = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB );
174
175     QGridLayout* layout = new QGridLayout( hB );
176     layout->addWidget( myBaseChk, 0, 0 );
177     layout->addWidget( myElemChk, 0, 1 );
178     layout->addWidget( myAddChk, 1, 0 );
179     layout->addWidget( myCtrlChk, 1, 1 );
180
181     QPushButton* pb = new QPushButton( this );
182
183     int row = grid->rowCount();
184     grid->addWidget( new QLabel( "", this ), row, 0 );
185     grid->addWidget( hB, row, 1, 1, 3 );
186     grid->addWidget( pb, row, 5 );
187
188     pb->hide();
189   }
190 }
191
192 /*!
193   \brief Get depth of the tree item
194   \internal
195   \param theItem tree widget item
196   \return item's depth in tree widget (where top-level items have zero depth)
197 */
198 static int itemDepth( QTreeWidgetItem* item )
199 {
200   int d = 0;
201   QTreeWidgetItem* p = item->parent();
202   while ( p ) {
203     d++;
204     p = p->parent();
205   }
206   return d;
207 }
208
209 /*!
210   \class SMESHGUI_MeshInfo
211   \brief Base mesh information widget
212   
213   Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source.
214 */
215
216 /*!
217   \brief Constructor.
218   \param parent parent widget
219 */
220 SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent )
221   : QFrame( parent ), myWidgets( iElementsEnd )
222 {
223   setFrameStyle( StyledPanel | Sunken );
224
225   QGridLayout* l = new QGridLayout( this );
226   l->setMargin( MARGIN );
227   l->setSpacing( SPACING );
228
229   int index = 0;
230
231   // object
232   QLabel* aNameLab     = new QLabel( tr( "NAME_LAB" ), this );
233   QLabel* aName        = createField();
234   aName->setObjectName("meshName");
235   aName->setMinimumWidth( 150 );
236   QLabel* aObjLab      = new QLabel( tr( "OBJECT_LAB" ), this );
237   QLabel* aObj         = createField();
238   aObj->setObjectName("meshType");
239   aObj->setMinimumWidth( 150 );
240   myWidgets[ index++ ] << aNameLab << aName;
241   myWidgets[ index++ ] << aObjLab  << aObj;
242
243   // nodes
244   QWidget* aNodesLine  = createLine();
245   QLabel*  aNodesLab   = new QLabel( tr( "NODES_LAB" ), this );
246   QLabel*  aNodes      = createField();
247   aNodes->setObjectName("nbNodes");
248   myWidgets[ index++ ] << aNodesLine;
249   myWidgets[ index++ ] << aNodesLab << aNodes;
250
251   // elements
252   QWidget* aElemLine   = createLine();
253   QLabel*  aElemLab    = new QLabel( tr( "ELEMENTS_LAB" ),     this );
254   QLabel*  aElemTotal  = new QLabel( tr( "TOTAL_LAB" ),        this );
255   QLabel*  aElemLin    = new QLabel( tr( "LINEAR_LAB" ),       this );
256   QLabel*  aElemQuad   = new QLabel( tr( "QUADRATIC_LAB" ),    this );
257   QLabel*  aElemBiQuad = new QLabel( tr( "BI_QUADRATIC_LAB" ), this );
258   myWidgets[ index++ ] << aElemLine;
259   myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad << aElemBiQuad;
260
261   // ... Number elements
262   QWidget* aNbLine     = createLine(); 
263   QLabel*  aNbTotal    = createField();
264   aNbTotal->setObjectName("totalNbElems");
265   QLabel*  aNbLin      = createField();
266   aNbLin->setObjectName("totalNbLinearElems");
267   QLabel*  aNbQuad     = createField();
268   aNbQuad->setObjectName("totalNbQuadraticElems");
269   QLabel*  aNbBiQuad   = createField();
270   aNbQuad->setObjectName("totalNbBiQuadraticElems");
271   myWidgets[ index++ ] << aNbLine;
272   myWidgets[ index++ ] << new QLabel( "", this ) << aNbTotal << aNbLin << aNbQuad << aNbBiQuad;
273
274   // ... 0D elements
275   QWidget* a0DLine     = createLine();
276   QLabel*  a0DLab      = new QLabel( tr( "0D_LAB" ), this );
277   QLabel*  a0DTotal    = createField();
278   a0DTotal->setObjectName("nb0D");
279
280   myWidgets[ index++ ] << a0DLine;
281   myWidgets[ index++ ] << a0DLab << a0DTotal;
282
283   // ... Ball elements
284   QWidget* aBallLine     = createLine();
285   QLabel*  aBallLab      = new QLabel( tr( "BALL_LAB" ), this );
286   QLabel*  aBallTotal    = createField();
287   aBallTotal->setObjectName("nbBall");
288   myWidgets[ index++ ] << aBallLine;
289   myWidgets[ index++ ] << aBallLab << aBallTotal;
290
291   // ... 1D elements
292   QWidget* a1DLine     = createLine();
293   QLabel*  a1DLab      = new QLabel( tr( "1D_LAB" ), this );
294   QLabel*  a1DTotal    = createField();
295   a1DTotal->setObjectName("nb1D");
296   QLabel*  a1DLin      = createField();
297   a1DLin->setObjectName("nbLinear1D");
298   QLabel*  a1DQuad     = createField();
299   a1DQuad->setObjectName("nbQuadratic1D");
300   myWidgets[ index++ ] << a1DLine;
301   myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad;
302
303   // ... 2D elements
304   QWidget* a2DLine      = createLine();
305   QLabel*  a2DLab       = new QLabel( tr( "2D_LAB" ), this );
306   QLabel*  a2DTotal     = createField();
307   a2DTotal->setObjectName("nb2D");
308   QLabel*  a2DLin       = createField();
309   a2DLin->setObjectName("nbLinear2D");
310   QLabel*  a2DQuad      = createField();
311   a2DQuad->setObjectName("nbQuadratic2D");
312   QLabel*  a2DBiQuad    = createField();
313   a2DBiQuad->setObjectName("nbBiQuadratic2D");
314   QLabel*  a2DTriLab    = new QLabel( tr( "TRIANGLES_LAB" ), this );
315   QLabel*  a2DTriTotal  = createField();
316   a2DTriTotal->setObjectName("nbTriangle");
317   QLabel*  a2DTriLin    = createField();
318   a2DTriLin->setObjectName("nbLinearTriangle");
319   QLabel*  a2DTriQuad   = createField();
320   a2DTriQuad->setObjectName("nbQuadraticTriangle");
321   QLabel*  a2DTriBiQuad = createField();
322   a2DTriBiQuad->setObjectName("nbBiQuadraticTriangle");
323   QLabel*  a2DQuaLab    = new QLabel( tr( "QUADRANGLES_LAB" ), this );
324   QLabel*  a2DQuaTotal  = createField();
325   a2DQuaTotal->setObjectName("nbQuadrangle");
326   QLabel*  a2DQuaLin    = createField();
327   a2DQuaLin->setObjectName("nbLinearQuadrangle");
328   QLabel*  a2DQuaQuad   = createField();
329   a2DQuaQuad->setObjectName("nbQuadraticQuadrangle");
330   QLabel*  a2DQuaBiQuad = createField();
331   a2DQuaBiQuad->setObjectName("nbBiQuadraticQuadrangle");
332   QLabel*  a2DPolLab    = new QLabel( tr( "POLYGONS_LAB" ), this );
333   QLabel*  a2DPolTotal  = createField();
334   a2DPolTotal->setObjectName("nbPolygon");
335   myWidgets[ index++ ] << a2DLine;
336   myWidgets[ index++ ] << a2DLab    << a2DTotal    << a2DLin    << a2DQuad    << a2DBiQuad;
337   myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad << a2DTriBiQuad;
338   myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad << a2DQuaBiQuad;
339   myWidgets[ index++ ] << a2DPolLab << a2DPolTotal;
340
341   // ... 3D elements
342   QWidget* a3DLine      = createLine();
343   QLabel*  a3DLab       = new QLabel( tr( "3D_LAB" ), this );
344   QLabel*  a3DTotal     = createField();
345   a3DTotal->setObjectName("nb3D");
346   QLabel*  a3DLin       = createField();
347   a3DLin->setObjectName("nbLinear3D");
348   QLabel*  a3DQuad      = createField();
349   a3DQuad->setObjectName("nbQuadratic3D");
350   QLabel*  a3DBiQuad    = createField();
351   a3DBiQuad->setObjectName("nbBiQuadratic3D");
352   QLabel*  a3DTetLab    = new QLabel( tr( "TETRAHEDRONS_LAB" ), this );
353   QLabel*  a3DTetTotal  = createField();
354   a3DTetTotal->setObjectName("nbTetrahedron");
355   QLabel*  a3DTetLin    = createField();
356   a3DTetLin->setObjectName("nbLinearTetrahedron");
357   QLabel*  a3DTetQuad   = createField();
358   a3DTetQuad->setObjectName("nbQudraticTetrahedron");
359   QLabel*  a3DHexLab    = new QLabel( tr( "HEXAHEDONRS_LAB" ), this );
360   QLabel*  a3DHexTotal  = createField();
361   a3DHexTotal->setObjectName("nbHexahedron");
362   QLabel*  a3DHexLin    = createField();
363   a3DHexLin->setObjectName("nbLinearHexahedron");
364   QLabel*  a3DHexQuad   = createField();
365   a3DHexQuad->setObjectName("nbQuadraticHexahedron");
366   QLabel*  a3DHexBiQuad = createField();
367   a3DHexBiQuad->setObjectName("nbBiQuadraticHexahedron");
368   QLabel*  a3DPyrLab    = new QLabel( tr( "PYRAMIDS_LAB" ), this );
369   QLabel*  a3DPyrTotal  = createField();
370   a3DPyrTotal->setObjectName("nbPyramid");
371   QLabel*  a3DPyrLin    = createField();
372   a3DPyrLin->setObjectName("nbLinearPyramid");
373   QLabel*  a3DPyrQuad   = createField();
374   a3DPyrQuad->setObjectName("nbQuadraticPyramid");
375   QLabel*  a3DPriLab    = new QLabel( tr( "PRISMS_LAB" ), this );
376   QLabel*  a3DPriTotal  = createField();
377   a3DPriTotal->setObjectName("nbPrism");
378   QLabel*  a3DPriLin    = createField();
379   a3DPriLin->setObjectName("nbLinearPrism");
380   QLabel*  a3DPriQuad   = createField();
381   a3DPriQuad->setObjectName("nbQuadraticPrism");
382   QLabel*  a3DHexPriLab   = new QLabel( tr( "HEX_PRISMS_LAB" ), this );
383   QLabel*  a3DHexPriTotal = createField();
384   a3DHexPriTotal->setObjectName("nbHexagonalPrism");
385   QLabel*  a3DPolLab    = new QLabel( tr( "POLYHEDRONS_LAB" ), this );
386   QLabel*  a3DPolTotal  = createField();
387   a3DPolTotal->setObjectName("nbPolyhedron");
388   myWidgets[ index++ ] << a3DLine;
389   myWidgets[ index++ ] << a3DLab    << a3DTotal    << a3DLin    << a3DQuad    << a3DBiQuad;
390   myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad;
391   myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad << a3DHexBiQuad;
392   myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad;
393   myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad;
394   myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal;
395   myWidgets[ index++ ] << a3DPolLab << a3DPolTotal;
396
397   myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this );
398   myLoadBtn->setAutoDefault( true );
399   connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) );
400   
401   setFontAttributes( aNameLab,    Bold );
402   setFontAttributes( aObjLab,     Bold );
403   setFontAttributes( aNodesLab,   Bold );
404   setFontAttributes( aElemLab,    Bold );
405   setFontAttributes( aElemTotal,  Italic );
406   setFontAttributes( aElemLin,    Italic );
407   setFontAttributes( aElemQuad,   Italic );
408   setFontAttributes( aElemBiQuad, Italic );
409   setFontAttributes( a0DLab,      Bold );
410   setFontAttributes( aBallLab,    Bold );
411   setFontAttributes( a1DLab,      Bold );
412   setFontAttributes( a2DLab,      Bold );
413   setFontAttributes( a3DLab,      Bold );
414
415   l->addWidget( aNameLab,     0, 0 );
416   l->addWidget( aName,        0, 1, 1, 4 );
417   l->addWidget( aObjLab,      1, 0 );
418   l->addWidget( aObj,         1, 1, 1, 4 );
419   l->addWidget( aNodesLine,   2, 0, 1, 5 );
420   l->addWidget( aNodesLab,    3, 0 );
421   l->addWidget( aNodes,       3, 1 );
422   l->addWidget( aElemLine,    4, 0, 1, 5 );
423   l->addWidget( aElemLab,     5, 0 );
424   l->addWidget( aElemTotal,   5, 1 );
425   l->addWidget( aElemLin,     5, 2 );
426   l->addWidget( aElemQuad,    5, 3 );
427   l->addWidget( aElemBiQuad,  5, 4 );
428   l->addWidget( aNbLine,      6, 1, 1, 4 );
429   l->addWidget( aNbTotal,     7, 1 );
430   l->addWidget( aNbLin,       7, 2 );
431   l->addWidget( aNbQuad,      7, 3 );
432   l->addWidget( aNbBiQuad,    7, 4 );
433   l->addWidget( a0DLine,      8, 1, 1, 4 );
434   l->addWidget( a0DLab,       9, 0 );
435   l->addWidget( a0DTotal,     9, 1 );
436   l->addWidget( aBallLine,    10, 1, 1, 4 );
437   l->addWidget( aBallLab,     11, 0 );
438   l->addWidget( aBallTotal,   11, 1 );
439   l->addWidget( a1DLine,      12, 1, 1, 4 );
440   l->addWidget( a1DLab,       13, 0 );
441   l->addWidget( a1DTotal,     13, 1 );
442   l->addWidget( a1DLin,       13, 2 );
443   l->addWidget( a1DQuad,      13, 3 );
444   l->addWidget( a2DLine,      14, 1, 1, 4 );
445   l->addWidget( a2DLab,       15, 0 );
446   l->addWidget( a2DTotal,     15, 1 );
447   l->addWidget( a2DLin,       15, 2 );
448   l->addWidget( a2DQuad,      15, 3 );
449   l->addWidget( a2DBiQuad,    15, 4 );
450   l->addWidget( a2DTriLab,    16, 0 );
451   l->addWidget( a2DTriTotal,  16, 1 );
452   l->addWidget( a2DTriLin,    16, 2 );
453   l->addWidget( a2DTriQuad,   16, 3 );
454   l->addWidget( a2DTriBiQuad, 16, 4 );
455   l->addWidget( a2DQuaLab,    17, 0 );
456   l->addWidget( a2DQuaTotal,  17, 1 );
457   l->addWidget( a2DQuaLin,    17, 2 );
458   l->addWidget( a2DQuaQuad,   17, 3 );
459   l->addWidget( a2DQuaBiQuad, 17, 4 );
460   l->addWidget( a2DPolLab,    18, 0 );
461   l->addWidget( a2DPolTotal,  18, 1 );
462   l->addWidget( a3DLine,      19, 1, 1, 4 );
463   l->addWidget( a3DLab,       20, 0 );
464   l->addWidget( a3DTotal,     20, 1 );
465   l->addWidget( a3DLin,       20, 2 );
466   l->addWidget( a3DQuad,      20, 3 );
467   l->addWidget( a3DBiQuad,    20, 4 );
468   l->addWidget( a3DTetLab,    21, 0 );
469   l->addWidget( a3DTetTotal,  21, 1 );
470   l->addWidget( a3DTetLin,    21, 2 );
471   l->addWidget( a3DTetQuad,   21, 3 );
472   l->addWidget( a3DHexLab,    22, 0 );
473   l->addWidget( a3DHexTotal,  22, 1 );
474   l->addWidget( a3DHexLin,    22, 2 );
475   l->addWidget( a3DHexQuad,   22, 3 );
476   l->addWidget( a3DHexBiQuad, 22, 4 );
477   l->addWidget( a3DPyrLab,    23, 0 );
478   l->addWidget( a3DPyrTotal,  23, 1 );
479   l->addWidget( a3DPyrLin,    23, 2 );
480   l->addWidget( a3DPyrQuad,   23, 3 );
481   l->addWidget( a3DPriLab,    24, 0 );
482   l->addWidget( a3DPriTotal,  24, 1 );
483   l->addWidget( a3DPriLin,    24, 2 );
484   l->addWidget( a3DPriQuad,   24, 3 );
485   l->addWidget( a3DHexPriLab,   25, 0 );
486   l->addWidget( a3DHexPriTotal, 25, 1 );
487   l->addWidget( a3DPolLab,    26, 0 );
488   l->addWidget( a3DPolTotal,  26, 1 );
489   l->addWidget( myLoadBtn,    28, 1, 1, 4 );
490
491   l->setColumnStretch( 0, 0 );
492   l->setColumnStretch( 1, 5 );
493   l->setColumnStretch( 2, 5 );
494   l->setColumnStretch( 3, 5 );
495   l->setColumnStretch( 4, 5 );
496   l->setRowStretch( 27, 5 );
497
498   clear();
499 }
500
501 /*!
502   \brief Destructor
503 */
504 SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo()
505 {
506 }
507
508 /*!
509   \brief Show information on the mesh object.
510   \param obj object being processed (mesh, sub-mesh, group, ID source)
511 */
512 void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
513 {
514   clear();
515   if ( !CORBA::is_nil( obj ) ) {
516     _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
517     if ( sobj ) 
518       myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() );
519     SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
520     SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
521     SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
522     if ( !aMesh->_is_nil() ) {
523       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) );
524     }
525     else if ( !aSubMesh->_is_nil() ) {
526       myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) );
527     }
528     else if ( !aGroup->_is_nil() ) {
529       QString objType;
530       switch( aGroup->GetType() ) {
531       case SMESH::NODE:  objType = tr( "OBJECT_GROUP_NODES"   );break;
532       case SMESH::EDGE:  objType = tr( "OBJECT_GROUP_EDGES"   );break;
533       case SMESH::FACE:  objType = tr( "OBJECT_GROUP_FACES"   );break;
534       case SMESH::VOLUME:objType = tr( "OBJECT_GROUP_VOLUMES" );break;
535       case SMESH::ELEM0D:objType = tr( "OBJECT_GROUP_0DELEMS" );break;
536       case SMESH::BALL:  objType = tr( "OBJECT_GROUP_BALLS"   );break;
537       default:           objType = tr( "OBJECT_GROUP"         );break;
538       }
539       myWidgets[iObject][iSingle]->setProperty( "text", objType );
540     }
541     SMESH::long_array_var info = obj->GetMeshInfo();
542     myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) );
543     myWidgets[i0D][iTotal]    ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) );
544     myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ) );
545     long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge];
546     myWidgets[i1D][iTotal]    ->setProperty( "text", QString::number( nbEdges ) );
547     myWidgets[i1D][iLinear]   ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) );
548     myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) );
549     long nbTriangles     = info[SMDSEntity_Triangle]   + info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_BiQuad_Triangle];
550     long nbQuadrangles   = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle];
551     long nb2DLinear      = info[SMDSEntity_Triangle]        + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon];
552     long nb2DQuadratic   = info[SMDSEntity_Quad_Triangle]   + info[SMDSEntity_Quad_Quadrangle];
553     long nb2DBiQuadratic = info[SMDSEntity_BiQuad_Triangle] + info[SMDSEntity_BiQuad_Quadrangle];
554     long nb2DTotal       = nb2DLinear + nb2DQuadratic + nb2DBiQuadratic;
555
556     myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( nb2DTotal ));
557     myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( nb2DLinear ) );
558     myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( nb2DQuadratic ) );
559     myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( nb2DBiQuadratic ) );
560     myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( nbTriangles ) );
561     myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) );
562     myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) );
563     myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Triangle] ) );
564     myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( nbQuadrangles ) );
565     myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) );
566     myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] ) );
567     myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_BiQuad_Quadrangle] ) );
568     myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) );
569     long nbTetrahedrons  = info[SMDSEntity_Tetra]   + info[SMDSEntity_Quad_Tetra];
570     long nbHexahedrons   = info[SMDSEntity_Hexa]    + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa];
571     long nbPyramids      = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid];
572     long nbPrisms        = info[SMDSEntity_Penta]   + info[SMDSEntity_Quad_Penta];
573     long nb3DLinear      = info[SMDSEntity_Tetra]   + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism];
574     long nb3DQuadratic   = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta];
575     long nb3DBiQuadratic = info[SMDSEntity_TriQuad_Hexa];
576     long nb3DTotal       = nb3DLinear + nb3DQuadratic + nb3DBiQuadratic;
577     myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( nb3DTotal ) );
578     myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( nb3DLinear ) );
579     myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( nb3DQuadratic ) );
580     myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( nb3DBiQuadratic ) );
581     myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( nbTetrahedrons ) );
582     myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) );
583     myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) );
584     myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( nbHexahedrons ) );
585     myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) );
586     myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] ) );
587     myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_TriQuad_Hexa] ) );
588     myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( nbPyramids ) );
589     myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) );
590     myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) );
591     myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( nbPrisms ) );
592     myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) );
593     myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) );
594     myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) );
595     myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) );
596     long nbElemTotal       = info[SMDSEntity_0D] + info[SMDSEntity_Ball] + nbEdges + nb2DTotal + nb3DTotal;
597     long nbElemLinerial    = info[SMDSEntity_Edge] + nb2DLinear + nb3DLinear;
598     long nbElemQuadratic   = info[SMDSEntity_Quad_Edge] + nb2DQuadratic + nb3DQuadratic;
599     long nbElemBiQuadratic = nb2DBiQuadratic + nb3DBiQuadratic;
600     myWidgets[iNb][iTotal]      ->setProperty( "text", QString::number( nbElemTotal ) );
601     myWidgets[iNb][iLinear]     ->setProperty( "text", QString::number( nbElemLinerial ) );
602     myWidgets[iNb][iQuadratic]  ->setProperty( "text", QString::number( nbElemQuadratic ) );
603     myWidgets[iNb][iBiQuadratic]->setProperty( "text", QString::number( nbElemBiQuadratic ) );
604     // before full loading from study file, type of elements in a sub-mesh can't be defined
605     // in some cases
606     bool infoOK = obj->IsMeshInfoCorrect();
607     myLoadBtn->setVisible( !infoOK );
608     if ( !infoOK )
609     {
610       // two options:
611       // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh)
612       // 2. No info at all (for a group on geom or filter)
613       bool hasAnyInfo = false;
614       for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i )
615         hasAnyInfo = info[i];
616       if ( hasAnyInfo ) // believe it is a sub-mesh
617       {
618         if ( nb2DLinear + nb2DQuadratic + nb2DBiQuadratic > 0 )
619         {
620           myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
621           myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
622           myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
623           myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
624           myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
625           myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
626           myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
627           myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
628           myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
629           myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
630           myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
631           myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
632           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
633           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
634           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
635           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
636         }
637         else if ( nb3DLinear + nb3DQuadratic + nb3DBiQuadratic > 0 )
638         {
639           myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
640           myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
641           myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", "?" );
642           myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
643           myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
644           myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
645           myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
646           myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
647           myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
648           myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
649           myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
650           myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
651           myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
652           myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
653           myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
654           myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
655           myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
656           myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
657           myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
658           myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
659           myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
660           myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
661         }
662       }
663       else
664       {
665         myWidgets[iNodes][iTotal]               ->setProperty( "text", "?" );
666         myWidgets[i0D][iTotal]                  ->setProperty( "text", "?" );
667         myWidgets[iBalls][iTotal]               ->setProperty( "text", "?" );
668         myWidgets[i1D][iTotal]                  ->setProperty( "text", "?" );
669         myWidgets[i1D][iLinear]                 ->setProperty( "text", "?" );
670         myWidgets[i1D][iQuadratic]              ->setProperty( "text", "?" );
671         myWidgets[i2D][iTotal]                  ->setProperty( "text", "?" );
672         myWidgets[i2D][iLinear]                 ->setProperty( "text", "?" );
673         myWidgets[i2D][iQuadratic]              ->setProperty( "text", "?" );
674         myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", "?" );
675         myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", "?" );
676         myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", "?" );
677         myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", "?" );
678         myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", "?" );
679         myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", "?" );
680         myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", "?" );
681         myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", "?" );
682         myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", "?" );
683         myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", "?" );
684         myWidgets[i3D][iTotal]                  ->setProperty( "text", "?" );
685         myWidgets[i3D][iLinear]                 ->setProperty( "text", "?" );
686         myWidgets[i3D][iQuadratic]              ->setProperty( "text", "?" );
687         myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", "?" );
688         myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", "?" );
689         myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", "?" );
690         myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", "?" );
691         myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", "?" );
692         myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", "?" );
693         myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", "?" );
694         myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", "?" );
695         myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", "?" );
696         myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", "?" );
697         myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", "?" );
698         myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", "?" );
699         myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", "?" );
700         myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", "?" );
701         myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", "?" );
702         myWidgets[iNb][iTotal]                  ->setProperty( "text", "?" );
703         myWidgets[iNb][iLinear]                 ->setProperty( "text", "?" );
704         myWidgets[iNb][iQuadratic]              ->setProperty( "text", "?" );
705         myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", "?" );
706       }
707     }
708   }
709 }
710
711 /*!
712   \brief Load mesh from a study file
713 */
714 void SMESHGUI_MeshInfo::loadMesh()
715 {
716   SUIT_OverrideCursor wc;
717
718   SALOME_ListIO selected;
719   SMESHGUI::selectionMgr()->selectedObjects( selected );
720
721   if ( selected.Extent() == 1 ) {
722     Handle(SALOME_InteractiveObject) IO = selected.First();
723     SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
724     if ( !CORBA::is_nil( obj ) ) {
725       SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
726       if ( !mesh->_is_nil() )
727       {
728         mesh->Load();
729         showInfo( obj );
730       }
731     }
732   }
733 }
734
735 /*!
736   \brief Reset the widget to the initial state (nullify all fields).
737 */
738 void SMESHGUI_MeshInfo::clear()
739 {
740   myWidgets[iName][iSingle]               ->setProperty( "text", QString() );
741   myWidgets[iObject][iSingle]             ->setProperty( "text", QString() );
742   myWidgets[iNodes][iTotal]               ->setProperty( "text", QString::number( 0 ) );
743   myWidgets[i0D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
744   myWidgets[iBalls][iTotal]               ->setProperty( "text", QString::number( 0 ) );
745   myWidgets[i1D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
746   myWidgets[i1D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
747   myWidgets[i1D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
748   myWidgets[i2D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
749   myWidgets[i2D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
750   myWidgets[i2D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
751   myWidgets[i2D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
752   myWidgets[i2DTriangles][iTotal]         ->setProperty( "text", QString::number( 0 ) );
753   myWidgets[i2DTriangles][iLinear]        ->setProperty( "text", QString::number( 0 ) );
754   myWidgets[i2DTriangles][iQuadratic]     ->setProperty( "text", QString::number( 0 ) );
755   myWidgets[i2DTriangles][iBiQuadratic]   ->setProperty( "text", QString::number( 0 ) );
756   myWidgets[i2DQuadrangles][iTotal]       ->setProperty( "text", QString::number( 0 ) );
757   myWidgets[i2DQuadrangles][iLinear]      ->setProperty( "text", QString::number( 0 ) );
758   myWidgets[i2DQuadrangles][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
759   myWidgets[i2DQuadrangles][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
760   myWidgets[i2DPolygons][iTotal]          ->setProperty( "text", QString::number( 0 ) );
761   myWidgets[i3D][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
762   myWidgets[i3D][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
763   myWidgets[i3D][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
764   myWidgets[i3D][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
765   myWidgets[i3DTetrahedrons][iTotal]      ->setProperty( "text", QString::number( 0 ) );
766   myWidgets[i3DTetrahedrons][iLinear]     ->setProperty( "text", QString::number( 0 ) );
767   myWidgets[i3DTetrahedrons][iQuadratic]  ->setProperty( "text", QString::number( 0 ) );
768   myWidgets[i3DHexahedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
769   myWidgets[i3DHexahedrons][iLinear]      ->setProperty( "text", QString::number( 0 ) );
770   myWidgets[i3DHexahedrons][iQuadratic]   ->setProperty( "text", QString::number( 0 ) );
771   myWidgets[i3DHexahedrons][iBiQuadratic] ->setProperty( "text", QString::number( 0 ) );
772   myWidgets[i3DPyramids][iTotal]          ->setProperty( "text", QString::number( 0 ) );
773   myWidgets[i3DPyramids][iLinear]         ->setProperty( "text", QString::number( 0 ) );
774   myWidgets[i3DPyramids][iQuadratic]      ->setProperty( "text", QString::number( 0 ) );
775   myWidgets[i3DPrisms][iTotal]            ->setProperty( "text", QString::number( 0 ) );
776   myWidgets[i3DPrisms][iLinear]           ->setProperty( "text", QString::number( 0 ) );
777   myWidgets[i3DPrisms][iQuadratic]        ->setProperty( "text", QString::number( 0 ) );
778   myWidgets[i3DHexaPrisms][iTotal]        ->setProperty( "text", QString::number( 0 ) );
779   myWidgets[i3DPolyhedrons][iTotal]       ->setProperty( "text", QString::number( 0 ) );
780   myWidgets[iNb][iTotal]                  ->setProperty( "text", QString::number( 0 ) );
781   myWidgets[iNb][iLinear]                 ->setProperty( "text", QString::number( 0 ) );
782   myWidgets[iNb][iQuadratic]              ->setProperty( "text", QString::number( 0 ) );
783   myWidgets[iNb][iBiQuadratic]            ->setProperty( "text", QString::number( 0 ) );
784 }
785
786 /*!
787   \brief Create info field
788   \return new info field
789 */
790 QLabel* SMESHGUI_MeshInfo::createField()
791 {
792   QLabel* lab = new QLabel( this );
793   lab->setFrameStyle( StyledPanel | Sunken );
794   lab->setAlignment( Qt::AlignCenter );
795   lab->setAutoFillBackground( true );
796   QPalette pal = lab->palette();
797   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
798   lab->setPalette( pal );
799   lab->setMinimumWidth( 70 );
800   return lab;
801 }
802
803 /*!
804   \brief Create horizontal rule.
805   \return new line object
806 */
807 QWidget* SMESHGUI_MeshInfo::createLine()
808 {
809   QFrame* line = new QFrame( this );
810   line->setFrameStyle( HLine | Sunken );
811   return line;
812 }
813
814 /*!
815   \brief Change widget font attributes (bold, italic, ...).
816   \param w widget
817   \param attr font attributes (XORed flags)
818   \param val value to be set to attributes
819 */
820 void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val )
821 {
822   if ( w && attr ) {
823     QFont f = w->font();
824     if ( attr & Bold   ) f.setBold( val );
825     if ( attr & Italic ) f.setItalic( val );
826     w->setFont( f );
827   }
828 }
829
830 /*!
831   \brief Show/hide group(s) of fields.
832   \param start beginning of the block
833   \param end end of the block
834   \param on visibility flag
835 */
836 void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on )
837 {
838   start = qMax( 0, start );
839   end   = qMin( end, (int)iElementsEnd );
840   for ( int i = start; i < end; i++ ) {
841     wlist wl = myWidgets[i];
842     foreach ( QWidget* w, wl ) w->setVisible( on );
843   }
844 }
845
846 void SMESHGUI_MeshInfo::saveInfo( QTextStream &out )
847 {
848   out << QString( 9, '-' ) << "\n";
849   out << tr( "BASE_INFO" ) << "\n";
850   out << QString( 9, '-' ) << "\n";
851   out <<                                   tr( "NAME_LAB" )         << "  " << ( myWidgets[iName][iSingle]->property( "text" ) ).toString() << "\n";
852   out <<                                   tr( "OBJECT_LAB" )       << "  " << ( myWidgets[iObject][iSingle]->property( "text" ) ).toString() << "\n";
853   out <<                                   tr( "NODES_LAB" )        << "  " << ( myWidgets[iNodes][iTotal]->property( "text" ) ).toString() << "\n";
854   out <<                                   tr( "ELEMENTS_LAB" )     << "\n";
855   out << QString( SPACING_INFO,   ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iNb][iTotal]->property( "text" ) ).toString() << "\n";
856   out << QString( SPACING_INFO,   ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[iNb][iLinear]->property( "text" ) ).toString() << "\n";
857   out << QString( SPACING_INFO,   ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[iNb][iQuadratic]->property( "text" ) ).toString() << "\n";
858   out << QString( SPACING_INFO,   ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[iNb][iBiQuadratic]->property( "text" ) ).toString() << "\n";
859   out << QString( SPACING_INFO,   ' ' ) << tr( "0D_LAB" )           << "\n";
860   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i0D][iTotal]->property( "text" ) ).toString() << "\n";
861   out << QString( SPACING_INFO,   ' ' ) << tr( "BALL_LAB" )         << "\n";
862   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[iBalls][iTotal]->property( "text" ) ).toString() << "\n";
863   out << QString( SPACING_INFO,   ' ' ) << tr( "1D_LAB" )           << "\n";
864   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i1D][iTotal]->property( "text" ) ).toString() << "\n";
865   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i1D][iLinear]->property( "text" ) ).toString() << "\n";
866   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i1D][iQuadratic]->property( "text" ) ).toString() << "\n";
867   out << QString( SPACING_INFO,   ' ' ) << tr( "2D_LAB" )           << "\n";
868   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2D][iTotal]->property( "text" ) ).toString() << "\n";
869   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2D][iLinear]->property( "text" ) ).toString() << "\n";
870   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2D][iQuadratic]->property( "text" ) ).toString() << "\n";
871   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
872   out << QString( SPACING_INFO*2, ' ' ) << tr( "TRIANGLES_LAB" )    << "\n";
873   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DTriangles][iTotal]->property( "text" ) ).toString() << "\n";
874   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DTriangles][iLinear]->property( "text" ) ).toString() << "\n";
875   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DTriangles][iQuadratic]->property( "text" ) ).toString() << "\n";
876   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DTriangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
877   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRANGLES_LAB" )  << "\n";
878   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DQuadrangles][iTotal]->property( "text" ) ).toString() << "\n";
879   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i2DQuadrangles][iLinear]->property( "text" ) ).toString() << "\n";
880   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i2DQuadrangles][iQuadratic]->property( "text" ) ).toString() << "\n";
881   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i2DQuadrangles][iBiQuadratic]->property( "text" ) ).toString() << "\n";
882   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYGONS_LAB" )     << "\n";
883   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i2DPolygons][iTotal]->property( "text" ) ).toString() << "\n";
884   out << QString( SPACING_INFO,   ' ' ) << tr( "3D_LAB" )           << "\n";
885   out << QString( SPACING_INFO*2, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3D][iTotal]->property( "text" ) ).toString() << "\n";
886   out << QString( SPACING_INFO*2, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3D][iLinear]->property( "text" ) ).toString() << "\n";
887   out << QString( SPACING_INFO*2, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3D][iQuadratic]->property( "text" ) ).toString() << "\n";
888   out << QString( SPACING_INFO*2, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3D][iBiQuadratic]->property( "text" ) ).toString() << "\n";
889   out << QString( SPACING_INFO*2, ' ' ) << tr( "TETRAHEDRONS_LAB" ) << "\n";
890   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DTetrahedrons][iTotal]->property( "text" ) ).toString() << "\n";
891   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DTetrahedrons][iLinear]->property( "text" ) ).toString() << "\n";
892   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DTetrahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
893   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEXAHEDONRS_LAB" )  << "\n";
894   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexahedrons][iTotal]->property( "text" ) ).toString() << "\n";
895   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DHexahedrons][iLinear]->property( "text" ) ).toString() << "\n";
896   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DHexahedrons][iQuadratic]->property( "text" ) ).toString() << "\n";
897   out << QString( SPACING_INFO*3, ' ' ) << tr( "BI_QUADRATIC_LAB" ) << ": " << ( myWidgets[i3DHexahedrons][iBiQuadratic]->property( "text" ) ).toString() << "\n";
898   out << QString( SPACING_INFO*2, ' ' ) << tr( "PYRAMIDS_LAB" )     << "\n";
899   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPyramids][iTotal]->property( "text" ) ).toString() << "\n";
900   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPyramids][iLinear]->property( "text" ) ).toString() << "\n";
901   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPyramids][iQuadratic]->property( "text" ) ).toString() << "\n";
902   out << QString( SPACING_INFO*2, ' ' ) << tr( "PRISMS_LAB" )       << "\n";
903   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPrisms][iTotal]->property( "text" ) ).toString() << "\n";
904   out << QString( SPACING_INFO*3, ' ' ) << tr( "LINEAR_LAB" )       << ": " << ( myWidgets[i3DPrisms][iLinear]->property( "text" ) ).toString() << "\n";
905   out << QString( SPACING_INFO*3, ' ' ) << tr( "QUADRATIC_LAB" )    << ": " << ( myWidgets[i3DPrisms][iQuadratic]->property( "text" ) ).toString() << "\n";
906   out << QString( SPACING_INFO*2, ' ' ) << tr( "HEX_PRISMS_LAB" )   << "\n";
907   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DHexaPrisms][iTotal]->property( "text" ) ).toString() << "\n";
908   out << QString( SPACING_INFO*2, ' ' ) << tr( "POLYHEDRONS_LAB" )  << "\n";
909   out << QString( SPACING_INFO*3, ' ' ) << tr( "TOTAL_LAB" )        << ": " << ( myWidgets[i3DPolyhedrons][iTotal]->property( "text" ) ).toString() << "\n" << "\n";
910 }
911
912 /*!
913   \class SMESHGUI_ElemInfo
914   \brief Base class for the mesh element information widget.
915 */
916
917 /*!
918   \brief Constructor
919   \param parent parent widget
920 */
921 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent )
922 : QWidget( parent ), myActor( 0 ), myIsElement( -1 )
923 {
924   myFrame = new QWidget( this );
925   myExtra = new ExtraWidget( this );
926   QVBoxLayout* vbl = new QVBoxLayout( this );
927   vbl->setMargin( 0 );
928   vbl->setSpacing( 0 );
929   vbl->addWidget( myFrame );
930   vbl->addWidget( myExtra );
931   connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
932   connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
933   clear();
934 }
935
936 /*!
937   \brief Destructor
938 */
939 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
940 {
941 }
942
943 /*!
944   \brief Set mesh data source (actor)
945   \param actor mesh object actor
946 */
947 void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor )
948 {
949   if ( myActor != actor ) {
950     myActor = actor;
951     myIsElement = -1;
952     clear();
953   }
954 }
955
956 /*!
957   \brief Show mesh element information
958   \param id mesh node / element ID
959   \param isElem show mesh element information if \c true or mesh node information if \c false
960 */
961 void SMESHGUI_ElemInfo::showInfo( long id, bool isElem )
962 {
963   QSet<long> ids;
964   ids << id;
965   showInfo( ids, isElem );
966 }
967
968 /*!
969   \brief Show mesh element information
970   \param ids mesh nodes / elements identifiers
971   \param isElem show mesh element information if \c true or mesh node information if \c false
972 */
973 void SMESHGUI_ElemInfo::showInfo( QSet<long> ids, bool isElem )
974 {
975   QList<long> newIds = ids.toList();
976   qSort( newIds );
977   if ( myIDs == newIds && myIsElement == isElem ) return;
978
979   myIDs = newIds;
980   myIsElement = isElem;
981   myIndex = 0;
982   updateControls();
983   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
984 }
985
986 /*!
987   \brief Clear mesh element information widget
988 */
989 void SMESHGUI_ElemInfo::clear()
990 {
991   myIDs.clear();
992   myIndex = 0;
993   clearInternal();
994   updateControls();
995 }
996
997 /*!
998   \brief Get central area widget
999   \return central widget
1000 */
1001 QWidget* SMESHGUI_ElemInfo::frame() const
1002 {
1003   return myFrame;
1004 }
1005
1006 /*!
1007   \brief Get actor
1008   \return actor being used
1009 */
1010 SMESH_Actor* SMESHGUI_ElemInfo::actor() const
1011 {
1012   return myActor;
1013 }
1014
1015 /*!
1016   \brief Get current info mode.
1017   \return \c true if mesh element information is shown or \c false if node information is shown
1018 */
1019 bool SMESHGUI_ElemInfo::isElements() const
1020 {
1021   return myIsElement;
1022 }
1023
1024 /*!
1025   \fn void SMESHGUI_ElemInfo::information( const QList<long>& ids )
1026   \brief Show information on the specified nodes / elements
1027
1028   This function is to be redefined in sub-classes.
1029
1030   \param ids nodes / elements identifiers information is to be shown on
1031 */
1032
1033 /*!
1034   \brief Internal clean-up (reset widget)
1035 */
1036 void SMESHGUI_ElemInfo::clearInternal()
1037 {
1038 }
1039
1040 /*!
1041   \brief Get node connectivity
1042   \param node mesh node
1043   \return node connectivity map
1044 */
1045 SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node )
1046 {
1047   Connectivity elmap;
1048   if ( node ) {
1049     SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
1050     while ( it && it->more() ) {
1051       const SMDS_MeshElement* ne = it->next();
1052       elmap[ ne->GetType() ] << ne->GetID();
1053     }
1054   }
1055   return elmap;
1056 }
1057
1058 /*!
1059   \brief Format connectivity data to string representation
1060   \param connectivity connetivity map
1061   \param type element type
1062   \return string representation of the connectivity
1063 */
1064 QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type )
1065 {
1066   QStringList str;
1067   if ( connectivity.contains( type ) ) {
1068     QList<int> elements = connectivity[ type ];
1069     qSort( elements );
1070     foreach( int id, elements )
1071       str << QString::number( id );
1072   }
1073   return str.join( " " );
1074 }
1075
1076 /*!
1077   \brief Calculate gravity center of the mesh element
1078   \param element mesh element
1079 */
1080 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element )
1081 {
1082   XYZ xyz;
1083   if ( element ) {
1084     SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
1085     while ( nodeIt->more() ) {
1086       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1087       xyz.add( node->X(), node->Y(), node->Z() );
1088     }
1089     xyz.divide( element->NbNodes() );
1090   }
1091   return xyz;
1092 }
1093
1094 /*!
1095   \brief Calculate normal vector to the mesh face
1096   \param element mesh face
1097 */
1098 SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::normal( const SMDS_MeshElement* element )
1099 {
1100   gp_XYZ n = SMESH::getNormale( dynamic_cast<const SMDS_MeshFace*>( element ) );
1101   return XYZ(n.X(), n.Y(), n.Z());
1102 }
1103
1104 /*!
1105   \brief This slot is called from "Show Previous" button click.
1106   Shows information on the previous group of the items.
1107 */
1108 void SMESHGUI_ElemInfo::showPrevious()
1109 {
1110   myIndex = qMax( 0, myIndex-1 );
1111   updateControls();
1112   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1113 }
1114
1115 /*!
1116   \brief This slot is called from "Show Next" button click.
1117   Shows information on the next group of the items.
1118 */
1119 void SMESHGUI_ElemInfo::showNext()
1120 {
1121   myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS );
1122   updateControls();
1123   information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) );
1124 }
1125
1126 /*!
1127   \brief Update widgets state
1128 */
1129 void SMESHGUI_ElemInfo::updateControls()
1130 {
1131   myExtra->updateControls( myIDs.count(), myIndex );
1132 }
1133
1134 /*!
1135   \class SMESHGUI_SimpleElemInfo
1136   \brief Represents mesh element information in the simple text area.
1137 */
1138
1139 /*!
1140   \brief Constructor
1141   \param parent parent widget
1142 */
1143 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
1144 : SMESHGUI_ElemInfo( parent )
1145 {
1146   myInfo = new QTextBrowser( frame() );
1147   QVBoxLayout* l = new QVBoxLayout( frame() );
1148   l->setMargin( 0 );
1149   l->addWidget( myInfo );
1150 }
1151
1152 /*!
1153   \brief Show mesh element information
1154   \param ids mesh nodes / elements identifiers
1155 */
1156 void SMESHGUI_SimpleElemInfo::information( const QList<long>& ids )
1157 {
1158   clearInternal();
1159   
1160   if ( actor() ) {
1161     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1162     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1163     int cprecision = -1;
1164     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1165       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1166     foreach ( long id, ids ) {
1167       if ( !isElements() ) {
1168         //
1169         // show node info
1170         //
1171         const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id );
1172         if ( !node ) return;
1173
1174         // node ID
1175         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( id ) );
1176         // separator
1177         myInfo->append( "" );
1178         // coordinates
1179         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1180                         arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1181                         arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1182                         arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1183         // separator
1184         myInfo->append( "" );
1185         // connectivity
1186         Connectivity connectivity = nodeConnectivity( node );
1187         if ( !connectivity.isEmpty() ) {
1188           myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1189           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1190           if ( !con.isEmpty() )
1191             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1192           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1193           if ( !con.isEmpty() )
1194             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1195           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1196           if ( !con.isEmpty() )
1197             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) ).arg( con ) );
1198           con = formatConnectivity( connectivity, SMDSAbs_Face );
1199           if ( !con.isEmpty() )
1200             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1201           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1202           if ( !con.isEmpty() )
1203             myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1204         }
1205         else {
1206           myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1207         }
1208         // node position
1209         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1210         if ( !CORBA::is_nil( aMeshPtr ) ) {
1211           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1212           int shapeID = pos->shapeID;
1213           if ( shapeID > 0 ) {
1214             QString shapeType;
1215             double u, v;
1216             switch ( pos->shapeType ) {
1217             case GEOM::EDGE:
1218               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1219               if ( pos->params.length() == 1 )
1220                 u = pos->params[0];
1221               break;
1222             case GEOM::FACE:
1223               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1224               if ( pos->params.length() == 2 ) {
1225                u = pos->params[0];
1226                v = pos->params[1];
1227               }
1228               break;
1229             case GEOM::VERTEX:
1230               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1231               break;
1232             default:
1233               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1234               break;
1235             }
1236             // separator
1237             myInfo->append( "" );
1238             myInfo->append( QString( "<b>%1:" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ) );
1239             myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( shapeType ).arg( shapeID ) );
1240             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1241               myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "U_POSITION" ) ).
1242                               arg( QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1243               if ( pos->shapeType == GEOM::FACE ) {
1244                 myInfo->append( QString( "- <b>%1: #%2</b>" ).arg( SMESHGUI_ElemInfo::tr( "V_POSITION" ) ).
1245                                 arg( QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )) ) );
1246               }
1247             }
1248           }
1249         }
1250         // groups node belongs to
1251         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1252         if ( !CORBA::is_nil( aMesh ) ) {
1253           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1254           myInfo->append( "" ); // separator
1255           bool top_created = false;
1256           for ( int i = 0; i < groups->length(); i++ ) {
1257             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1258             if ( CORBA::is_nil( aGrp ) ) continue;
1259             QString aName = aGrp->GetName();
1260             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1261               if ( !top_created ) {
1262                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1263                 top_created = true;
1264               }
1265               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1266               if ( grp_details ) {
1267                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1268                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1269                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1270                 
1271                 // type : group on geometry, standalone group, group on filter
1272                 if ( !CORBA::is_nil( aStdGroup ) ) {
1273                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1274                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1275                 }
1276                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1277                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1278                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1279                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1280                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1281                   if ( sobj ) {
1282                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1283                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1284                   }
1285                 }
1286                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1287                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1288                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1289                 }
1290                 
1291                 // size
1292                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1293                                 arg( QString::number( aGrp->Size() ) ) );
1294                 
1295                 // color
1296                 SALOMEDS::Color color = aGrp->GetColor();
1297                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1298                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1299               }
1300             }
1301           }
1302         }
1303       }
1304       else {
1305         //
1306         // show element info
1307         // 
1308         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1309         SMESH::Controls::NumericalFunctorPtr afunctor;
1310         if ( !e ) return;
1311         
1312         // Element ID && Type
1313         QString stype;
1314         switch( e->GetType() ) {
1315         case SMDSAbs_0DElement:
1316           stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1317         case SMDSAbs_Ball:
1318           stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1319         case SMDSAbs_Edge:
1320           stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1321         case SMDSAbs_Face:
1322           stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1323         case SMDSAbs_Volume:
1324           stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1325         default: 
1326           break;
1327         }
1328         if ( stype.isEmpty() ) return;
1329         myInfo->append( QString( "<b>%1 #%2</b>" ).arg( stype ).arg( id ) );
1330         // separator
1331         myInfo->append( "" );
1332
1333         // Geometry type
1334         QString gtype;
1335         switch( e->GetEntityType() ) {
1336         case SMDSEntity_Triangle:
1337         case SMDSEntity_Quad_Triangle:
1338         case SMDSEntity_BiQuad_Triangle:
1339           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1340         case SMDSEntity_Quadrangle:
1341         case SMDSEntity_Quad_Quadrangle:
1342         case SMDSEntity_BiQuad_Quadrangle:
1343           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1344         case SMDSEntity_Polygon:
1345         case SMDSEntity_Quad_Polygon:
1346           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1347         case SMDSEntity_Tetra:
1348         case SMDSEntity_Quad_Tetra:
1349           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1350         case SMDSEntity_Pyramid:
1351         case SMDSEntity_Quad_Pyramid:
1352           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1353         case SMDSEntity_Hexa:
1354         case SMDSEntity_Quad_Hexa:
1355         case SMDSEntity_TriQuad_Hexa:
1356           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1357         case SMDSEntity_Penta:
1358         case SMDSEntity_Quad_Penta:
1359           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1360         case SMDSEntity_Hexagonal_Prism:
1361           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1362         case SMDSEntity_Polyhedra:
1363         case SMDSEntity_Quad_Polyhedra:
1364           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1365         default: 
1366           break;
1367         }
1368         if ( !gtype.isEmpty() )
1369           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "TYPE" ) ).arg( gtype ) );
1370
1371         // Quadratic flag (any element except 0D)
1372         if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) {
1373           myInfo->append( QString( "<b>%1?</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) ) );
1374         }
1375         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1376           // Ball diameter
1377           myInfo->append( QString( "<b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() ));
1378         }
1379         // separator
1380         myInfo->append( "" );
1381
1382         // Connectivity
1383         SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1384         for ( int idx = 1; nodeIt->more(); idx++ ) {
1385           const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1386           // node number and ID
1387           myInfo->append( QString( "<b>%1 %2/%3</b> - #%4" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) );
1388           // node coordinates
1389           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "COORDINATES" ) ).
1390                           arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1391                           arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ).
1392                           arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1393           // node connectivity
1394           Connectivity connectivity = nodeConnectivity( node );
1395           if ( !connectivity.isEmpty() ) {
1396             myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) ) );
1397             QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1398             if ( !con.isEmpty() )
1399               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) ).arg( con ) );
1400             con = formatConnectivity( connectivity, SMDSAbs_Edge );
1401             if ( !con.isEmpty() )
1402               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "EDGES" ) ).arg( con ) );
1403             con = formatConnectivity( connectivity, SMDSAbs_Face );
1404             if ( !con.isEmpty() )
1405               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "FACES" ) ).arg( con ) );
1406             con = formatConnectivity( connectivity, SMDSAbs_Volume );
1407             if ( !con.isEmpty() )
1408               myInfo->append( QString( "- <b>%1:</b> %2" ).arg( SMESHGUI_ElemInfo::tr( "VOLUMES" ) ).arg( con ) );
1409           }
1410           else {
1411             myInfo->append( QString( "<b>%1</b>" ).arg( SMESHGUI_ElemInfo::tr( "FREE_NODE" ) ).arg( id ) );
1412           }
1413         }
1414         // separator
1415         myInfo->append( "" );
1416
1417         // Controls
1418         myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_ElemInfo::tr( "CONTROLS" ) ) );
1419         //Length
1420         if ( e->GetType() == SMDSAbs_Edge ) {
1421           afunctor.reset( new SMESH::Controls::Length() );
1422           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1423           afunctor->SetPrecision( cprecision );
1424           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "LENGTH_EDGES" ) ).arg( afunctor->GetValue( id ) ) );  
1425         }
1426         if( e->GetType() == SMDSAbs_Face ) {
1427           //Area
1428           afunctor.reset(  new SMESH::Controls::Area() );
1429           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1430           afunctor->SetPrecision( cprecision );  
1431           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "AREA_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1432           //Taper
1433           afunctor.reset( new SMESH::Controls::Taper() );
1434           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1435           afunctor->SetPrecision( cprecision );
1436           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "TAPER_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1437           //AspectRatio2D
1438           afunctor.reset( new SMESH::Controls::AspectRatio() );
1439           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1440           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1441           //Minimum angle         
1442           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1443           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1444           afunctor->SetPrecision( cprecision );
1445           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MINIMUMANGLE_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1446           //Wraping angle        
1447           afunctor.reset( new SMESH::Controls::Warping() );
1448           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1449           afunctor->SetPrecision( cprecision );
1450           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "WARP_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1451           //Skew         
1452           afunctor.reset( new SMESH::Controls::Skew() );
1453           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1454           afunctor->SetPrecision( cprecision );
1455           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "SKEW_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1456           //ElemDiam2D   
1457           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1458           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1459           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_2D" ) ).arg( afunctor->GetValue( id ) ) );
1460         }
1461         if( e->GetType() == SMDSAbs_Volume ) {
1462           //AspectRatio3D
1463           afunctor.reset(  new SMESH::Controls::AspectRatio3D() );
1464           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1465           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "ASPECTRATIO_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1466           //Volume      
1467           afunctor.reset(  new SMESH::Controls::Volume() );
1468           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1469           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "VOLUME_3D_ELEMENTS" ) ).arg( afunctor->GetValue( id ) ) );
1470           //ElementDiameter3D    
1471           afunctor.reset(  new SMESH::Controls::Volume() );
1472           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1473           myInfo->append( QString( "- <b>%1:</b> %2" ).arg( tr( "MAX_ELEMENT_LENGTH_3D" ) ).arg( afunctor->GetValue( id ) ) );
1474         }
1475         // separator
1476         myInfo->append( "" );
1477
1478         // Gravity center
1479         XYZ gc = gravityCenter( e );
1480         myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1481         
1482         // Normal vector
1483         if( e->GetType() == SMDSAbs_Face ) {
1484           XYZ gc = normal( e );
1485           myInfo->append( QString( "<b>%1:</b> (%2, %3, %4)" ).arg( SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) );
1486         }
1487
1488         // Element position
1489         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1490           SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();    
1491           if ( !CORBA::is_nil( aMesh ) ) {
1492             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
1493             int shapeID = pos.shapeID;
1494             if ( shapeID > 0 ) {
1495               myInfo->append( "" ); // separator
1496               QString shapeType;
1497               switch ( pos.shapeType ) {
1498               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
1499               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
1500               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
1501               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
1502               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
1503               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
1504               }
1505               myInfo->append( QString( "<b>%1:</b> %2 #%3" ).arg( SMESHGUI_ElemInfo::tr( "POSITION" ) ).arg( shapeType ).arg( shapeID ) );
1506             }
1507           }
1508         }
1509
1510         // Groups the element belongs to
1511         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1512         if ( !CORBA::is_nil( aMesh ) ) {
1513           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
1514           myInfo->append( "" ); // separator
1515           bool top_created = false;
1516           for ( int i = 0; i < groups->length(); i++ ) {
1517             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1518             if ( CORBA::is_nil( aGrp ) ) continue;
1519             QString aName = aGrp->GetName();
1520             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1521               if ( !top_created ) {
1522                 myInfo->append( QString( "<b>%1:</b>" ).arg( SMESHGUI_AddInfo::tr( "GROUPS" ) ) );
1523                 top_created = true;
1524               }
1525               myInfo->append( QString( "+ <b>%1:</b>" ).arg( aName.trimmed() ) );
1526               if ( grp_details ) {
1527                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1528                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1529                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1530                 
1531                 // type : group on geometry, standalone group, group on filter
1532                 if ( !CORBA::is_nil( aStdGroup ) ) {
1533                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1534                                   arg( SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ) );
1535                 }
1536                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1537                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1538                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ) );
1539                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1540                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1541                   if ( sobj ) {
1542                     myInfo->append( QString( "  - <b>%1:</b> %2: %3" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1543                                     arg( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) ).arg( sobj->GetName().c_str() ) );
1544                   }
1545                 }
1546                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1547                   myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "TYPE" ) ).
1548                                   arg( SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ) );
1549                 }
1550                 
1551                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "SIZE" ) ).
1552                                 arg( QString::number( aGrp->Size() ) ) );
1553                 
1554                 // color
1555                 SALOMEDS::Color color = aGrp->GetColor();
1556                 myInfo->append( QString( "  - <b>%1:</b> %2" ).arg( SMESHGUI_AddInfo::tr( "COLOR" ) ).
1557                                 arg( QColor( color.R*255., color.G*255., color.B*255. ).name() ) );
1558               }
1559             }
1560           }
1561         }
1562       }
1563       // separator
1564       if ( ids.count() > 1 ) {
1565         myInfo->append( "" );
1566         myInfo->append( "------" );
1567         myInfo->append( "" );
1568       }
1569     }
1570   }
1571 }
1572
1573 /*!
1574   \brief Internal clean-up (reset widget)
1575 */
1576 void SMESHGUI_SimpleElemInfo::clearInternal()
1577 {
1578   myInfo->clear();
1579 }
1580
1581 void SMESHGUI_SimpleElemInfo::saveInfo( QTextStream &out )
1582 {
1583   out << QString( 12, '-' ) << "\n";
1584   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
1585   out << QString( 12, '-' ) << "\n";
1586   out << myInfo->toPlainText();
1587   out << "\n";
1588 }
1589
1590
1591 /*!
1592   \class SMESHGUI_TreeElemInfo::ItemDelegate
1593   \brief Item delegate for tree mesh info widget
1594   \internal
1595 */
1596 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
1597 {
1598 public:
1599   ItemDelegate( QObject* );
1600   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
1601 };
1602
1603 /*!
1604   \brief Constructor
1605   \internal
1606 */
1607 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent )
1608 {
1609 }
1610
1611 /*!
1612   \brief Create item editor widget
1613   \internal
1614 */
1615 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
1616 {
1617   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
1618   if ( qobject_cast<QLineEdit*>( w ) ) qobject_cast<QLineEdit*>( w )->setReadOnly(  true );
1619   return w;
1620 }
1621
1622 /*!
1623   \class SMESHGUI_TreeElemInfo
1624   \brief Represents mesh element information in the tree-like form.
1625 */
1626
1627 /*!
1628   \brief Constructor
1629   \param parent parent widget
1630 */
1631 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
1632 : SMESHGUI_ElemInfo( parent )
1633 {
1634   myInfo = new QTreeWidget( frame() );
1635   myInfo->setColumnCount( 2 );
1636   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
1637   myInfo->header()->setStretchLastSection( true );
1638   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
1639   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
1640   QVBoxLayout* l = new QVBoxLayout( frame() );
1641   l->setMargin( 0 );
1642   l->addWidget( myInfo );
1643   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
1644 }
1645
1646 /*!
1647   \brief Show mesh element information
1648   \param ids mesh nodes / elements identifiers
1649 */
1650 void SMESHGUI_TreeElemInfo::information( const QList<long>& ids )
1651 {
1652   clearInternal();
1653
1654   if ( actor() ) {
1655     int grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1656     int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1657     int cprecision = -1;
1658     if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
1659       cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
1660     foreach ( long id, ids ) {
1661       if ( !isElements() ) {
1662         //
1663         // show node info
1664         //
1665         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id );
1666         if ( !e ) return;
1667         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( e );
1668       
1669         // node ID
1670         QTreeWidgetItem* nodeItem = createItem( 0, Bold | All );
1671         nodeItem->setText( 0, SMESHGUI_ElemInfo::tr( "NODE" ) );
1672         nodeItem->setText( 1, QString( "#%1" ).arg( id ) );
1673         // coordinates
1674         QTreeWidgetItem* coordItem = createItem( nodeItem, Bold );
1675         coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
1676         QTreeWidgetItem* xItem = createItem( coordItem );
1677         xItem->setText( 0, "X" );
1678         xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1679         QTreeWidgetItem* yItem = createItem( coordItem );
1680         yItem->setText( 0, "Y" );
1681         yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1682         QTreeWidgetItem* zItem = createItem( coordItem );
1683         zItem->setText( 0, "Z" );
1684         zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
1685         // connectivity
1686         QTreeWidgetItem* conItem = createItem( nodeItem, Bold );
1687         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1688         Connectivity connectivity = nodeConnectivity( node );
1689         if ( !connectivity.isEmpty() ) {
1690           QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
1691           if ( !con.isEmpty() ) {
1692             QTreeWidgetItem* i = createItem( conItem );
1693             i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
1694             i->setText( 1, con );
1695           }
1696           con = formatConnectivity( connectivity, SMDSAbs_Ball );
1697           if ( !con.isEmpty() ) {
1698             QTreeWidgetItem* i = createItem( conItem );
1699             i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
1700             i->setText( 1, con );
1701             i->setData( 1, TypeRole, NodeConnectivity );
1702           }
1703           con = formatConnectivity( connectivity, SMDSAbs_Edge );
1704           if ( !con.isEmpty() ) {
1705             QTreeWidgetItem* i = createItem( conItem );
1706             i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
1707             i->setText( 1, con );
1708             i->setData( 1, TypeRole, NodeConnectivity );
1709           }
1710           con = formatConnectivity( connectivity, SMDSAbs_Face );
1711           if ( !con.isEmpty() ) {
1712             QTreeWidgetItem* i = createItem( conItem );
1713             i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
1714             i->setText( 1, con );
1715             i->setData( 1, TypeRole, NodeConnectivity );
1716           }
1717           con = formatConnectivity( connectivity, SMDSAbs_Volume );
1718           if ( !con.isEmpty() ) {
1719             QTreeWidgetItem* i = createItem( conItem );
1720             i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
1721             i->setText( 1, con );
1722             i->setData( 1, TypeRole, NodeConnectivity );
1723           }
1724         }
1725         else {
1726           conItem->setText( 1, SMESHGUI_ElemInfo::tr( "FREE_NODE" ) );
1727         }
1728         // node position
1729         SMESH::SMESH_Mesh_ptr aMeshPtr = actor()->GetObject()->GetMeshServer();   
1730         if ( !CORBA::is_nil( aMeshPtr ) ) {
1731           SMESH::NodePosition_var pos = aMeshPtr->GetNodePosition( id );
1732           int shapeID = pos->shapeID;
1733           if ( shapeID > 0 ) {
1734             QString shapeType;
1735             double u, v;
1736             switch ( pos->shapeType ) {
1737             case GEOM::EDGE:
1738               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );
1739               if ( pos->params.length() == 1 )
1740                 u = pos->params[0];
1741               break;
1742             case GEOM::FACE:
1743               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );
1744               if ( pos->params.length() == 2 ) {
1745                 u = pos->params[0];
1746                 v = pos->params[1];
1747               }
1748               break;
1749             case GEOM::VERTEX:
1750               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" );
1751               break;
1752             default:
1753               shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );
1754               break;
1755             }
1756             QTreeWidgetItem* posItem = createItem( nodeItem, Bold );
1757             posItem->setText( 0, SMESHGUI_ElemInfo::tr("POSITION") );
1758             posItem->setText( 1, (shapeType + " #%1").arg( shapeID ));
1759             if ( pos->shapeType == GEOM::EDGE || pos->shapeType == GEOM::FACE ) {
1760               QTreeWidgetItem* uItem = createItem( posItem );
1761               uItem->setText( 0, SMESHGUI_ElemInfo::tr("U_POSITION") );
1762               uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision )));
1763               if ( pos->shapeType == GEOM::FACE ) {
1764                 QTreeWidgetItem* vItem = createItem( posItem );
1765                 vItem->setText( 0, SMESHGUI_ElemInfo::tr("V_POSITION") );
1766                 vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision )));
1767               }
1768             }
1769           }
1770         }
1771         // groups node belongs to
1772         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
1773         if ( !CORBA::is_nil( aMesh ) ) {
1774           SMESH::ListOfGroups_var groups = aMesh->GetGroups();
1775           QTreeWidgetItem* groupsItem = 0;
1776           for ( int i = 0; i < groups->length(); i++ ) {
1777             SMESH::SMESH_GroupBase_var aGrp = groups[i];
1778             if ( CORBA::is_nil( aGrp ) ) continue;
1779             QString aName = aGrp->GetName();
1780             if ( aGrp->GetType() == SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
1781               if ( !groupsItem ) {
1782                 groupsItem = createItem( nodeItem, Bold );
1783                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
1784               }
1785               QTreeWidgetItem* it = createItem( groupsItem, Bold );
1786               it->setText( 0, aName.trimmed() );
1787               if ( grp_details ) {
1788                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
1789                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
1790                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
1791                 
1792                 // type : group on geometry, standalone group, group on filter
1793                 QTreeWidgetItem* typeItem = createItem( it );
1794                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
1795                 if ( !CORBA::is_nil( aStdGroup ) ) {
1796                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1797                 }
1798                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
1799                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1800                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
1801                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
1802                   if ( sobj ) {
1803                     QTreeWidgetItem* gobjItem = createItem( typeItem );
1804                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
1805                     gobjItem->setText( 1, sobj->GetName().c_str() );
1806                   }
1807                 }
1808                 else if ( !CORBA::is_nil( aFltGroup ) ) {
1809                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1810                 }
1811                 
1812                 // size
1813                 QTreeWidgetItem* sizeItem = createItem( it );
1814                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
1815                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
1816                 
1817                 // color
1818                 SALOMEDS::Color color = aGrp->GetColor();
1819                 QTreeWidgetItem* colorItem = createItem( it );
1820                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
1821                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
1822               }
1823             }
1824           }
1825         }
1826       }
1827       else {
1828         //
1829         // show element info
1830         // 
1831         const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id );
1832         SMESH::Controls::NumericalFunctorPtr afunctor;
1833         if ( !e ) return;
1834         
1835         // element ID && type
1836         QString stype;
1837         switch( e->GetType() ) {
1838         case SMDSAbs_0DElement: stype = SMESHGUI_ElemInfo::tr( "0D_ELEMENT" ); break;
1839         case SMDSAbs_Ball:      stype = SMESHGUI_ElemInfo::tr( "BALL" ); break;
1840         case SMDSAbs_Edge:      stype = SMESHGUI_ElemInfo::tr( "EDGE" ); break;
1841         case SMDSAbs_Face:      stype = SMESHGUI_ElemInfo::tr( "FACE" ); break;
1842         case SMDSAbs_Volume:    stype = SMESHGUI_ElemInfo::tr( "VOLUME" ); break;
1843         default:;
1844         }
1845         if ( stype.isEmpty() ) return;
1846         QTreeWidgetItem* elemItem = createItem( 0, Bold | All );
1847         elemItem->setText( 0, stype );
1848         elemItem->setText( 1, QString( "#%1" ).arg( id ) );
1849         // geometry type
1850         QString gtype;
1851         switch( e->GetEntityType() ) {
1852         case SMDSEntity_Triangle:
1853         case SMDSEntity_Quad_Triangle:
1854         case SMDSEntity_BiQuad_Triangle:
1855           gtype = SMESHGUI_ElemInfo::tr( "TRIANGLE" ); break;
1856         case SMDSEntity_Quadrangle:
1857         case SMDSEntity_Quad_Quadrangle:
1858         case SMDSEntity_BiQuad_Quadrangle:
1859           gtype = SMESHGUI_ElemInfo::tr( "QUADRANGLE" ); break;
1860         case SMDSEntity_Polygon:
1861         case SMDSEntity_Quad_Polygon:
1862           gtype = SMESHGUI_ElemInfo::tr( "POLYGON" ); break;
1863         case SMDSEntity_Tetra:
1864         case SMDSEntity_Quad_Tetra:
1865           gtype = SMESHGUI_ElemInfo::tr( "TETRAHEDRON" ); break;
1866         case SMDSEntity_Pyramid:
1867         case SMDSEntity_Quad_Pyramid:
1868           gtype = SMESHGUI_ElemInfo::tr( "PYRAMID" ); break;
1869         case SMDSEntity_Hexa:
1870         case SMDSEntity_Quad_Hexa:
1871         case SMDSEntity_TriQuad_Hexa:
1872           gtype = SMESHGUI_ElemInfo::tr( "HEXAHEDRON" ); break;
1873         case SMDSEntity_Penta:
1874         case SMDSEntity_Quad_Penta:
1875           gtype = SMESHGUI_ElemInfo::tr( "PRISM" ); break;
1876         case SMDSEntity_Hexagonal_Prism:
1877           gtype = SMESHGUI_ElemInfo::tr( "HEX_PRISM" ); break;
1878         case SMDSEntity_Polyhedra:
1879         case SMDSEntity_Quad_Polyhedra:
1880           gtype = SMESHGUI_ElemInfo::tr( "POLYHEDRON" ); break;
1881         default: 
1882           break;
1883         }
1884         if ( !gtype.isEmpty() ) {
1885           QTreeWidgetItem* typeItem = createItem( elemItem, Bold );
1886           typeItem->setText( 0, SMESHGUI_ElemInfo::tr( "TYPE" ) );
1887           typeItem->setText( 1, gtype );
1888         }
1889         // quadratic flag (for edges, faces and volumes)
1890         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
1891           // quadratic flag
1892           QTreeWidgetItem* quadItem = createItem( elemItem, Bold );
1893           quadItem->setText( 0, SMESHGUI_ElemInfo::tr( "QUADRATIC" ) );
1894           quadItem->setText( 1, e->IsQuadratic() ? SMESHGUI_ElemInfo::tr( "YES" ) : SMESHGUI_ElemInfo::tr( "NO" ) );
1895         }
1896         if ( const SMDS_BallElement* ball = dynamic_cast<const SMDS_BallElement*>( e )) {
1897           // ball diameter
1898           QTreeWidgetItem* diamItem = createItem( elemItem, Bold );
1899           diamItem->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_DIAMETER" ) );
1900           diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() ));
1901         }
1902         // connectivity
1903         QTreeWidgetItem* conItem = createItem( elemItem, Bold );
1904         conItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
1905
1906
1907         if( e->GetGeomType() != SMDSGeom_POLYHEDRA ) {
1908           SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
1909           for ( int idx = 1; nodeIt->more(); idx++ ) {
1910             const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
1911             nodeInfo( node, idx, e->NbNodes(), conItem );
1912           }
1913         }
1914         else {
1915           const SMDS_VtkVolume* aVtkVolume = dynamic_cast<const SMDS_VtkVolume*>(e);
1916           SMDS_ElemIteratorPtr nodeIt = aVtkVolume->uniqueNodesIterator();
1917           QList<const SMDS_MeshElement*> uniqueNodes;
1918           while ( nodeIt->more() )
1919             uniqueNodes.append( nodeIt->next() );
1920
1921           SMDS_VolumeTool vtool( e );
1922           const int nbFaces = vtool.NbFaces();
1923           for( int face_id = 0; face_id < nbFaces; face_id++ ) {
1924             QTreeWidgetItem* faceItem = createItem( conItem, Bold );
1925             faceItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "FACE" ) ).arg( face_id + 1 ).arg( nbFaces ) );
1926             faceItem->setExpanded( true );
1927
1928             const SMDS_MeshNode** aNodeIds = vtool.GetFaceNodes( face_id );
1929             const int nbNodes = vtool.NbFaceNodes( face_id );
1930             for( int node_id = 0; node_id < nbNodes; node_id++ ) {
1931               const SMDS_MeshNode* node = aNodeIds[node_id];
1932               nodeInfo( node, uniqueNodes.indexOf(node) + 1, aVtkVolume->NbUniqueNodes(), faceItem );
1933             }
1934           }
1935         }
1936         //Controls
1937         QTreeWidgetItem* cntrItem = createItem( elemItem, Bold );
1938         cntrItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONTROLS" ) );
1939         //Length
1940         if( e->GetType()==SMDSAbs_Edge){         
1941           afunctor.reset( new SMESH::Controls::Length() );
1942           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1943           afunctor->SetPrecision( cprecision );
1944           QTreeWidgetItem* lenItem = createItem( cntrItem, Bold );
1945           lenItem->setText( 0, tr( "LENGTH_EDGES" ) );
1946           lenItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );         
1947         }
1948         if( e->GetType() == SMDSAbs_Face ) {
1949           //Area         
1950           afunctor.reset( new SMESH::Controls::Area() );        
1951           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1952           afunctor->SetPrecision( cprecision );
1953           QTreeWidgetItem* areaItem = createItem( cntrItem, Bold );
1954           areaItem->setText( 0, tr( "AREA_ELEMENTS" ) );
1955           areaItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue(id) ) );         
1956           //Taper
1957           afunctor.reset( new SMESH::Controls::Taper() );
1958           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1959           afunctor->SetPrecision( cprecision );
1960           QTreeWidgetItem* taperlItem = createItem( cntrItem, Bold );
1961           taperlItem->setText( 0, tr( "TAPER_ELEMENTS" ) );
1962           taperlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1963           //AspectRatio2D
1964           afunctor.reset( new SMESH::Controls::AspectRatio() );
1965           afunctor->SetMesh( actor()->GetObject()->GetMesh() );  
1966           QTreeWidgetItem* ratlItem = createItem( cntrItem, Bold );
1967           ratlItem->setText( 0, tr( "ASPECTRATIO_ELEMENTS" ));
1968           ratlItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
1969           //Minimum angle
1970           afunctor.reset( new SMESH::Controls::MinimumAngle() );
1971           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1972           afunctor->SetPrecision( cprecision );
1973           QTreeWidgetItem* minanglItem = createItem( cntrItem, Bold );
1974           minanglItem->setText( 0, tr( "MINIMUMANGLE_ELEMENTS" ) );
1975           minanglItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );    
1976           //Wraping angle       
1977           afunctor.reset( new SMESH::Controls::Warping() );
1978           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1979           afunctor->SetPrecision( cprecision );
1980           QTreeWidgetItem* warpItem = createItem( cntrItem, Bold );
1981           warpItem->setText( 0, tr( "WARP_ELEMENTS" ));
1982           warpItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );        
1983           //Skew          
1984           afunctor.reset( new SMESH::Controls::Skew() );
1985           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1986           afunctor->SetPrecision( cprecision );
1987           QTreeWidgetItem* skewItem = createItem( cntrItem, Bold );
1988           skewItem->setText( 0, tr( "SKEW_ELEMENTS" ) );
1989           skewItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1990           //ElemDiam2D    
1991           afunctor.reset( new SMESH::Controls::MaxElementLength2D() );
1992           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
1993           QTreeWidgetItem* diamItem = createItem( cntrItem, Bold );
1994           diamItem->setText( 0, tr( "MAX_ELEMENT_LENGTH_2D" ));
1995           diamItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );       
1996         }
1997         if( e->GetType() == SMDSAbs_Volume ) {
1998           //AspectRatio3D
1999           afunctor.reset( new SMESH::Controls::AspectRatio3D() );
2000           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2001           QTreeWidgetItem* ratlItem3 = createItem( cntrItem, Bold );
2002           ratlItem3->setText( 0, tr( "ASPECTRATIO_3D_ELEMENTS" ) );
2003           ratlItem3->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );      
2004           //Volume
2005           afunctor.reset( new SMESH::Controls::Volume() );
2006           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2007           QTreeWidgetItem* volItem = createItem( cntrItem, Bold );
2008           volItem->setText( 0, tr( "VOLUME_3D_ELEMENTS" ) );
2009           volItem->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );
2010           //ElementDiameter3D
2011           afunctor.reset( new SMESH::Controls::MaxElementLength3D() );
2012           afunctor->SetMesh( actor()->GetObject()->GetMesh() );
2013           QTreeWidgetItem* diam3Item = createItem( cntrItem, Bold );
2014           diam3Item->setText( 0, tr( "MAX_ELEMENT_LENGTH_3D" ) );
2015           diam3Item->setText( 1, QString( "%1" ).arg( afunctor->GetValue( id ) ) );     
2016         }
2017
2018         // gravity center
2019         XYZ gc = gravityCenter( e );
2020         QTreeWidgetItem* gcItem = createItem( elemItem, Bold );
2021         gcItem->setText( 0, SMESHGUI_ElemInfo::tr( "GRAVITY_CENTER" ) );
2022         QTreeWidgetItem* xItem = createItem( gcItem );
2023         xItem->setText( 0, "X" );
2024         xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2025         QTreeWidgetItem* yItem = createItem( gcItem );
2026         yItem->setText( 0, "Y" );
2027         yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2028         QTreeWidgetItem* zItem = createItem( gcItem );
2029         zItem->setText( 0, "Z" );
2030         zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2031
2032         // normal vector
2033         if( e->GetType() == SMDSAbs_Face ) {
2034           XYZ gc = normal( e );
2035           QTreeWidgetItem* nItem = createItem( elemItem, Bold );
2036           nItem->setText( 0, SMESHGUI_ElemInfo::tr( "NORMAL_VECTOR" ) );
2037           QTreeWidgetItem* xItem = createItem( nItem );
2038           xItem->setText( 0, "X" );
2039           xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2040           QTreeWidgetItem* yItem = createItem( nItem );
2041           yItem->setText( 0, "Y" );
2042           yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2043           QTreeWidgetItem* zItem = createItem( nItem );
2044           zItem->setText( 0, "Z" );
2045           zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2046         }
2047
2048         // element position
2049         SMESH::SMESH_Mesh_ptr aMesh = actor()->GetObject()->GetMeshServer();
2050         if ( e->GetType() >= SMDSAbs_Edge && e->GetType() <= SMDSAbs_Volume ) {
2051           if ( !CORBA::is_nil( aMesh ) ) {
2052             SMESH::ElementPosition pos = aMesh->GetElementPosition( id );
2053             int shapeID = pos.shapeID;
2054             if ( shapeID > 0 ) {
2055               QTreeWidgetItem* shItem = createItem( elemItem, Bold );
2056               QString shapeType;
2057               switch ( pos.shapeType ) {
2058               case GEOM::EDGE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_EDGE" );   break;
2059               case GEOM::FACE:   shapeType = SMESHGUI_ElemInfo::tr( "GEOM_FACE" );   break;
2060               case GEOM::VERTEX: shapeType = SMESHGUI_ElemInfo::tr( "GEOM_VERTEX" ); break;
2061               case GEOM::SOLID:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SOLID" );  break;
2062               case GEOM::SHELL:  shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHELL" );  break;
2063               default:           shapeType = SMESHGUI_ElemInfo::tr( "GEOM_SHAPE" );  break;
2064               }
2065               shItem->setText( 0, SMESHGUI_ElemInfo::tr( "POSITION" ) );
2066               shItem->setText( 1, QString( "%1 #%2" ).arg( shapeType ).arg( shapeID ) );
2067             }
2068           }
2069         }
2070         // groups element belongs to
2071         if ( !CORBA::is_nil( aMesh ) ) {
2072           SMESH::ListOfGroups_var  groups = aMesh->GetGroups();
2073           QTreeWidgetItem* groupsItem = 0;
2074           for ( int i = 0; i < groups->length(); i++ ) {
2075             SMESH::SMESH_GroupBase_var aGrp = groups[i];
2076             if ( CORBA::is_nil( aGrp ) ) continue;
2077             QString aName = aGrp->GetName();
2078             if ( aGrp->GetType() != SMESH::NODE && !aName.isEmpty() && aGrp->Contains( id ) ) {
2079               if ( !groupsItem ) {
2080                 groupsItem = createItem( elemItem, Bold );
2081                 groupsItem->setText( 0, SMESHGUI_AddInfo::tr( "GROUPS" ) );
2082               }
2083               QTreeWidgetItem* it = createItem( groupsItem, Bold );
2084               it->setText( 0, aName.trimmed() );
2085               if ( grp_details ) {
2086                 SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( aGrp );
2087                 SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( aGrp );
2088                 SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( aGrp );
2089                 
2090                 // type : group on geometry, standalone group, group on filter
2091                 QTreeWidgetItem* typeItem = createItem( it );
2092                 typeItem->setText( 0, SMESHGUI_AddInfo::tr( "TYPE" ) );
2093                 if ( !CORBA::is_nil( aStdGroup ) ) {
2094                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
2095                 }
2096                 else if ( !CORBA::is_nil( aGeomGroup ) ) {
2097                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
2098                   GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2099                   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2100                   if ( sobj ) {
2101                     QTreeWidgetItem* gobjItem = createItem( typeItem );
2102                     gobjItem->setText( 0, SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ) );
2103                     gobjItem->setText( 1, sobj->GetName().c_str() );
2104                   }
2105                 }
2106                 else if ( !CORBA::is_nil( aFltGroup ) ) {
2107                   typeItem->setText( 1, SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
2108                 }
2109                 
2110                 // size
2111                 QTreeWidgetItem* sizeItem = createItem( it );
2112                 sizeItem->setText( 0, SMESHGUI_AddInfo::tr( "SIZE" ) );
2113                 sizeItem->setText( 1, QString::number( aGrp->Size() ) );
2114                 
2115                 // color
2116                 SALOMEDS::Color color = aGrp->GetColor();
2117                 QTreeWidgetItem* colorItem = createItem( it );
2118                 colorItem->setText( 0, SMESHGUI_AddInfo::tr( "COLOR" ) );
2119                 colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2120               }
2121             }
2122           }
2123         }
2124       }
2125     }
2126   }
2127 }
2128
2129 /*!
2130   \brief Show node information
2131   \param node mesh node for showing
2132   \param index index of current node
2133   \param nbNodes number of unique nodes in element
2134   \param parentItem parent item of tree
2135 */
2136 void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* node, int index,
2137                                       int nbNodes, QTreeWidgetItem* parentItem )
2138 {
2139   int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
2140   // node number and ID
2141   QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
2142   nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" ) ).arg( index ).arg( nbNodes ) );
2143   nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) );
2144   nodeItem->setData( 1, TypeRole, ElemConnectivity );
2145   nodeItem->setData( 1, IdRole, node->GetID() );
2146   nodeItem->setExpanded( false );
2147   // node coordinates
2148   QTreeWidgetItem* coordItem = createItem( nodeItem );
2149   coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ) );
2150   QTreeWidgetItem* xItem = createItem( coordItem );
2151   xItem->setText( 0, "X" );
2152   xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2153   QTreeWidgetItem* yItem = createItem( coordItem );
2154   yItem->setText( 0, "Y" );
2155   yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2156   QTreeWidgetItem* zItem = createItem( coordItem );
2157   zItem->setText( 0, "Z" );
2158   zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) );
2159   // node connectivity
2160   QTreeWidgetItem* nconItem = createItem( nodeItem );
2161   nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ) );
2162   Connectivity connectivity = nodeConnectivity( node );
2163   if ( !connectivity.isEmpty() ) {
2164     QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
2165     if ( !con.isEmpty() ) {
2166       QTreeWidgetItem* i = createItem( nconItem );
2167       i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ) );
2168       i->setText( 1, con );
2169     }
2170     con = formatConnectivity( connectivity, SMDSAbs_Edge );
2171     if ( !con.isEmpty() ) {
2172       QTreeWidgetItem* i = createItem( nconItem );
2173       i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ) );
2174       i->setText( 1, con );
2175       i->setData( 1, TypeRole, NodeConnectivity );
2176     }
2177     con = formatConnectivity( connectivity, SMDSAbs_Ball );
2178     if ( !con.isEmpty() ) {
2179       QTreeWidgetItem* i = createItem( nconItem );
2180       i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ) );
2181       i->setText( 1, con );
2182       i->setData( 1, TypeRole, NodeConnectivity );
2183     }
2184     con = formatConnectivity( connectivity, SMDSAbs_Face );
2185     if ( !con.isEmpty() ) {
2186       QTreeWidgetItem* i = createItem( nconItem );
2187       i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ) );
2188       i->setText( 1, con );
2189       i->setData( 1, TypeRole, NodeConnectivity );
2190     }
2191     con = formatConnectivity( connectivity, SMDSAbs_Volume );
2192     if ( !con.isEmpty() ) {
2193       QTreeWidgetItem* i = createItem( nconItem );
2194       i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ) );
2195       i->setText( 1, con );
2196       i->setData( 1, TypeRole, NodeConnectivity );
2197     }
2198   }
2199 }
2200 /*!
2201   \brief Internal clean-up (reset widget)
2202 */
2203 void SMESHGUI_TreeElemInfo::clearInternal()
2204 {
2205   myInfo->clear();
2206   myInfo->repaint();
2207 }
2208
2209 /*!
2210   \brief Create new tree item.
2211   \param parent parent tree widget item
2212   \param flags item flag
2213   \return new tree widget item
2214 */
2215 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags )
2216 {
2217   QTreeWidgetItem* item;
2218   if ( parent )
2219     item = new QTreeWidgetItem( parent );
2220   else
2221     item = new QTreeWidgetItem( myInfo );
2222
2223   item->setFlags( item->flags() | Qt::ItemIsEditable );
2224
2225   QFont f = item->font( 0 );
2226   f.setBold( true );
2227   for ( int i = 0; i < myInfo->columnCount(); i++ ) {
2228     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2229       item->setFont( i, f );
2230   }
2231
2232   item->setExpanded( true );
2233   return item;
2234 }
2235
2236 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2237 {
2238   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2239   if ( widgets.isEmpty() ) return;
2240   QTreeWidgetItem* aTreeItem = widgets.first();
2241   int type = aTreeItem->data( 1, TypeRole ).toInt();
2242   int id   = aTreeItem->data( 1, IdRole ).toInt();
2243   QMenu menu;
2244   QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ) );
2245   if ( type == ElemConnectivity && id > 0 && menu.exec( e->globalPos() ) == a )
2246     emit( itemInfo( id ) );
2247   else if ( type == NodeConnectivity && menu.exec( e->globalPos() ) == a )
2248     emit( itemInfo( aTreeItem->text( 1 ) ) );
2249 }
2250
2251 void  SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
2252 {
2253   if ( theItem ) {
2254     int type = theItem->data( 1, TypeRole ).toInt();
2255     int id   = theItem->data( 1, IdRole ).toInt();
2256     if ( type == ElemConnectivity && id > 0 )
2257       emit( itemInfo( id ) );
2258     else if ( type == NodeConnectivity )
2259       emit( itemInfo( theItem->text( 1 ) ) );
2260   }
2261 }
2262
2263 void SMESHGUI_TreeElemInfo::saveInfo( QTextStream &out )
2264 {
2265   out << QString( 12, '-' ) << "\n";
2266   out << SMESHGUI_ElemInfo::tr( "ELEM_INFO" ) << "\n";
2267   out << QString( 12, '-' ) << "\n";
2268
2269   QTreeWidgetItemIterator it( myInfo );
2270   while ( *it ) {
2271     if ( !( *it )->text(0).isEmpty() ) {
2272       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2273       if ( !( *it )->text(1).isEmpty() ) out << ": " << ( *it )->text(1);
2274       out << "\n";
2275     }
2276     ++it;
2277   }
2278   out << "\n";
2279 }
2280
2281 /*!
2282   \class GrpComputor
2283   \brief Mesh information computer
2284   \internal
2285   
2286   The class is created for different computation operation. Currently it is used
2287   to compute number of underlying nodes for the groups.
2288 */
2289
2290 /*!
2291   \brief Contructor
2292 */
2293 GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent )
2294   : QObject( parent ), myItem( item )
2295 {
2296   myGroup = SMESH::SMESH_GroupBase::_narrow( grp );
2297 }
2298
2299 /*!
2300   \brief Compute function
2301 */
2302 void GrpComputor::compute()
2303 {
2304   if ( !CORBA::is_nil( myGroup ) && myItem ) {
2305     QTreeWidgetItem* item = myItem;
2306     myItem = 0;
2307     int nbNodes = myGroup->GetNumberOfNodes();
2308     item->treeWidget()->removeItemWidget( item, 1 );
2309     item->setText( 1, QString::number( nbNodes ));
2310   }
2311 }
2312
2313 /*!
2314   \class SMESHGUI_AddInfo
2315   \brief The wigdet shows additional information on the mesh object.
2316 */
2317
2318 /*!
2319   \brief Constructor
2320   \param parent parent widget
2321 */
2322 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent )
2323 : QTreeWidget( parent )
2324 {
2325   setColumnCount( 2 );
2326   header()->setStretchLastSection( true );
2327   header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2328   header()->hide();
2329 }
2330
2331 /*!
2332   \brief Destructor
2333 */
2334 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2335 {
2336 }
2337
2338 /*!
2339   \brief Show additional information on the selected object
2340   \param obj object being processed (mesh, sub-mesh, group, ID source)
2341 */
2342 void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
2343 {
2344   setProperty( "group_index", 0 );
2345   setProperty( "submesh_index",  0 );
2346   myComputors.clear();
2347   clear();
2348
2349   if ( CORBA::is_nil( obj ) ) return;
2350
2351   _PTR(SObject) sobj = SMESH::ObjectToSObject( obj );
2352   if ( !sobj ) return;
2353
2354   // name
2355   QTreeWidgetItem* nameItem = createItem( 0, Bold | All );
2356   nameItem->setText( 0, tr( "NAME" ) );
2357   nameItem->setText( 1, sobj->GetName().c_str() );
2358   
2359   SMESH::SMESH_Mesh_var      aMesh    = SMESH::SMESH_Mesh::_narrow( obj );
2360   SMESH::SMESH_subMesh_var   aSubMesh = SMESH::SMESH_subMesh::_narrow( obj );
2361   SMESH::SMESH_GroupBase_var aGroup   = SMESH::SMESH_GroupBase::_narrow( obj );
2362   
2363   if ( !aMesh->_is_nil() )
2364     meshInfo( aMesh, nameItem );
2365   else if ( !aSubMesh->_is_nil() )
2366     subMeshInfo( aSubMesh, nameItem );
2367   else if ( !aGroup->_is_nil() )
2368     groupInfo( aGroup.in(), nameItem );
2369 }
2370
2371 /*!
2372   \brief Create new tree item.
2373   \param parent parent tree widget item
2374   \param flags item flag
2375   \return new tree widget item
2376 */
2377 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags )
2378 {
2379   QTreeWidgetItem* item;
2380
2381   if ( parent )
2382     item = new QTreeWidgetItem( parent );
2383   else
2384     item = new QTreeWidgetItem( this );
2385
2386   //item->setFlags( item->flags() | Qt::ItemIsEditable );
2387
2388   QFont f = item->font( 0 );
2389   f.setBold( true );
2390   for ( int i = 0; i < columnCount(); i++ ) {
2391     if ( ( flags & Bold ) && ( i == 0 || flags & All ) )
2392       item->setFont( i, f );
2393   }
2394
2395   item->setExpanded( true );
2396   return item;
2397 }
2398
2399 /*!
2400   \brief Show mesh info
2401   \param mesh mesh object
2402   \param parent parent tree item
2403 */
2404 void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent )
2405 {
2406   // type
2407   GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh();
2408   SMESH::MedFileInfo_var inf = mesh->GetMEDFileInfo();
2409   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2410   typeItem->setText( 0, tr( "TYPE" ) );
2411   if ( !CORBA::is_nil( shape ) ) {
2412     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2413     _PTR(SObject) sobj = SMESH::ObjectToSObject( shape );
2414     if ( sobj ) {
2415       QTreeWidgetItem* gobjItem = createItem( typeItem );
2416       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2417       gobjItem->setText( 1, sobj->GetName().c_str() );
2418     }
2419   }
2420   else if ( strlen( (char*)inf->fileName ) > 0 ) {
2421     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2422     QTreeWidgetItem* fileItem = createItem( typeItem );
2423     fileItem->setText( 0, tr( "FILE_NAME" ) );
2424     fileItem->setText( 1, (char*)inf->fileName );
2425   }
2426   else {
2427     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2428   }
2429   
2430   // groups
2431   myGroups = mesh->GetGroups();
2432   showGroups();
2433
2434   // sub-meshes
2435   mySubMeshes = mesh->GetSubMeshes();
2436   showSubMeshes();
2437 }
2438
2439 /*!
2440   \brief Show sub-mesh info
2441   \param subMesh sub-mesh object
2442   \param parent parent tree item
2443 */
2444 void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent )
2445 {
2446   bool isShort = parent->parent() != 0;
2447
2448   if ( !isShort ) {
2449     // parent mesh
2450     _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() );
2451     if ( sobj ) {
2452       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2453       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2454       nameItem->setText( 1, sobj->GetName().c_str() );
2455     }
2456   }
2457   
2458   // shape
2459   GEOM::GEOM_Object_var gobj = subMesh->GetSubShape();
2460   _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2461   if ( sobj ) {
2462     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2463     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2464     gobjItem->setText( 1, sobj->GetName().c_str() );
2465   }
2466 }
2467
2468 /*!
2469   \brief Show group info
2470   \param grp mesh group object
2471   \param parent parent tree item
2472 */
2473 void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent )
2474 {
2475   bool isShort = parent->parent() != 0;
2476
2477   SMESH::SMESH_Group_var         aStdGroup  = SMESH::SMESH_Group::_narrow( grp );
2478   SMESH::SMESH_GroupOnGeom_var   aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp );
2479   SMESH::SMESH_GroupOnFilter_var aFltGroup  = SMESH::SMESH_GroupOnFilter::_narrow( grp );
2480
2481   if ( !isShort ) {
2482     // parent mesh
2483     _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() );
2484     if ( sobj ) {
2485       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2486       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2487       nameItem->setText( 1, sobj->GetName().c_str() );
2488     }
2489   }
2490
2491   // type : group on geometry, standalone group, group on filter
2492   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2493   typeItem->setText( 0, tr( "TYPE" ) );
2494   if ( !CORBA::is_nil( aStdGroup ) ) {
2495     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2496   }
2497   else if ( !CORBA::is_nil( aGeomGroup ) ) {
2498     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2499     GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape();
2500     _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj );
2501     if ( sobj ) {
2502       QTreeWidgetItem* gobjItem = createItem( typeItem );
2503       gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2504       gobjItem->setText( 1, sobj->GetName().c_str() );
2505     }
2506   }
2507   else if ( !CORBA::is_nil( aFltGroup ) ) {
2508     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2509   }
2510
2511   if ( !isShort ) {
2512     // entity type
2513     QString etype = tr( "UNKNOWN" );
2514     switch( grp->GetType() ) {
2515     case SMESH::NODE:
2516       etype = tr( "NODE" );
2517       break;
2518     case SMESH::EDGE:
2519       etype = tr( "EDGE" );
2520       break;
2521     case SMESH::FACE:
2522       etype = tr( "FACE" );
2523       break;
2524     case SMESH::VOLUME:
2525       etype = tr( "VOLUME" );
2526       break;
2527     case SMESH::ELEM0D:
2528       etype = tr( "0DELEM" );
2529       break;
2530     case SMESH::BALL:
2531       etype = tr( "BALL" );
2532       break;
2533     default:
2534       break;
2535     }
2536     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2537     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2538     etypeItem->setText( 1, etype );
2539   }
2540
2541   // size
2542   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2543   sizeItem->setText( 0, tr( "SIZE" ) );
2544   sizeItem->setText( 1, QString::number( grp->Size() ) );
2545
2546   // color
2547   SALOMEDS::Color color = grp->GetColor();
2548   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2549   colorItem->setText( 0, tr( "COLOR" ) );
2550   colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) );
2551
2552   // nb of underlying nodes
2553   if ( grp->GetType() != SMESH::NODE) {
2554     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2555     nodesItem->setText( 0, tr( "NB_NODES" ) );
2556     int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 );
2557     SMESH::SMESH_Mesh_var mesh = grp->GetMesh();
2558     bool meshLoaded = mesh->IsLoaded();
2559     bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit );
2560     if ( toShowNodes && meshLoaded ) {
2561       // already calculated and up-to-date
2562       nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) );
2563     }
2564     else {
2565       QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this );
2566       setItemWidget( nodesItem, 1, btn );
2567       GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); 
2568       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2569       myComputors.append( comp );
2570       if ( !meshLoaded )
2571         connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) );
2572     }
2573   }
2574 }
2575
2576 void SMESHGUI_AddInfo::showGroups()
2577 {
2578   myComputors.clear();
2579
2580   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2581   if ( !parent ) return;
2582
2583   int idx = property( "group_index" ).toInt();
2584
2585   QTreeWidgetItem* itemGroups = 0;
2586   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) {
2587     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) {
2588       itemGroups = parent->child( i );
2589       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemGroups, 1 ) );
2590       if ( extra )
2591         extra->updateControls( myGroups->length(), idx );
2592       while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items
2593     }
2594   }
2595
2596   QMap<int, QTreeWidgetItem*> grpItems;
2597   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) {
2598     SMESH::SMESH_GroupBase_var grp = myGroups[i];
2599     if ( CORBA::is_nil( grp ) ) continue;
2600     _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp );
2601     if ( !grpSObj ) continue;
2602
2603     int grpType = grp->GetType();
2604
2605     if ( !itemGroups ) {
2606       // create top-level groups container item
2607       itemGroups = createItem( parent, Bold | All );
2608       itemGroups->setText( 0, tr( "GROUPS" ) );
2609       itemGroups->setData( 0, Qt::UserRole, GROUPS_ID );
2610
2611       // total number of groups > 10, show extra widgets for info browsing
2612       if ( myGroups->length() > MAXITEMS ) {
2613         ExtraWidget* extra = new ExtraWidget( this, true );
2614         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2615         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2616         setItemWidget( itemGroups, 1, extra );
2617         extra->updateControls( myGroups->length(), idx );
2618       }
2619     }
2620
2621     if ( grpItems.find( grpType ) == grpItems.end() ) {
2622       grpItems[ grpType ] = createItem( itemGroups, Bold | All );
2623       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2624       itemGroups->insertChild( grpType-1, grpItems[ grpType ] );
2625     }
2626   
2627     // group name
2628     QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] );
2629     grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2630
2631     // group info
2632     groupInfo( grp.in(), grpNameItem );
2633   }
2634 }
2635
2636 void SMESHGUI_AddInfo::showSubMeshes()
2637 {
2638   QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item
2639   if ( !parent ) return;
2640
2641   int idx = property( "submesh_index" ).toInt();
2642
2643   QTreeWidgetItem* itemSubMeshes = 0;
2644   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) {
2645     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) {
2646       itemSubMeshes = parent->child( i );
2647       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( itemWidget( itemSubMeshes, 1 ) );
2648       if ( extra )
2649         extra->updateControls( mySubMeshes->length(), idx );
2650       while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items
2651     }
2652   }
2653
2654   QMap<int, QTreeWidgetItem*> smItems;
2655   for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) {
2656     SMESH::SMESH_subMesh_var sm = mySubMeshes[i];
2657     if ( CORBA::is_nil( sm ) ) continue;
2658     _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm );
2659     if ( !smSObj ) continue;
2660     
2661     GEOM::GEOM_Object_var gobj = sm->GetSubShape();
2662     if ( CORBA::is_nil(gobj ) ) continue;
2663     
2664     int smType = gobj->GetShapeType();
2665     if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND;
2666
2667     if ( !itemSubMeshes ) {
2668       itemSubMeshes = createItem( parent, Bold | All );
2669       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2670       itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID );
2671
2672       // total number of sub-meshes > 10, show extra widgets for info browsing
2673       if ( mySubMeshes->length() > MAXITEMS ) {
2674         ExtraWidget* extra = new ExtraWidget( this, true );
2675         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2676         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2677         setItemWidget( itemSubMeshes, 1, extra );
2678         extra->updateControls( mySubMeshes->length(), idx );
2679       }
2680     }
2681          
2682     if ( smItems.find( smType ) == smItems.end() ) {
2683       smItems[ smType ] = createItem( itemSubMeshes, Bold | All );
2684       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2685       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2686     }
2687     
2688     // submesh name
2689     QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] );
2690     smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed
2691     
2692     // submesh info
2693     subMeshInfo( sm.in(), smNameItem );
2694   }
2695 }
2696
2697 /*!
2698  * \brief Change button label of "nb underlying node" group from "Load" to "Compute"
2699  */
2700 void SMESHGUI_AddInfo::changeLoadToCompute()
2701 {
2702   for ( int i = 0; i < myComputors.count(); ++i )
2703   {
2704     if ( QTreeWidgetItem* item = myComputors[i]->getItem() )
2705     {
2706       if ( QPushButton* btn = qobject_cast<QPushButton*>( itemWidget ( item, 1 ) ) )
2707         btn->setText( tr("COMPUTE") );
2708     }
2709   }
2710 }
2711
2712 void SMESHGUI_AddInfo::showPreviousGroups()
2713 {
2714   int idx = property( "group_index" ).toInt();
2715   setProperty( "group_index", idx-1 );
2716   showGroups();
2717 }
2718
2719 void SMESHGUI_AddInfo::showNextGroups()
2720 {
2721   int idx = property( "group_index" ).toInt();
2722   setProperty( "group_index", idx+1 );
2723   showGroups();
2724 }
2725
2726 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2727 {
2728   int idx = property( "submesh_index" ).toInt();
2729   setProperty( "submesh_index", idx-1 );
2730   showSubMeshes();
2731 }
2732
2733 void SMESHGUI_AddInfo::showNextSubMeshes()
2734 {
2735   int idx = property( "submesh_index" ).toInt();
2736   setProperty( "submesh_index", idx+1 );
2737   showSubMeshes();
2738 }
2739
2740 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2741 {
2742   out << QString( 15, '-')       << "\n";
2743   out << tr( "ADDITIONAL_INFO" ) << "\n";
2744   out << QString( 15, '-' )      << "\n";
2745   QTreeWidgetItemIterator it( this );
2746   while ( *it ) {
2747     if ( !( ( *it )->text(0) ).isEmpty() ) {
2748       out << QString( SPACING_INFO * itemDepth( *it ), ' ' ) << ( *it )->text(0);
2749       if ( ( *it )->text(0)  == tr( "COLOR" ) ) {
2750         out << ": " << ( ( ( *it )->background(1) ).color() ).name();
2751       }
2752       else if ( !( ( *it )->text(1) ).isEmpty() ) out << ": " << ( *it )->text(1);
2753       out << "\n";
2754     }
2755     ++it;
2756   }
2757   out << "\n";
2758 }
2759
2760 /*!
2761   \class SMESHGUI_MeshInfoDlg
2762   \brief Mesh information dialog box
2763 */
2764
2765 /*!
2766   \brief Constructor
2767   \param parent parent widget
2768   \param page specifies the dialog page to be shown at the start-up
2769 */
2770 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
2771 : QDialog( parent ), myActor( 0 )
2772 {
2773   setModal( false );
2774   setAttribute( Qt::WA_DeleteOnClose, true );
2775   setWindowTitle( tr( "MESH_INFO" ) );
2776   setSizeGripEnabled( true );
2777
2778   myTabWidget = new QTabWidget( this );
2779
2780   // base info 
2781
2782   myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget );
2783   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
2784
2785   // elem info 
2786   
2787   QWidget* w = new QWidget( myTabWidget );
2788
2789   myMode = new QButtonGroup( this );
2790   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
2791   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
2792   myMode->button( NodeMode )->setChecked( true );
2793   myID = new QLineEdit( w );
2794   myID->setValidator( new SMESHGUI_IdValidator( this ) );
2795
2796   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
2797   mode = qMin( 1, qMax( 0, mode ) );
2798   
2799   if ( mode == 0 ) 
2800     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
2801   else
2802     myElemInfo = new SMESHGUI_TreeElemInfo( w );
2803
2804   QGridLayout* elemLayout = new QGridLayout( w );
2805   elemLayout->setMargin( MARGIN );
2806   elemLayout->setSpacing( SPACING );
2807   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
2808   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
2809   elemLayout->addWidget( myID, 0, 2 );
2810   elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 );
2811   
2812   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
2813
2814   // additional info
2815
2816   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
2817   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
2818
2819   // controls info
2820
2821   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
2822   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
2823
2824   // buttons
2825
2826   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
2827   okBtn->setAutoDefault( true );
2828   okBtn->setDefault( true );
2829   okBtn->setFocus();
2830   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
2831   dumpBtn->setAutoDefault( true );
2832   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
2833   helpBtn->setAutoDefault( true );
2834
2835   QHBoxLayout* btnLayout = new QHBoxLayout;
2836   btnLayout->setSpacing( SPACING );
2837   btnLayout->setMargin( 0 );
2838
2839   btnLayout->addWidget( okBtn );
2840   btnLayout->addWidget( dumpBtn );
2841   btnLayout->addStretch( 10 );
2842   btnLayout->addWidget( helpBtn );
2843
2844   QVBoxLayout* l = new QVBoxLayout ( this );
2845   l->setMargin( MARGIN );
2846   l->setSpacing( SPACING );
2847   l->addWidget( myTabWidget );
2848   l->addLayout( btnLayout );
2849
2850   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
2851
2852   connect( okBtn,       SIGNAL( clicked() ),              this, SLOT( reject() ) );
2853   connect( dumpBtn,     SIGNAL( clicked() ),              this, SLOT( dump() ) );
2854   connect( helpBtn,     SIGNAL( clicked() ),              this, SLOT( help() ) );
2855   connect( myTabWidget, SIGNAL( currentChanged( int  ) ), this, SLOT( updateSelection() ) );
2856   connect( myMode,      SIGNAL( buttonClicked( int  ) ),  this, SLOT( modeChanged() ) );
2857   connect( myID,        SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
2858   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
2859   connect( SMESHGUI::GetSMESHGUI(),  SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
2860   connect( myElemInfo,  SIGNAL( itemInfo( int ) ),     this, SLOT( showItemInfo( int ) ) );
2861   connect( myElemInfo,  SIGNAL( itemInfo( QString ) ), this, SLOT( showItemInfo( QString ) ) );
2862
2863   updateSelection();
2864 }
2865
2866 /*!
2867   \brief Destructor
2868 */
2869 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
2870 {
2871 }
2872
2873 /*!
2874   \brief Show mesh information
2875   \param IO interactive object
2876 */
2877 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
2878 {
2879   SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO );
2880   if ( !CORBA::is_nil( obj ) ) {
2881     myBaseInfo->showInfo( obj );
2882     myAddInfo->showInfo( obj );
2883     myCtrlInfo->showInfo( obj );
2884
2885     myActor = SMESH::FindActorByEntry( IO->getEntry() );
2886     SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
2887     QString ID;
2888     int nb = 0;
2889     if ( myActor && selector ) {
2890       nb = myMode->checkedId() == NodeMode ? 
2891         SMESH::GetNameOfSelectedElements( selector, IO, ID ) :
2892         SMESH::GetNameOfSelectedNodes( selector, IO, ID );
2893     }
2894     myElemInfo->setSource( myActor ) ;
2895     if ( nb > 0 ) {
2896       myID->setText( ID.trimmed() );
2897       QSet<long> ids;
2898       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
2899       foreach ( ID, idTxt )
2900         ids << ID.trimmed().toLong();
2901       myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
2902     }
2903     else {
2904       myID->clear();
2905       myElemInfo->clear();
2906     }
2907   }
2908 }
2909
2910 /*!
2911   \brief Perform clean-up actions on the dialog box closing.
2912 */
2913 void SMESHGUI_MeshInfoDlg::reject()
2914 {
2915   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2916   selMgr->clearFilters();
2917   SMESH::SetPointRepresentation( false );
2918   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2919     aViewWindow->SetSelectionMode( ActorSelection );
2920   QDialog::reject();
2921 }
2922
2923 /*!
2924   \brief Process keyboard event
2925   \param e key press event
2926 */
2927 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
2928 {
2929   QDialog::keyPressEvent( e );
2930   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
2931     e->accept();
2932     help();
2933   }
2934 }
2935
2936 /*!
2937   \brief Reactivate dialog box, when mouse pointer goes into it.
2938 */
2939 void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* )
2940 {
2941   //activate();
2942 }
2943
2944 /*!
2945   \brief Setup selection mode depending on the current dialog box state.
2946 */
2947 void SMESHGUI_MeshInfoDlg::updateSelection()
2948 {
2949   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
2950
2951   disconnect( selMgr, 0, this, 0 );
2952   selMgr->clearFilters();
2953
2954   if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo || myTabWidget->currentIndex() == CtrlInfo ) {
2955     SMESH::SetPointRepresentation( false );
2956     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2957       aViewWindow->SetSelectionMode( ActorSelection );
2958   }
2959   else {
2960     if ( myMode->checkedId() == NodeMode ) {
2961       SMESH::SetPointRepresentation( true );
2962       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2963         aViewWindow->SetSelectionMode( NodeSelection );
2964     }
2965     else {
2966       SMESH::SetPointRepresentation( false );
2967       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
2968         aViewWindow->SetSelectionMode( CellSelection );
2969     }
2970   }
2971
2972   QString oldID = myID->text().trimmed();
2973   SMESH_Actor* oldActor = myActor;
2974   myID->clear();
2975   
2976   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
2977   updateInfo();
2978   
2979   if ( oldActor == myActor && myActor && !oldID.isEmpty() ) {
2980     myID->setText( oldID );
2981     idChanged();
2982   }
2983 }
2984
2985 /*!
2986   \brief Show help page
2987 */
2988 void SMESHGUI_MeshInfoDlg::help()
2989 {
2990   SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ?
2991                        "mesh_infos_page.html#advanced_mesh_infos_anchor" : 
2992                        "mesh_infos_page.html#mesh_element_info_anchor" );
2993 }
2994
2995 /*!
2996   \brief Show mesh information
2997 */
2998 void SMESHGUI_MeshInfoDlg::updateInfo()
2999 {
3000   SUIT_OverrideCursor wc;
3001
3002   SALOME_ListIO selected;
3003   SMESHGUI::selectionMgr()->selectedObjects( selected );
3004
3005   if ( selected.Extent() == 1 ) {
3006     Handle(SALOME_InteractiveObject) IO = selected.First();
3007     showInfo( IO );
3008   }
3009 //   else {
3010 //     myBaseInfo->clear();
3011 //     myElemInfo->clear();
3012 //     myAddInfo->clear();
3013 //   }
3014 }
3015
3016 /*!
3017   \brief Activate dialog box
3018 */
3019 void SMESHGUI_MeshInfoDlg::activate()
3020 {
3021   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3022   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3023   myTabWidget->setEnabled( true );
3024   updateSelection();
3025 }
3026
3027 /*!
3028   \brief Deactivate dialog box
3029 */
3030 void SMESHGUI_MeshInfoDlg::deactivate()
3031 {
3032   myTabWidget->setEnabled( false );
3033   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3034 }
3035
3036 /*!
3037   \brief Called when users switches between node / element modes.
3038 */
3039 void SMESHGUI_MeshInfoDlg::modeChanged()
3040 {
3041   myID->clear();
3042   updateSelection();
3043 }
3044
3045 /*!
3046   \brief Caled when users prints mesh element ID in the corresponding field.
3047 */
3048 void SMESHGUI_MeshInfoDlg::idChanged()
3049 {
3050   SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector();
3051   if ( myActor && selector ) {
3052     Handle(SALOME_InteractiveObject) IO = myActor->getIO();
3053     TColStd_MapOfInteger ID;
3054     QSet<long> ids;
3055     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3056     foreach ( QString tid, idTxt ) {
3057       long id = tid.trimmed().toLong();
3058       const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? 
3059         myActor->GetObject()->GetMesh()->FindElement( id ) :
3060         myActor->GetObject()->GetMesh()->FindNode( id );
3061       if ( e ) {
3062         ID.Add( id );
3063         ids << id;
3064       }
3065     }
3066     selector->AddOrRemoveIndex( IO, ID, false );
3067     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) {
3068       aViewWindow->highlight( IO, true, true );
3069       aViewWindow->Repaint();
3070     }
3071     myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode );
3072   }
3073 }
3074
3075 void SMESHGUI_MeshInfoDlg::showItemInfo( int id )
3076 {
3077   if ( id > 0 &&  myActor->GetObject()->GetMesh()->FindNode( id ) ) {
3078     myMode->button( NodeMode )->click();
3079     myID->setText( QString::number( id ) );
3080   }
3081 }
3082
3083 void SMESHGUI_MeshInfoDlg::showItemInfo( const QString& theStr )
3084 {
3085   if ( !theStr.isEmpty() ) {
3086     myMode->button( ElemMode )->click();
3087     myID->setText( theStr );
3088   }
3089 }
3090
3091 void SMESHGUI_MeshInfoDlg::dump()
3092 {
3093   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3094   if ( !app ) return;
3095   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3096   if ( !appStudy ) return;
3097   _PTR( Study ) aStudy = appStudy->studyDS();
3098
3099   QStringList aFilters;
3100   aFilters.append( tr( "TEXT_FILES" ) );
3101
3102   bool anIsBase = true;
3103   bool anIsElem = true;
3104   bool anIsAdd  = true;
3105   bool anIsCtrl = true;
3106
3107   if ( SUIT_ResourceMgr* aResourceMgr = SMESHGUI::resourceMgr() ) {
3108     anIsBase = aResourceMgr->booleanValue( "SMESH", "info_dump_base", anIsBase );
3109     anIsElem = aResourceMgr->booleanValue( "SMESH", "info_dump_elem", anIsElem );
3110     anIsAdd  = aResourceMgr->booleanValue( "SMESH", "info_dump_add",  anIsAdd );
3111     anIsCtrl = aResourceMgr->booleanValue( "SMESH", "info_dump_ctrl", anIsCtrl );
3112   }
3113
3114   DumpFileDlg fd( this );
3115   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3116   fd.setFilters( aFilters );
3117   fd.myBaseChk->setChecked( anIsBase );
3118   fd.myElemChk->setChecked( anIsElem );
3119   fd.myAddChk ->setChecked( anIsAdd );
3120   fd.myCtrlChk->setChecked( anIsCtrl );
3121   if ( fd.exec() == QDialog::Accepted )
3122   {
3123     QString aFileName = fd.selectedFile();
3124
3125     bool toBase = fd.myBaseChk->isChecked();
3126     bool toElem = fd.myElemChk->isChecked();
3127     bool toAdd  = fd.myAddChk->isChecked();
3128     bool toCtrl = fd.myCtrlChk->isChecked();
3129
3130     if ( !aFileName.isEmpty() ) {
3131       QFileInfo aFileInfo( aFileName );
3132       if ( aFileInfo.isDir() )
3133         return;
3134  
3135       QFile aFile( aFileName );
3136       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3137         return;
3138       
3139       QTextStream out( &aFile );
3140       
3141       if ( toBase ) myBaseInfo->saveInfo( out );
3142       if ( toElem ) myElemInfo->saveInfo( out );
3143       if ( toAdd )  myAddInfo ->saveInfo( out );
3144       if ( toCtrl ) myCtrlInfo->saveInfo( out );
3145     }
3146   }
3147 }
3148
3149 /*!
3150   \class SMESHGUI_CtrlInfo
3151   \brief Class for the mesh controls information widget.
3152 */
3153
3154 /*!
3155   \brief Constructor
3156   \param parent parent widget
3157 */
3158 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent )
3159   : QFrame( parent ), myPlot( 0 ), myPlot3D( 0 )
3160 {
3161   setFrameStyle( StyledPanel | Sunken );
3162
3163   myMainLayout = new QGridLayout( this );
3164   myMainLayout->setMargin( MARGIN );
3165   myMainLayout->setSpacing( SPACING );
3166
3167   // name
3168   QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this );
3169   QLabel* aName = createField();
3170   aName->setMinimumWidth( 150 );
3171   myWidgets << aName;
3172
3173   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
3174   QIcon aComputeIcon( aResMgr->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3175
3176   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3177
3178   // nodes info
3179   QLabel* aNodesLab = new QLabel( tr( "NODES_INFO" ), this );
3180   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3181   QLabel* aNodesFree = createField();
3182   myWidgets << aNodesFree;
3183   myPredicates << aFilterMgr->CreateFreeNodes();
3184   //
3185   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3186   QLabel* aNodesDouble = createField();
3187   myWidgets << aNodesDouble;
3188   myPredicates << aFilterMgr->CreateEqualNodes();
3189   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3190   myToleranceWidget = new SMESHGUI_SpinBox( this );
3191   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3192   myToleranceWidget->setAcceptNames( false );
3193   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3194
3195   // edges info
3196   QLabel* anEdgesLab = new QLabel( tr( "EDGES_INFO" ),  this );
3197   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3198   QLabel* anEdgesDouble = createField();
3199   myWidgets << anEdgesDouble;
3200   myPredicates << aFilterMgr->CreateEqualEdges();
3201
3202   // faces info
3203   QLabel* aFacesLab = new QLabel( tr( "FACES_INFO" ), this );
3204   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3205   QLabel* aFacesDouble = createField();
3206   myWidgets << aFacesDouble;
3207   myPredicates << aFilterMgr->CreateEqualFaces();
3208   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3209   QLabel* aFacesOver = createField();
3210   myWidgets << aFacesOver;
3211   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3212   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3213   myPlot = createPlot( this );
3214   myAspectRatio = aFilterMgr->CreateAspectRatio();
3215  
3216   // volumes info
3217   QLabel* aVolumesLab = new QLabel( tr( "VOLUMES_INFO" ), this );
3218   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3219   QLabel* aVolumesDouble = createField();
3220   myWidgets << aVolumesDouble;
3221   myPredicates << aFilterMgr->CreateEqualVolumes();
3222   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3223   QLabel* aVolumesOver = createField();
3224   myWidgets << aVolumesOver;
3225   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3226   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3227   myPlot3D = createPlot( this );
3228   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3229
3230   QToolButton* aFreeNodesBtn = new QToolButton( this );
3231   aFreeNodesBtn->setIcon(aComputeIcon);
3232   myButtons << aFreeNodesBtn;       //0
3233
3234   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3235   aDoubleNodesBtn->setIcon(aComputeIcon);
3236   myButtons << aDoubleNodesBtn;     //1
3237
3238   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3239   aDoubleEdgesBtn->setIcon(aComputeIcon);
3240   myButtons << aDoubleEdgesBtn;     //2
3241
3242   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3243   aDoubleFacesBtn->setIcon(aComputeIcon);
3244   myButtons << aDoubleFacesBtn;     //3
3245
3246   QToolButton* aOverContFacesBtn = new QToolButton( this );
3247   aOverContFacesBtn->setIcon(aComputeIcon);
3248   myButtons << aOverContFacesBtn;   //4
3249
3250   QToolButton* aComputeFaceBtn = new QToolButton( this );
3251   aComputeFaceBtn->setIcon(aComputeIcon);
3252   myButtons << aComputeFaceBtn;     //5
3253
3254   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3255   aDoubleVolumesBtn->setIcon(aComputeIcon);
3256   myButtons << aDoubleVolumesBtn;   //6
3257
3258   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3259   aOverContVolumesBtn->setIcon(aComputeIcon);
3260   myButtons << aOverContVolumesBtn; //7
3261
3262   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3263   aComputeVolumeBtn->setIcon(aComputeIcon);
3264   myButtons << aComputeVolumeBtn;   //8
3265
3266   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3267   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3268   connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3269   connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3270   connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3271   connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3272   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3273   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3274   connect( aOverContVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3275   connect( myToleranceWidget, SIGNAL(valueChanged(double)), this, SLOT( setTolerance( double )));
3276
3277   setFontAttributes( aNameLab );
3278   setFontAttributes( aNodesLab );
3279   setFontAttributes( anEdgesLab );
3280   setFontAttributes( aFacesLab );
3281   setFontAttributes( aVolumesLab );
3282
3283   myMainLayout->addWidget( aNameLab,           0, 0 );       //0
3284   myMainLayout->addWidget( aName,              0, 1, 1, 2 ); //1
3285   myMainLayout->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3286   myMainLayout->addWidget( aNodesFreeLab,      2, 0 );       //3
3287   myMainLayout->addWidget( aNodesFree,         2, 1 );       //4
3288   myMainLayout->addWidget( aFreeNodesBtn,      2, 2 );       //5
3289   myMainLayout->addWidget( aNodesDoubleLab,    3, 0 );       //6
3290   myMainLayout->addWidget( aNodesDouble,       3, 1 );       //7
3291   myMainLayout->addWidget( aDoubleNodesBtn,    3, 2 );       //8
3292   myMainLayout->addWidget( aToleranceLab,      4, 0 );       //9
3293   myMainLayout->addWidget( myToleranceWidget,  4, 1 );       //10
3294   myMainLayout->addWidget( anEdgesLab,         5, 0, 1, 3 ); //11
3295   myMainLayout->addWidget( anEdgesDoubleLab,   6, 0 );       //12
3296   myMainLayout->addWidget( anEdgesDouble,      6, 1 );       //13
3297   myMainLayout->addWidget( aDoubleEdgesBtn,    6, 2 );       //14
3298   myMainLayout->addWidget( aFacesLab,          7, 0, 1, 3 ); //15
3299   myMainLayout->addWidget( aFacesDoubleLab,    8, 0 );       //16
3300   myMainLayout->addWidget( aFacesDouble,       8, 1 );       //17
3301   myMainLayout->addWidget( aDoubleFacesBtn,    8, 2 );       //18
3302   myMainLayout->addWidget( aFacesOverLab,      9, 0 );       //19
3303   myMainLayout->addWidget( aFacesOver,         9, 1 );       //20
3304   myMainLayout->addWidget( aOverContFacesBtn,  9, 2 );       //21
3305   myMainLayout->addWidget( anAspectRatioLab,   10, 0 );      //22
3306   myMainLayout->addWidget( aComputeFaceBtn,    10, 2 );      //23
3307   myMainLayout->addWidget( myPlot,             11, 0, 1, 3 );//24
3308   myMainLayout->addWidget( aVolumesLab,        12, 0, 1, 3 );//25
3309   myMainLayout->addWidget( aVolumesDoubleLab,  13, 0 );      //26
3310   myMainLayout->addWidget( aVolumesDouble,     13, 1 );      //27
3311   myMainLayout->addWidget( aDoubleVolumesBtn,  13, 2 );      //28
3312   myMainLayout->addWidget( aVolumesOverLab,    14, 0 );      //28
3313   myMainLayout->addWidget( aVolumesOver,       14, 1 );      //30
3314   myMainLayout->addWidget( aOverContVolumesBtn,14, 2 );      //31
3315   myMainLayout->addWidget( anAspectRatio3DLab, 15, 0 );      //32
3316   myMainLayout->addWidget( aComputeVolumeBtn,  15, 2 );      //33
3317   myMainLayout->addWidget( myPlot3D,           16, 0, 1, 3 );//34
3318  
3319   myMainLayout->setColumnStretch(  0,  0 );
3320   myMainLayout->setColumnStretch(  1,  5 );
3321   myMainLayout->setRowStretch   ( 11,  5 );
3322   myMainLayout->setRowStretch   ( 16,  5 );
3323   myMainLayout->setRowStretch   ( 17,  1 );
3324
3325   clearInternal();
3326 }
3327
3328 /*!
3329   \brief Destructor
3330 */
3331 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3332 {}
3333
3334 /*!
3335   \brief Change widget font attributes (bold, ...).
3336   \param w widget
3337   \param attr font attributes (XORed flags)
3338 */
3339 void SMESHGUI_CtrlInfo::setFontAttributes( QWidget* w )
3340 {
3341   if ( w ) {
3342     QFont f = w->font();
3343     f.setBold( true );
3344     w->setFont( f );
3345   }
3346 }
3347
3348 /*!
3349   \brief Create info field
3350   \return new info field
3351 */
3352 QLabel* SMESHGUI_CtrlInfo::createField()
3353 {
3354   QLabel* lab = new QLabel( this );
3355   lab->setFrameStyle( StyledPanel | Sunken );
3356   lab->setAlignment( Qt::AlignCenter );
3357   lab->setAutoFillBackground( true );
3358   QPalette pal = lab->palette();
3359   pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) );
3360   lab->setPalette( pal );
3361   lab->setMinimumWidth( 60 );
3362   return lab;
3363 }
3364
3365 /*!
3366   \brief Create QwtPlot
3367   \return new QwtPlot
3368 */
3369 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3370 {
3371   QwtPlot* aPlot = new QwtPlot( parent );
3372   aPlot->setMinimumSize( 100, 100 );
3373   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3374   xFont.setPointSize( 5 );
3375   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3376   yFont.setPointSize( 5 );
3377   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3378   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3379   aPlot->replot();
3380   return aPlot;
3381 }
3382
3383 /*!
3384   \brief Show controls information on the selected object
3385 */
3386 void SMESHGUI_CtrlInfo::showInfo( SMESH::SMESH_IDSource_ptr obj )
3387 {
3388   clearInternal();
3389
3390   myObject = SMESH::SMESH_IDSource::_duplicate( obj );
3391   if ( myObject->_is_nil() ) return;
3392
3393   if ( _PTR(SObject) aSO = SMESH::FindSObject( obj ))
3394     myWidgets[0]->setText( aSO->GetName().c_str() );
3395
3396   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3397   if ( mesh->_is_nil() ) return;
3398
3399   const bool meshLoaded = mesh->IsLoaded();
3400   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3401     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3402     for ( int i = 0; i < myButtons.count(); ++i )
3403       myButtons[i]->setEnabled( true );
3404
3405   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3406   if ( ! &nbElemsByType.in() ) return;
3407
3408   const CORBA::Long ctrlLimit =
3409     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3410
3411   // nodes info
3412   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3413   const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3414                                 nbElemsByType[ SMESH::FACE ] +
3415                                 nbElemsByType[ SMESH::VOLUME ] );
3416   if ( nbNodes + nbElems > 0 ) {
3417     if ( Max( (int)nbNodes, (int)nbElems ) <= ctrlLimit ) {
3418       // free nodes
3419       computeFreeNodesInfo();
3420       // double nodes
3421       if ( Max( (int)mesh->NbNodes(), (int)mesh->NbElements() ) <= ctrlLimit )
3422         computeDoubleNodesInfo();
3423     }
3424     else {
3425       myButtons[0]->setEnabled( true );
3426       myButtons[1]->setEnabled( true );
3427     }
3428   }
3429   else {
3430     for( int i=2; i<=10; i++)
3431       myMainLayout->itemAt(i)->widget()->setVisible( false );
3432   }
3433
3434   // edges info
3435   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3436     // double edges
3437     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3438       computeDoubleEdgesInfo();
3439     else
3440       myButtons[2]->setEnabled( true );
3441   }
3442   else {
3443     for( int i=11; i<=14; i++)
3444       myMainLayout->itemAt(i)->widget()->setVisible( false );
3445   }
3446  
3447   // faces info
3448   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3449     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3450       // double faces
3451       computeDoubleFacesInfo();
3452       // over constrained faces
3453       computeOverConstrainedFacesInfo();
3454       // aspect Ratio histogram
3455       computeAspectRatio();
3456     }
3457     else {
3458       myButtons[3]->setEnabled( true );
3459       myButtons[4]->setEnabled( true );
3460       myButtons[5]->setEnabled( true );
3461     }
3462   }
3463   else {
3464     myMainLayout->setRowStretch(11,0);
3465     for( int i=15; i<=24; i++)
3466       myMainLayout->itemAt(i)->widget()->setVisible( false );
3467   }
3468
3469   // volumes info
3470   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3471     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3472       // double volumes
3473       computeDoubleVolumesInfo();
3474       // over constrained volumes
3475       computeOverConstrainedVolumesInfo();
3476       // aspect Ratio 3D histogram
3477       computeAspectRatio3D();
3478      }
3479      else {
3480        myButtons[6]->setEnabled( true );
3481        myButtons[7]->setEnabled( true );
3482        myButtons[8]->setEnabled( true );
3483      }
3484   }
3485   else {
3486     myMainLayout->setRowStretch(16,0);
3487     for( int i=25; i<=34; i++)
3488       myMainLayout->itemAt(i)->widget()->setVisible( false );
3489   }
3490 }
3491
3492 //================================================================================
3493 /*!
3494  * \brief Computes and shows nb of elements satisfying a given predicate
3495  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3496  *  \param [in] iBut - index of one of myButtons to disable
3497  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3498  */
3499 //================================================================================
3500
3501 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3502 {
3503   myButtons[ iBut ]->setEnabled( false );
3504   myWidgets[ iWdg ]->setText( "" );
3505   if ( myObject->_is_nil() ) return;
3506
3507   SUIT_OverrideCursor wc;
3508
3509   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3510   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3511   {
3512     mesh->Load();
3513     this->showInfo( myObject ); // try to show all values
3514     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3515       return; // <ft> predicate already computed
3516   }
3517   // look for a predicate of type <ft>
3518   for ( int i = 0; i < myPredicates.count(); ++i )
3519     if ( myPredicates[i]->GetFunctorType() == ft )
3520     {
3521       CORBA::Long nb = myPredicates[i]->NbSatisfying( myObject );
3522       myWidgets[ iWdg ]->setText( QString::number( nb ));
3523     }
3524 }
3525
3526 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3527 {
3528   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3529 }
3530
3531 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3532 {
3533   computeNb( SMESH::FT_EqualNodes, 1, 2 );
3534 }
3535
3536 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3537 {
3538   computeNb( SMESH::FT_EqualEdges, 2, 3 );
3539 }
3540
3541 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3542 {
3543   computeNb( SMESH::FT_EqualFaces, 3, 4 );
3544 }
3545
3546 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3547 {
3548   computeNb( SMESH::FT_OverConstrainedFace, 4, 5 );
3549 }
3550
3551 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3552 {
3553   computeNb( SMESH::FT_EqualVolumes, 6, 6 );
3554 }
3555
3556 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3557 {
3558   computeNb( SMESH::FT_OverConstrainedVolume, 7, 7 );
3559 }
3560
3561 void SMESHGUI_CtrlInfo::computeAspectRatio()
3562 {
3563   myButtons[5]->setEnabled( false );
3564
3565   if ( myObject->_is_nil() ) return;
3566
3567   SUIT_OverrideCursor wc;
3568
3569   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3570   if ( aHistogram && !aHistogram->isEmpty() ) {
3571     QwtPlotItem* anItem = aHistogram->createPlotItem();
3572     anItem->attach( myPlot );
3573     myPlot->replot();
3574   }
3575   delete aHistogram;
3576 }
3577
3578 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3579 {
3580   myButtons[8]->setEnabled( false );
3581
3582   if ( myObject->_is_nil() ) return;
3583
3584   SUIT_OverrideCursor wc;
3585
3586   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3587   if ( aHistogram && !aHistogram->isEmpty() ) {
3588     QwtPlotItem* anItem = aHistogram->createPlotItem();
3589     anItem->attach( myPlot3D );
3590     myPlot3D->replot();
3591   }
3592   delete aHistogram;
3593 }
3594
3595 /*!
3596   \brief Internal clean-up (reset widget)
3597 */
3598 void SMESHGUI_CtrlInfo::clearInternal()
3599 {
3600   for( int i=0; i<=34; i++)
3601     myMainLayout->itemAt(i)->widget()->setVisible( true );
3602   for( int i=0; i<=8; i++)
3603     myButtons[i]->setEnabled( false );
3604   myPlot->detachItems();
3605   myPlot3D->detachItems();
3606   myPlot->replot();
3607   myPlot3D->replot();
3608   myWidgets[0]->setText( QString() );
3609   for ( int i = 1; i < myWidgets.count(); i++ )
3610     myWidgets[i]->setText( "" );
3611   myMainLayout->setRowStretch(11,5);
3612   myMainLayout->setRowStretch(16,5);
3613 }
3614
3615 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3616 {
3617   //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE );
3618   myButtons[1]->setEnabled( true );
3619   myWidgets[2]->setText("");
3620 }
3621
3622 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3623 {
3624   SMESH::SMESH_Mesh_var mesh = myObject->GetMesh();
3625   if ( mesh->_is_nil() ) return 0;
3626   if ( !mesh->IsLoaded() )
3627     mesh->Load();
3628   aNumFun->SetMesh( mesh );
3629
3630   CORBA::Long cprecision = 6;
3631   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) 
3632     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3633   aNumFun->SetPrecision( cprecision );
3634
3635   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3636
3637   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3638                                                                   /*isLogarithmic=*/false,
3639                                                                   myObject );
3640   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3641   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3642   if ( &histogramVar.in() )
3643   {
3644     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3645       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3646     if ( histogramVar->length() >= 2 )
3647       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3648   }
3649   return aHistogram;
3650 }
3651
3652 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) {
3653   out << QString( 20, '-' ) << "\n";
3654   out << tr( "CTRL_INFO"  ) << "\n";
3655   out << QString( 20, '-' ) << "\n";
3656   out <<                                 tr( "NAME_LAB" )                       << "  " << myWidgets[0]->text() << "\n";
3657   out <<                                 tr( "NODES_INFO" )                     << "\n";
3658   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_FREE_NODES" )       << ": " << myWidgets[1]->text() << "\n";
3659   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_NODES" )     << ": " << myWidgets[2]->text() << "\n";
3660   out <<                                 tr( "EDGES_INFO" )                     << "\n";
3661   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_EDGES" )     << ": " << myWidgets[3]->text() << "\n";
3662   out <<                                 tr( "FACES_INFO" )                     << "\n";
3663   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_FACES" )     << ": " << myWidgets[4]->text() << "\n";
3664   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << "\n";
3665   out <<                                 tr( "VOLUMES_INFO" )                   << "\n";
3666   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" )   << ": " << myWidgets[6]->text() << "\n";
3667   out << QString( SPACING_INFO, ' ' ) << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << "\n";
3668 }
3669
3670 /*!
3671   \class SMESHGUI_CtrlInfoDlg
3672   \brief Controls information dialog box
3673 */
3674
3675 /*!
3676   \brief Constructor
3677   \param parent parent widget
3678   \param page specifies the dialog page to be shown at the start-up
3679 */
3680 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3681 : QDialog( parent )
3682 {
3683   setAttribute( Qt::WA_DeleteOnClose, true );
3684   setWindowTitle( tr( "CTRL_INFO" ) );
3685   setMinimumSize( 400, 600 );
3686
3687   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3688   
3689   // buttons
3690   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3691   okBtn->setAutoDefault( true );
3692   okBtn->setDefault( true );
3693   okBtn->setFocus();
3694   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3695   dumpBtn->setAutoDefault( true );
3696   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3697   helpBtn->setAutoDefault( true );
3698
3699   QHBoxLayout* btnLayout = new QHBoxLayout;
3700   btnLayout->setSpacing( SPACING );
3701   btnLayout->setMargin( 0 );
3702
3703   btnLayout->addWidget( okBtn );
3704   btnLayout->addWidget( dumpBtn );
3705   btnLayout->addStretch( 10 );
3706   btnLayout->addWidget( helpBtn );
3707
3708   QVBoxLayout* l = new QVBoxLayout ( this );
3709   l->setMargin( MARGIN );
3710   l->setSpacing( SPACING );
3711   l->addWidget( myCtrlInfo );
3712   l->addLayout( btnLayout );
3713
3714   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
3715   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3716   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3717   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3718   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
3719
3720   updateSelection();
3721 }
3722
3723 /*!
3724   \brief Destructor
3725 */
3726 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
3727 {
3728 }
3729
3730 /*!
3731   \brief Show controls information
3732   \param IO interactive object
3733 */
3734 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO )
3735 {  
3736   if ( SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( IO ) )
3737     myCtrlInfo->showInfo( obj );
3738 }
3739
3740 /*!
3741   \brief Perform clean-up actions on the dialog box closing.
3742 */
3743 void SMESHGUI_CtrlInfoDlg::reject()
3744 {
3745   SMESH::SetPointRepresentation( false );
3746   QDialog::reject();
3747 }
3748
3749 /*!
3750   \brief Setup selection mode depending on the current dialog box state.
3751 */
3752 void SMESHGUI_CtrlInfoDlg::updateSelection()
3753 {
3754   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3755   disconnect( selMgr, 0, this, 0 );
3756   SMESH::SetPointRepresentation( false );  
3757   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3758   updateInfo();  
3759 }
3760
3761 /*!
3762   \brief Show mesh information
3763 */
3764 void SMESHGUI_CtrlInfoDlg::updateInfo()
3765 {
3766   SUIT_OverrideCursor wc;
3767
3768   SALOME_ListIO selected;
3769   SMESHGUI::selectionMgr()->selectedObjects( selected );
3770
3771   if ( selected.Extent() == 1 ) {
3772     Handle(SALOME_InteractiveObject) IO = selected.First();
3773     showInfo( IO );
3774   }
3775 }
3776
3777 /*!
3778   \brief Activate dialog box
3779 */
3780 void SMESHGUI_CtrlInfoDlg::activate()
3781 {
3782   SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog();
3783   SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this );
3784   updateSelection();
3785 }
3786
3787 /*!
3788   \brief Deactivate dialog box
3789 */
3790 void SMESHGUI_CtrlInfoDlg::deactivate()
3791 {
3792   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3793 }
3794
3795 /*!
3796  * \brief Dump contents into a file
3797  */
3798 void SMESHGUI_CtrlInfoDlg::dump()
3799 {
3800   SUIT_Application* app = SUIT_Session::session()->activeApplication();
3801   if ( !app ) return;
3802   SalomeApp_Study* appStudy = dynamic_cast<SalomeApp_Study *>( app->activeStudy() );
3803   if ( !appStudy ) return;
3804   _PTR( Study ) aStudy = appStudy->studyDS();
3805
3806   QStringList aFilters;
3807   aFilters.append( tr( "TEXT_FILES" ) );
3808
3809   DumpFileDlg fd( this );
3810   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3811   fd.setFilters( aFilters );
3812   fd.myBaseChk->hide();
3813   fd.myElemChk->hide();
3814   fd.myAddChk ->hide();
3815   fd.myCtrlChk->hide();
3816   if ( fd.exec() == QDialog::Accepted )
3817   {
3818     QString aFileName = fd.selectedFile();
3819     if ( !aFileName.isEmpty() ) {
3820       QFileInfo aFileInfo( aFileName );
3821       if ( aFileInfo.isDir() )
3822         return;
3823  
3824       QFile aFile( aFileName );
3825       if ( !aFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
3826         return;
3827       
3828       QTextStream out( &aFile );
3829       myCtrlInfo->saveInfo( out );
3830     }
3831   }
3832 }
3833
3834 /*!
3835  * \brief Show help
3836  */
3837 void SMESHGUI_CtrlInfoDlg::help()
3838 {
3839   SMESH::ShowHelpFile("mesh_infos_page.html#mesh_quality_info_anchor");
3840 }