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