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