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