Salome HOME
Update of CheckDone
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "SMESHGUI_MeshInfo.h"
24
25 #include "SMDS_Mesh.hxx"
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 Field
70 /// \brief Field widget.
71 /// \internal
72 ////////////////////////////////////////////////////////////////////////////////
73
74 class Field : public QLabel
75 {
76 public:
77   Field( QWidget*, const QString& = QString() );
78   bool event( QEvent* );
79 };
80
81 /*!
82   \brief Constructor.
83   \param parent Parent widget.
84   \param name Field name. Defaults to null string.
85 */
86 Field::Field( 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 Field::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 Field's object. Default to null string.
336     \return New field.
337   */
338   QLabel* createField( QWidget* parent, const QString& name = QString() )
339   {
340     return new Field( 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_MinimumAngle:
1678     title = tr( "MINIMUMANGLE_ELEMENTS" ); break;
1679   case SMESH::FT_Taper:
1680     title = tr( "TAPER_ELEMENTS" ); break;
1681   case SMESH::FT_Skew:
1682     title = tr( "SKEW_ELEMENTS" ); break;
1683   case SMESH::FT_Area:
1684     title = tr( "AREA_ELEMENTS" ); break;
1685   case SMESH::FT_Volume3D:
1686     title = tr( "VOLUME_3D_ELEMENTS" ); break;
1687   case SMESH::FT_MaxElementLength2D:
1688     title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
1689   case SMESH::FT_MaxElementLength3D:
1690     title = tr( "MAX_ELEMENT_LENGTH_3D" ); break;
1691   case SMESH::FT_Length:
1692     title = tr( "LENGTH_EDGES" ); break;
1693   case SMESH::FT_Length2D:
1694   case SMESH::FT_Length3D:
1695     title = tr( "MIN_ELEM_EDGE" ); break;
1696   case SMESH::FT_BallDiameter:
1697     title = tr( "BALL_DIAMETER" ); break;
1698   default:
1699     break;
1700   }
1701   return title;
1702 }
1703
1704 /*!
1705   \brief Write information on given mesh nodes / elements.
1706   \param writer Information writer.
1707   \param ids Nodes / elements IDs.
1708 */
1709 void SMESHGUI_ElemInfo::writeInfo( InfoWriter* writer, const QList<uint>& ids )
1710 {
1711   if ( !proxy() )
1712     return;
1713
1714   bool grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1715   int cprecision = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ? 
1716     SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ) : -1;
1717
1718   SMESH::XYZ xyz;
1719   SMESH::Connectivity connectivity;
1720   SMESH::Position position;
1721   bool ok;
1722
1723   foreach ( uint id, ids )
1724   {
1725     writer->separator();
1726
1727     if ( what() == ShowNodes )
1728     {
1729       // show node info
1730       // - check that node exists
1731       if ( !proxy().hasNode( id ) )
1732         continue;
1733       // - id
1734       writer->write( tr( "NODE" ), (int)id, true );
1735       writer->indent();
1736       // - coordinates
1737       ok = proxy().nodeCoordinates( id, xyz );
1738       if ( ok )
1739       {
1740         writer->write( tr( "COORDINATES" ), xyz );
1741       }
1742       // - connectivity
1743       ok = proxy().nodeConnectivity( id, connectivity );
1744       if ( ok )
1745       {
1746         if ( !connectivity.isEmpty() )
1747         {
1748           writer->write( tr( "CONNECTIVITY" ) );
1749           writer->indent();
1750           for ( int i = SMDSAbs_Edge; i <= SMDSAbs_Ball; i++ )
1751           {
1752             QString formatted = formatConnectivity( connectivity, i );
1753             if ( !formatted.isEmpty() )
1754               writer->write( type2str( i, true ), formatted );
1755           }
1756           writer->unindent();
1757         }
1758         else
1759         {
1760           writer->write( tr( "CONNECTIVITY" ), tr( "FREE_NODE" ) );
1761         }
1762       }
1763       // - position
1764       ok = proxy().nodePosition( id, position );
1765       if ( ok && position.isValid() )
1766       {
1767         writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
1768         writer->indent();
1769         if ( position.hasU() )
1770           writer->write( tr("U_POSITION"), position.u() );
1771         if ( position.hasV() )
1772           writer->write( tr("V_POSITION"), position.v() );
1773         writer->unindent();
1774       }
1775       // - groups node belongs to
1776       QList<SMESH::SelectionProxy> groups = proxy().nodeGroups( id );
1777       bool topCreated = false;
1778       foreach( SMESH::SelectionProxy group, groups )
1779       {
1780         if ( group && !group.name().isEmpty() )
1781         {
1782           if ( !topCreated )
1783           {
1784             writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
1785             writer->indent();
1786             topCreated = true;
1787           }
1788           writer->write( group.name().trimmed() ); // trim name
1789           if ( grp_details )
1790           {
1791             writer->indent();
1792             int type = group.type();
1793             if ( type == SMESH::SelectionProxy::GroupStd )
1794             {
1795               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1796             }
1797             else if ( type == SMESH::SelectionProxy::GroupGeom )
1798             {
1799               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1800               writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
1801             }
1802             else if ( type == SMESH::SelectionProxy::GroupFilter )
1803             {
1804               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1805             }
1806             int size = group.size();
1807             if ( size != -1 )
1808               writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
1809             QColor color = group.color();
1810             if ( color.isValid() )
1811               writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
1812             writer->unindent();
1813           }
1814         }
1815       }
1816       if ( topCreated )
1817         writer->unindent();
1818       writer->unindent();
1819     }
1820     else if ( what() == ShowElements )
1821     {
1822       // show element info
1823       // - check that element exists
1824       if ( !proxy().hasElement( id ) )
1825         continue;
1826       // - id & type
1827       int type = proxy().elementType( id );
1828       if  ( type == SMESH::ALL )
1829         continue;
1830       writer->write( type2str( type ), (int)id, true );
1831       writer->indent();
1832       // - geometry type
1833       type = proxy().elementEntityType( id );
1834       writer->write( tr( "TYPE" ), etype2str( type ) );
1835       // - connectivity
1836       if ( type == SMESH::Entity_Polyhedra ||
1837            type == SMESH::Entity_Quad_Polyhedra )
1838       {
1839         int nbNodes;
1840         ok = proxy().perFaceConnectivity( id, connectivity, nbNodes );
1841         if ( ok && !connectivity.isEmpty() )
1842         {
1843           writer->write( tr( "NB_NODES" ), nbNodes );
1844           writer->write( tr( "CONNECTIVITY" ) );
1845           writer->indent();
1846           int nbFaces = connectivity.size();
1847           for ( int iF = 1; iF <= nbFaces; ++iF )
1848           {
1849             QString formatted = formatConnectivity( connectivity, -iF );
1850             writer->write(( type2str( SMDSAbs_Face, 0 ) + " %1 / %2" ).arg( iF ).arg( nbFaces ),
1851                           formatted );
1852           }
1853           writer->unindent();
1854         }
1855       }
1856       else
1857       {
1858         ok = proxy().elementConnectivity( id, connectivity );
1859         if ( ok && !connectivity.isEmpty() )
1860         {
1861           QString formatted = formatConnectivity( connectivity, SMDSAbs_Node );
1862           if ( !formatted.isEmpty() )
1863           {
1864             writer->write( tr( "NB_NODES" ), connectivity[ SMDSAbs_Node ].size() );
1865             writer->write( tr( "CONNECTIVITY" ), formatted ); //todo: TypeRole: ElemConnectivity
1866           }
1867         }
1868       }
1869       // - position
1870       ok = proxy().elementPosition( id, position );
1871       if ( ok && position.isValid() )
1872       {
1873         writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
1874       }
1875       // - gravity center
1876       ok = proxy().elementGravityCenter( id, xyz );
1877       if ( ok )
1878       {
1879         writer->write( tr( "GRAVITY_CENTER" ), xyz );
1880       }
1881       // - normal vector
1882       ok = proxy().elementNormal( id, xyz );
1883       if ( ok )
1884       {
1885         writer->write( tr( "NORMAL_VECTOR" ), xyz );
1886       }
1887       // - controls
1888       bool topCreated = false;
1889       for ( int i = SMESH::FT_AspectRatio; i < SMESH::FT_Undefined; i++ )
1890       {
1891         QString ctrlTitle = ctrl2str( i );
1892         if ( ctrlTitle.isEmpty() )
1893           continue;
1894         if ( !topCreated )
1895         {
1896           writer->write( tr( "CONTROLS" ) );
1897           writer->indent();
1898           topCreated = true;
1899         }
1900         double value;
1901         if ( proxy().elementControl( id, i, cprecision, value ) )
1902           writer->write( ctrlTitle, value );
1903       }
1904       if ( topCreated )
1905         writer->unindent();
1906       // - groups element belongs to
1907       QList<SMESH::SelectionProxy> groups = proxy().elementGroups( id );
1908       topCreated = false;
1909       foreach( SMESH::SelectionProxy group, groups )
1910       {
1911         if ( group && !group.name().isEmpty() )
1912         {
1913           if ( !topCreated )
1914           {
1915             writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
1916             writer->indent();
1917             topCreated = true;
1918           }
1919           writer->write( group.name().trimmed() ); // trim name
1920           if ( grp_details )
1921           {
1922             writer->indent();
1923             int type = group.type();
1924             if ( type == SMESH::SelectionProxy::GroupStd )
1925             {
1926               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1927             }
1928             else if ( type == SMESH::SelectionProxy::GroupGeom )
1929             {
1930               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1931               writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
1932             }
1933             else if ( type == SMESH::SelectionProxy::GroupFilter )
1934             {
1935               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1936             }
1937             int size = group.size();
1938             if ( size != -1 )
1939               writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
1940             QColor color = group.color();
1941             if ( color.isValid() )
1942               writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
1943             writer->unindent();
1944           }
1945         }
1946       }
1947       if ( topCreated )
1948         writer->unindent();
1949       writer->unindent();
1950     }
1951   }  
1952 }
1953
1954 /*!
1955   \fn void SMESHGUI_ElemInfo::information( const QList<uint>& ids )
1956   \brief Show information on given mesh nodes / elements.
1957
1958   This function has to be redefined in sub-classes.
1959
1960   \param ids Nodes / elements IDs.
1961 */
1962
1963 /*!
1964   \brief Internal clean-up (reset panel).
1965
1966   Default implementation does nothing; the method has to be redefined
1967   in sub-classes to perform internal clean-up.
1968 */
1969 void SMESHGUI_ElemInfo::clearInternal()
1970 {
1971 }
1972
1973 /*!
1974   \brief Show previous chunk of information.
1975 */
1976 void SMESHGUI_ElemInfo::showPrevious()
1977 {
1978   myIndex = qMax( 0, myIndex-1 );
1979   updateControls();
1980   information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
1981 }
1982
1983 /*!
1984   \brief Show next chunk of information.
1985 */
1986 void SMESHGUI_ElemInfo::showNext()
1987 {
1988   myIndex = qMin( myIndex+1, myIDs.count() / blockSize() );
1989   updateControls();
1990   information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
1991 }
1992
1993 /*!
1994   \brief Update control widget state.
1995 */
1996 void SMESHGUI_ElemInfo::updateControls()
1997 {
1998   myExtra->updateControls( myIDs.count(), myIndex );
1999 }
2000
2001 /*!
2002   \brief Write information from panel to output stream.
2003   \param out Text stream output.
2004 */
2005 void SMESHGUI_ElemInfo::saveInfo( QTextStream &out )
2006 {
2007   // title
2008   QString title = tr( "ELEM_INFO" );
2009   out << ruler( title.size() ) << endl;
2010   out << title << endl;
2011   out << ruler( title.size() ) << endl;
2012   //  out << endl;
2013
2014   // info
2015   StreamWriter writer( out );
2016   writeInfo( &writer, myIDs );
2017   out << endl;
2018 }
2019
2020 ////////////////////////////////////////////////////////////////////////////////
2021 /// \class SMESHGUI_SimpleElemInfo
2022 /// \brief Show mesh element information in the simple text area.
2023 ////////////////////////////////////////////////////////////////////////////////
2024
2025 /*!
2026   \brief Constructor.
2027   \param parent Parent widget. Defaults to 0.
2028 */
2029 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
2030   : SMESHGUI_ElemInfo( parent )
2031 {
2032   myInfo = new QTextBrowser( centralWidget() );
2033   QVBoxLayout* l = new QVBoxLayout( centralWidget() );
2034   l->setMargin( 0 );
2035   l->addWidget( myInfo );
2036
2037   connect( myInfo, SIGNAL( anchorClicked(QUrl)), this, SLOT( connectivityClicked( QUrl )));
2038 }
2039
2040 /*!
2041   \brief Show mesh element information.
2042   \param ids Nodes / elements IDs.
2043 */
2044 void SMESHGUI_SimpleElemInfo::information( const QList<uint>& ids )
2045 {
2046   clearInternal();
2047   TextWriter writer( myInfo );
2048   writeInfo( &writer, ids );
2049 }
2050
2051 /*!
2052   \brief Internal clean-up (reset widget)
2053 */
2054 void SMESHGUI_SimpleElemInfo::clearInternal()
2055 {
2056   myInfo->clear();
2057 }
2058
2059 void SMESHGUI_SimpleElemInfo::connectivityClicked(const QUrl & url)
2060 {
2061   int type = ( url.scheme()[0] == 'n' ) ? NodeConnectivity : ElemConnectivity;
2062   QString ids = url.path(); // excess chars will be filtered off by SMESHGUI_IdValidator
2063   emit( itemInfo( type, ids ));
2064 }
2065
2066 ////////////////////////////////////////////////////////////////////////////////
2067 /// \class SMESHGUI_TreeElemInfo::ItemDelegate
2068 /// \brief Item delegate for tree mesh info widget.
2069 /// \internal
2070 ////////////////////////////////////////////////////////////////////////////////
2071
2072 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
2073 {
2074 public:
2075   ItemDelegate( QObject* );
2076   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
2077 };
2078
2079 /*!
2080   \brief Constructor.
2081   \internal
2082 */
2083 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ): QItemDelegate( parent )
2084 {
2085 }
2086
2087 /*!
2088   \brief Redefined from QItemDelegate.
2089   \internal
2090 */
2091 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
2092 {
2093   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
2094   if ( qobject_cast<QLineEdit*>( w ) )
2095     qobject_cast<QLineEdit*>( w )->setReadOnly( true );
2096   return w;
2097 }
2098
2099 ////////////////////////////////////////////////////////////////////////////////
2100 /// \class SMESHGUI_TreeElemInfo::ItemCreator
2101 /// \brief Item creator for tree mesh info widget.
2102 /// \internal
2103 ////////////////////////////////////////////////////////////////////////////////
2104
2105 class SMESHGUI_TreeElemInfo::ItemCreator : public TreeItemCreator
2106 {
2107   SMESHGUI_TreeElemInfo* myView;
2108 public:
2109   ItemCreator( SMESHGUI_TreeElemInfo* );
2110   QTreeWidgetItem* createItem( QTreeWidgetItem*, int );
2111 };
2112
2113 /*!
2114   \brief Constructor.
2115   \param view Parent view.
2116   \internal
2117 */
2118 SMESHGUI_TreeElemInfo::ItemCreator::ItemCreator( SMESHGUI_TreeElemInfo* view ): TreeItemCreator(), myView( view )
2119 {
2120 }
2121
2122 /*!
2123   \brief Create new tree item.
2124   \param parent Parent tree item.
2125   \param options Item options.
2126   \return New tree widget item.
2127   \internal
2128 */
2129 QTreeWidgetItem* SMESHGUI_TreeElemInfo::ItemCreator::createItem( QTreeWidgetItem* parent, int options )
2130 {
2131   return myView->createItem( parent, options );
2132 }
2133
2134 ////////////////////////////////////////////////////////////////////////////////
2135 /// \class SMESHGUI_TreeElemInfo
2136 /// \brief Show mesh element information as the tree.
2137 ////////////////////////////////////////////////////////////////////////////////
2138
2139 /*!
2140   \brief Constructor.
2141   \param parent Parent widget. Defaults to 0.
2142 */
2143 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
2144   : SMESHGUI_ElemInfo( parent )
2145 {
2146   myInfo = new QTreeWidget( centralWidget() );
2147   myInfo->setColumnCount( 2 );
2148   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
2149   myInfo->header()->setStretchLastSection( true );
2150   myInfo->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2151   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
2152   QVBoxLayout* l = new QVBoxLayout( centralWidget() );
2153   l->setMargin( 0 );
2154   l->addWidget( myInfo );
2155   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
2156   connect( myInfo, SIGNAL( itemCollapsed( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
2157   connect( myInfo, SIGNAL( itemExpanded( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
2158 }
2159
2160 /*!
2161   \brief Show mesh element information.
2162   \param ids Nodes / elements IDs.
2163 */
2164 void SMESHGUI_TreeElemInfo::information( const QList<uint>& ids )
2165 {
2166   clearInternal();
2167   TreeWriter writer( myInfo, new ItemCreator( this ) );
2168   writeInfo( &writer, ids );
2169 }
2170
2171 /*!
2172   \brief Show node information
2173   \param node mesh node for showing
2174   \param index index of current node
2175   \param nbNodes number of unique nodes in element
2176   \param parentItem parent item of tree
2177 */
2178 void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* /*node*/, int /*index*/,
2179                                       int /*nbNodes*/, QTreeWidgetItem* /*parentItem*/ )
2180 {
2181   // int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
2182   // // node number and ID
2183   // QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
2184   // nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( index ).arg( nbNodes ));
2185   // nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ));
2186   // nodeItem->setData( 1, TypeRole, ElemConnectivity );
2187   // nodeItem->setData( 1, IdRole, node->GetID() );
2188   // nodeItem->setExpanded( false );
2189   // // node coordinates
2190   // QTreeWidgetItem* coordItem = createItem( nodeItem );
2191   // coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ));
2192   // QTreeWidgetItem* xItem = createItem( coordItem );
2193   // xItem->setText( 0, "X" );
2194   // xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2195   // QTreeWidgetItem* yItem = createItem( coordItem );
2196   // yItem->setText( 0, "Y" );
2197   // yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2198   // QTreeWidgetItem* zItem = createItem( coordItem );
2199   // zItem->setText( 0, "Z" );
2200   // zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2201   // // node connectivity
2202   // QTreeWidgetItem* nconItem = createItem( nodeItem );
2203   // nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
2204   // Connectivity connectivity = nodeConnectivity( node );
2205   // if ( !connectivity.isEmpty() ) {
2206   //   QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
2207   //   if ( !con.isEmpty() ) {
2208   //     QTreeWidgetItem* i = createItem( nconItem );
2209   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ));
2210   //     i->setText( 1, con );
2211   //   }
2212   //   con = formatConnectivity( connectivity, SMDSAbs_Edge );
2213   //   if ( !con.isEmpty() ) {
2214   //     QTreeWidgetItem* i = createItem( nconItem );
2215   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ));
2216   //     i->setText( 1, con );
2217   //     i->setData( 1, TypeRole, NodeConnectivity );
2218   //   }
2219   //   con = formatConnectivity( connectivity, SMDSAbs_Ball );
2220   //   if ( !con.isEmpty() ) {
2221   //     QTreeWidgetItem* i = createItem( nconItem );
2222   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ));
2223   //     i->setText( 1, con );
2224   //     i->setData( 1, TypeRole, NodeConnectivity );
2225   //   }
2226   //   con = formatConnectivity( connectivity, SMDSAbs_Face );
2227   //   if ( !con.isEmpty() ) {
2228   //     QTreeWidgetItem* i = createItem( nconItem );
2229   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ));
2230   //     i->setText( 1, con );
2231   //     i->setData( 1, TypeRole, NodeConnectivity );
2232   //   }
2233   //   con = formatConnectivity( connectivity, SMDSAbs_Volume );
2234   //   if ( !con.isEmpty() ) {
2235   //     QTreeWidgetItem* i = createItem( nconItem );
2236   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ));
2237   //     i->setText( 1, con );
2238   //     i->setData( 1, TypeRole, NodeConnectivity );
2239   //   }
2240   // }
2241 }
2242 /*!
2243   \brief Internal clean-up (reset widget)
2244 */
2245 void SMESHGUI_TreeElemInfo::clearInternal()
2246 {
2247   myInfo->clear();
2248   myInfo->repaint();
2249 }
2250
2251 /*!
2252   \brief Create new item and add it to the tree.
2253   \param parent Parent tree widget item. Defaults to 0 (top-level item).
2254   \param options Item flags. Defaults to 0 (none).
2255   \return New tree widget item.
2256 */
2257 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int options )
2258 {
2259   QTreeWidgetItem* item = new QTreeWidgetItem( parent ? parent : myInfo->invisibleRootItem() );
2260   setTreeItemAttributes( item, options | Expanded | Editable );
2261
2262   if ( parent && parent->childCount() == 1 && itemDepth( parent ) == 1 )
2263   {
2264     QString resName = expandedResource( parent );
2265     parent->setExpanded( SMESHGUI::resourceMgr()->booleanValue("SMESH", resName, true ));
2266   }
2267   
2268   return item;
2269 }
2270
2271 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2272 {
2273   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2274   if ( widgets.isEmpty() ) return;
2275   QTreeWidgetItem* aTreeItem = widgets.first();
2276   int type = aTreeItem->data( 1, TypeRole ).toInt();
2277   if (( type == ElemConnectivity || type == NodeConnectivity ) &&
2278       ( !aTreeItem->text( 1 ).isEmpty() ))
2279   {
2280     QMenu menu;
2281     QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ));
2282     if ( menu.exec( e->globalPos() ) == a )
2283       emit( itemInfo( type, aTreeItem->text( 1 )) );
2284   }
2285 }
2286
2287 void SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int /*theColumn*/ )
2288 {
2289   if ( theItem ) {
2290     int type = theItem->data( 1, TypeRole ).toInt();
2291     emit( itemInfo( type, theItem->text( 1 )) );
2292   }
2293 }
2294
2295 void SMESHGUI_TreeElemInfo::saveExpanded( QTreeWidgetItem* theItem )
2296 {
2297   if ( theItem )
2298     SMESHGUI::resourceMgr()->setValue("SMESH", expandedResource( theItem ), theItem->isExpanded() );
2299 }
2300
2301 QString SMESHGUI_TreeElemInfo::expandedResource( QTreeWidgetItem* theItem )
2302 {
2303   return QString("Expanded_") + ( what()==ShowElements ? "E_" : "N_" ) + theItem->text(0);
2304 }
2305
2306 ////////////////////////////////////////////////////////////////////////////////
2307 /// \class InfoComputor
2308 /// \brief Mesh information computor.
2309 /// \internal
2310 ///
2311 /// The class is created for different computation operations. Currently it is
2312 /// used to compute size and number of underlying nodes for given group.
2313 ////////////////////////////////////////////////////////////////////////////////
2314
2315 /*!
2316   \brief Constructor.
2317   \param parent Parent object.
2318   \param proxy Object to compute information on (group).
2319   \param item Tree widget item, referenced by this computer.
2320   \param operation Value to compute.
2321   \internal
2322 */
2323 InfoComputor::InfoComputor( QObject* parent, const SMESH::SelectionProxy& proxy, int operation )
2324   : QObject( parent ), myProxy( proxy ), myOperation( operation )
2325 {
2326 }
2327
2328 /*!
2329   \brief Compute requested information.
2330   \internal
2331 */
2332 void InfoComputor::compute()
2333 {
2334   if ( myProxy )
2335   {
2336     SUIT_OverrideCursor wc;
2337     myProxy.load();
2338     switch ( myOperation )
2339     {
2340     case GrpSize:
2341       myProxy.size( true ); // force size computation
2342       emit computed();
2343       break;
2344     case GrpNbNodes:
2345       myProxy.nbNodes( true ); // force size computation
2346       emit computed();
2347       break;
2348     default:
2349       break;
2350     }
2351   }
2352 }
2353
2354 ////////////////////////////////////////////////////////////////////////////////
2355 /// \class SMESHGUI_AddInfo
2356 /// \brief Show additional information on selected object.
2357 ///
2358 /// Displays an additional information about selected object: mesh, sub-mesh
2359 /// or group.
2360 ///
2361 /// \todo Rewrite saveInfo() method to print all data, not currently shown only.
2362 ////////////////////////////////////////////////////////////////////////////////
2363
2364 /*!
2365   \brief Constructor.
2366   \param parent Parent widget. Defaults to 0.
2367 */
2368 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent ): SMESHGUI_Info( parent )
2369 {
2370   QVBoxLayout* l = new QVBoxLayout( this );
2371   l->setMargin( 0 );
2372   l->setSpacing( SPACING );
2373
2374   myTree = new QTreeWidget( this );
2375
2376   myTree->setColumnCount( 2 );
2377   myTree->header()->setStretchLastSection( true );
2378   myTree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2379   myTree->header()->hide();
2380
2381   l->addWidget( myTree );
2382 }
2383
2384 /*!
2385   \brief Destructor.
2386 */
2387 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2388 {
2389 }
2390
2391 /*!
2392   \brief Show information on given object.
2393   \param proxy Object to show information on (mesh, sub-mesh, group).
2394 */
2395 void SMESHGUI_AddInfo::showInfo( const SMESH::SelectionProxy& proxy )
2396 {
2397   // reset panel
2398   setProperty( "group_index", 0 );
2399   setProperty( "submesh_index",  0 );
2400   myComputors.clear();
2401   myTree->clear();
2402
2403   // then fill panel with data if object is not null
2404   if ( proxy )
2405   {
2406     myProxy = proxy;
2407
2408     // name
2409     QTreeWidgetItem* nameItem = createItem( 0, Bold | AllColumns );
2410     nameItem->setText( 0, tr( "NAME" ) );
2411     nameItem->setText( 1, proxy.name() );
2412
2413     // object info
2414     if ( proxy.type() == SMESH::SelectionProxy::Mesh )
2415       meshInfo( proxy, nameItem );
2416     else if ( proxy.type() == SMESH::SelectionProxy::Submesh )
2417       subMeshInfo( proxy, nameItem );
2418     else if ( proxy.type() >= SMESH::SelectionProxy::Group )
2419       groupInfo( proxy, nameItem );
2420   }
2421 }
2422
2423 /*!
2424   \brief Update information in panel.
2425 */
2426 void SMESHGUI_AddInfo::updateInfo()
2427 {
2428   showInfo( myProxy );
2429 }
2430
2431 /*!
2432   \brief Reset panel (clear all data).
2433 */
2434 void SMESHGUI_AddInfo::clear()
2435 {
2436   myTree->clear();
2437 }
2438
2439 /*!
2440   \brief Create new item and add it to the tree.
2441   \param parent Parent tree widget item. Defaults to 0 (top-level item).
2442   \param options Item flags. Defaults to 0 (none).
2443   \return New tree widget item.
2444 */
2445 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int options )
2446 {
2447   QTreeWidgetItem* item = parent ? new QTreeWidgetItem( parent ) : 
2448     new QTreeWidgetItem( myTree->invisibleRootItem() );
2449   setTreeItemAttributes( item, options | Expanded );
2450   return item;
2451 }
2452
2453 /*!
2454   \brief Show information on mesh.
2455   \param proxy Proxy object (mesh).
2456   \param parent Parent tree item.
2457 */
2458 void SMESHGUI_AddInfo::meshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2459 {
2460   if ( !proxy )
2461     return;
2462
2463   QString shapeName = proxy.shapeName();
2464   SMESH::MedInfo inf = proxy.medFileInfo();
2465
2466   // type
2467   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2468   typeItem->setText( 0, tr( "TYPE" ) );
2469   if ( !shapeName.isEmpty() )
2470   {
2471     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2472     // shape
2473     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2474     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2475     gobjItem->setText( 1, shapeName );
2476   }
2477   else if ( inf.isValid() )
2478   {
2479     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2480     // med file information
2481     QTreeWidgetItem* fileItem = createItem( parent, Bold );
2482     fileItem->setText( 0, tr( "FILE_NAME" ) );
2483     fileItem->setText( 1, inf.fileName() );
2484     QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2485     sizeItem->setText( 0, tr( "FILE_SIZE" ) );
2486     sizeItem->setText( 1, QString::number( inf.size() ) );
2487     QTreeWidgetItem* versionItem = createItem( parent, Bold );
2488     versionItem->setText( 0, tr( "FILE_VERSION" ) );
2489     versionItem->setText( 1, inf.version() != "0" ? inf.version() : tr( "VERSION_UNKNOWN" ) );
2490   }
2491   else
2492   {
2493     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2494   }
2495   
2496   // groups
2497   myGroups = proxy.groups();
2498   showGroups();
2499
2500   // sub-meshes
2501   mySubMeshes = proxy.submeshes();
2502   showSubMeshes();
2503 }
2504
2505 /*!
2506   \brief Show information on sub-mesh.
2507   \param proxy Proxy object (sub-mesh).
2508   \param parent Parent tree item.
2509 */
2510 void SMESHGUI_AddInfo::subMeshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2511 {
2512   if ( !proxy )
2513     return;
2514
2515   bool isShort = parent->parent() != 0;
2516
2517   if ( !isShort )
2518   {
2519     // parent mesh
2520     SMESH::SelectionProxy meshProxy = proxy.mesh();
2521     if ( meshProxy )
2522     {
2523       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2524       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2525       nameItem->setText( 1, meshProxy.name() );
2526     }
2527   }
2528   
2529   // shape
2530   QString shapeName = proxy.shapeName();
2531   if ( !shapeName.isEmpty() )
2532   {
2533     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2534     gobjItem->setText( 1, shapeName );
2535   }
2536 }
2537
2538 /*!
2539   \brief Show information on group.
2540   \param proxy Proxy object (group).
2541   \param parent Parent tree item.
2542 */
2543 void SMESHGUI_AddInfo::groupInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2544 {
2545   if ( !proxy )
2546     return;
2547
2548   bool isShort = parent->parent() != 0;
2549
2550   if ( !isShort )
2551   {
2552     // parent mesh
2553     SMESH::SelectionProxy meshProxy = proxy.mesh();
2554     if ( meshProxy )
2555     {
2556       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2557       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2558       nameItem->setText( 1, meshProxy.name() );
2559     }
2560   }
2561
2562   // type
2563   SMESH::SelectionProxy::Type type = proxy.type();
2564   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2565   typeItem->setText( 0, tr( "TYPE" ) );
2566   if ( type == SMESH::SelectionProxy::GroupStd )
2567   {
2568     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2569   }
2570   else if ( type == SMESH::SelectionProxy::GroupGeom )
2571   {
2572     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2573     // shape
2574     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2575     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2576     gobjItem->setText( 1, proxy.shapeName() );
2577   }
2578   else if ( type == SMESH::SelectionProxy::GroupFilter )
2579   {
2580     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2581   }
2582
2583   // element type
2584   int etype = proxy.groupElementType();
2585   if ( !isShort )
2586   {
2587     QString typeName = tr( "UNKNOWN" );
2588     switch( etype )
2589     {
2590     case SMESH::NODE:
2591       typeName = tr( "NODE" );
2592       break;
2593     case SMESH::EDGE:
2594       typeName = tr( "EDGE" );
2595       break;
2596     case SMESH::FACE:
2597       typeName = tr( "FACE" );
2598       break;
2599     case SMESH::VOLUME:
2600       typeName = tr( "VOLUME" );
2601       break;
2602     case SMESH::ELEM0D:
2603       typeName = tr( "0DELEM" );
2604       break;
2605     case SMESH::BALL:
2606       typeName = tr( "BALL" );
2607       break;
2608     default:
2609       break;
2610     }
2611     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2612     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2613     etypeItem->setText( 1, typeName );
2614   }
2615
2616   // size
2617   // note: size is not computed for group on filter for performance reasons, see IPAL52831
2618   bool meshLoaded = proxy.isMeshLoaded();
2619   int size = proxy.size();
2620
2621   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2622   sizeItem->setText( 0, tr( "SIZE" ) );
2623   if ( size >= 0 )
2624   {
2625     sizeItem->setText( 1, QString::number( size ) );
2626   }
2627   else
2628   {
2629     QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
2630     myTree->setItemWidget( sizeItem, 1, btn );
2631     InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpSize );
2632     connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2633     connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
2634     myComputors.append( comp );
2635   }
2636
2637   // color
2638   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2639   colorItem->setText( 0, tr( "COLOR" ) );
2640   colorItem->setBackground( 1, proxy.color() );
2641
2642   // nb of underlying nodes
2643   if ( etype != SMESH::NODE )
2644   {
2645     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2646     nodesItem->setText( 0, tr( "NB_NODES" ) );
2647
2648     int nbNodes = proxy.nbNodes();
2649     if ( nbNodes >= 0 )
2650     {
2651       nodesItem->setText( 1, QString::number( nbNodes ) );
2652     }
2653     else
2654     {
2655       QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
2656       myTree->setItemWidget( nodesItem, 1, btn );
2657       InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpNbNodes ); 
2658       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2659       connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
2660       myComputors.append( comp );
2661     }
2662   }
2663 }
2664
2665 /*!
2666   \brief Update information on child groups.
2667 */
2668 void SMESHGUI_AddInfo::showGroups()
2669 {
2670   // remove all computors
2671   myComputors.clear();
2672
2673   // tree root should be the first top level item
2674   QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
2675   if ( !parent )
2676     return;
2677
2678   int idx = property( "group_index" ).toInt();
2679
2680   // find sub-meshes top-level container item
2681   QTreeWidgetItem* itemGroups = 0;
2682   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ )
2683   {
2684     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GroupsId )
2685     {
2686       itemGroups = parent->child( i );
2687       // update controls
2688       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemGroups, 1 ) );
2689       if ( extra )
2690         extra->updateControls( myGroups.count(), idx );
2691       // clear: remove all group items
2692       while ( itemGroups->childCount() )
2693         delete itemGroups->child( 0 );
2694     }
2695   }
2696
2697   QMap<int, QTreeWidgetItem*> grpItems;
2698   for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), (int)myGroups.count() ); i++ )
2699   {
2700     SMESH::SelectionProxy grp = myGroups[i];
2701     if ( !grp )
2702       continue;
2703
2704     int grpType = grp.groupElementType();
2705
2706     // create top-level groups container item if it does not exist
2707     if ( !itemGroups )
2708     {
2709       itemGroups = createItem( parent, Bold | AllColumns );
2710       itemGroups->setText( 0, tr( "GROUPS" ) );
2711       itemGroups->setData( 0, Qt::UserRole, GroupsId );
2712
2713       // if necessary, create extra widget to show information by chunks
2714       if ( myGroups.count() > blockSize() )
2715       {
2716         ExtraWidget* extra = new ExtraWidget( this, true );
2717         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2718         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2719         myTree->setItemWidget( itemGroups, 1, extra );
2720         extra->updateControls( myGroups.count(), idx );
2721       }
2722     }
2723
2724     // create container item corresponding to particular element type
2725     if ( !grpItems.contains( grpType ) )
2726     {
2727       grpItems[ grpType ] = createItem( itemGroups, Bold | AllColumns );
2728       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2729       itemGroups->insertChild( grpType-1, grpItems[ grpType ] ); // -1 needed since 0 corresponds to SMESH::ALL
2730     }
2731   
2732     // name
2733     QTreeWidgetItem* nameItem = createItem( grpItems[ grpType ] );
2734     nameItem->setText( 0, grp.name().trimmed() ); // trim name
2735
2736     // group info
2737     groupInfo( grp, nameItem );
2738   }
2739 }
2740
2741 /*!
2742   \brief Update information on child sub-meshes.
2743 */
2744 void SMESHGUI_AddInfo::showSubMeshes()
2745 {
2746   // tree root should be the first top level item
2747   QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
2748   if ( !parent )
2749     return;
2750
2751   int idx = property( "submesh_index" ).toInt();
2752
2753   // find sub-meshes top-level container item
2754   QTreeWidgetItem* itemSubMeshes = 0;
2755   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ )
2756   {
2757     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SubMeshesId )
2758     {
2759       itemSubMeshes = parent->child( i );
2760       // update controls
2761       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemSubMeshes, 1 ) );
2762       if ( extra )
2763         extra->updateControls( mySubMeshes.count(), idx );
2764       // clear: remove all sub-mesh items
2765       while ( itemSubMeshes->childCount() )
2766         delete itemSubMeshes->child( 0 );
2767     }
2768   }
2769
2770   QMap<int, QTreeWidgetItem*> smItems;
2771   for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), mySubMeshes.count() ); i++ )
2772   {
2773     SMESH::SelectionProxy sm = mySubMeshes[i];
2774     if ( !sm )
2775       continue;
2776     
2777     int smType = sm.shapeType();
2778     if ( smType < 0 )
2779       continue;
2780     else if ( smType == GEOM::COMPSOLID )
2781       smType = GEOM::COMPOUND;
2782
2783     // create top-level sub-meshes container item if it does not exist
2784     if ( !itemSubMeshes )
2785     {
2786       itemSubMeshes = createItem( parent, Bold | AllColumns );
2787       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2788       itemSubMeshes->setData( 0, Qt::UserRole, SubMeshesId );
2789
2790       // if necessary, create extra widget to show information by chunks
2791       if ( mySubMeshes.count() > blockSize() )
2792       {
2793         ExtraWidget* extra = new ExtraWidget( this, true );
2794         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2795         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2796         myTree->setItemWidget( itemSubMeshes, 1, extra );
2797         extra->updateControls( mySubMeshes.count(), idx );
2798       }
2799     }
2800
2801     // create container item corresponding to particular shape type
2802     if ( !smItems.contains( smType ) )
2803     {
2804       smItems[ smType ] = createItem( itemSubMeshes, Bold | AllColumns );
2805       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2806       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2807     }
2808     
2809     // name
2810     QTreeWidgetItem* nameItem = createItem( smItems[ smType ] );
2811     nameItem->setText( 0, sm.name().trimmed() ); // trim name
2812     
2813     // submesh info
2814     subMeshInfo( sm, nameItem );
2815   }
2816 }
2817
2818 /*!
2819   \brief Show previous chunk of information on child groups.
2820 */
2821 void SMESHGUI_AddInfo::showPreviousGroups()
2822 {
2823   int idx = property( "group_index" ).toInt();
2824   setProperty( "group_index", idx-1 );
2825   showGroups();
2826 }
2827
2828 /*!
2829   \brief Show next chunk of information on child groups.
2830 */
2831 void SMESHGUI_AddInfo::showNextGroups()
2832 {
2833   int idx = property( "group_index" ).toInt();
2834   setProperty( "group_index", idx+1 );
2835   showGroups();
2836 }
2837
2838 /*!
2839   \brief Show previous chunk of information on child sub-meshes.
2840 */
2841 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2842 {
2843   int idx = property( "submesh_index" ).toInt();
2844   setProperty( "submesh_index", idx-1 );
2845   showSubMeshes();
2846 }
2847
2848 /*!
2849   \brief Show next chunk of information on child sub-meshes.
2850 */
2851 void SMESHGUI_AddInfo::showNextSubMeshes()
2852 {
2853   int idx = property( "submesh_index" ).toInt();
2854   setProperty( "submesh_index", idx+1 );
2855   showSubMeshes();
2856 }
2857
2858 /*!
2859   \brief Write information from panel to output stream.
2860   \param out Text stream output.
2861 */
2862 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2863 {
2864   // title
2865   QString title = tr( "ADDITIONAL_INFO" );
2866   out << ruler( title.size() ) << endl;
2867   out << title << endl;
2868   out << ruler( title.size() ) << endl;
2869   out << endl;
2870
2871   // info
2872   QTreeWidgetItemIterator it( myTree );
2873   while ( *it )
2874   {
2875     if ( !( ( *it )->text(0) ).isEmpty() )
2876     {
2877       out << indent( itemDepth( *it ) ) << ( *it )->text(0);
2878       if ( ( *it )->text(0)  == tr( "COLOR" ) )
2879         out << ":" << spacing() << ( ( ( *it )->background(1) ).color() ).name();
2880       else if ( !( ( *it )->text(1) ).isEmpty() )
2881         out << ":" << spacing() << ( *it )->text(1);
2882       out << endl;
2883     }
2884     ++it;
2885   }
2886   out << endl;
2887 }
2888
2889 ////////////////////////////////////////////////////////////////////////////////
2890 /// \class GroupCombo
2891 /// \brief Customized combo box to manage list of mesh groups.
2892 /// \internal
2893 ////////////////////////////////////////////////////////////////////////////////
2894
2895 class GroupCombo: public QComboBox
2896 {
2897   class Item: public QStandardItem
2898   {
2899   public:
2900     SMESH::SelectionProxy myGroup;
2901     Item( const SMESH::SelectionProxy& group )
2902     {
2903       myGroup = group;
2904       setText( myGroup.name() );
2905     }
2906     SMESH::SelectionProxy group()
2907     {
2908       return myGroup;
2909     }
2910   };
2911
2912   SMESH::SelectionProxy myProxy;
2913
2914 public:
2915   GroupCombo( QWidget* );
2916   void setSource( const SMESH::SelectionProxy& );
2917   SMESH::SelectionProxy currentGroup() const;
2918 };
2919
2920 /*!
2921   \brief Constructor.
2922   \param parent Parent widget.
2923   \internal
2924 */
2925 GroupCombo::GroupCombo( QWidget* parent ): QComboBox( parent )
2926 {
2927   setModel( new QStandardItemModel( this ) );
2928 }
2929
2930 /*!
2931   \brief Set mesh source.
2932   \param obj Mesh source.
2933   \internal
2934 */
2935 void GroupCombo::setSource( const SMESH::SelectionProxy& proxy )
2936 {
2937   if ( myProxy == proxy )
2938     return;
2939
2940   myProxy = proxy;
2941
2942   bool blocked = blockSignals( true );
2943   QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
2944   m->clear();
2945
2946   if ( myProxy )
2947   {
2948     if ( myProxy.type() == SMESH::SelectionProxy::Mesh )
2949     {
2950       QList<SMESH::SelectionProxy> groups = myProxy.groups();
2951       for ( int i = 0; i < groups.count(); ++i )
2952       {
2953         if ( groups[i] )
2954         {
2955           QString name = groups[i].name();
2956           if ( !name.isEmpty() )
2957             m->appendRow( new Item( groups[i] ) );
2958         }
2959       }
2960       setCurrentIndex( -1 ); // for performance reasons
2961     }
2962     else if ( myProxy.type() >= SMESH::SelectionProxy::Group )
2963     {
2964       m->appendRow( new Item( myProxy ) );
2965       setCurrentIndex( 0 );
2966     }
2967   }
2968
2969   blockSignals( blocked );
2970 }
2971
2972 /*!
2973   \brief Get currently selected group.
2974   \return Selected group.
2975   \internal
2976 */
2977 SMESH::SelectionProxy GroupCombo::currentGroup() const
2978 {
2979   SMESH::SelectionProxy group;
2980   QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
2981   if ( currentIndex() >= 0 )
2982     group = dynamic_cast<Item*>( m->item( currentIndex() ) )->group();
2983   return group;
2984 }
2985
2986 ////////////////////////////////////////////////////////////////////////////////
2987 /// \class SMESHGUI_MeshInfoDlg
2988 /// \brief Mesh information dialog box
2989 ///
2990 /// \todo Move all business logic for element info to SMESHGUI_ElemInfo class.
2991 /// \todo Add selection button to reactivate selection on move from other dlg.
2992 ////////////////////////////////////////////////////////////////////////////////
2993
2994 /*!
2995   \brief Constructor
2996   \param parent Parent widget.
2997   \param page Dialog page to show at start-up. Defaults to \c BaseInfo.
2998 */
2999 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
3000   : QDialog( parent )
3001 {
3002   setModal( false );
3003   setAttribute( Qt::WA_DeleteOnClose, true );
3004   setWindowTitle( tr( "MESH_INFO" ) );
3005   setSizeGripEnabled( true );
3006
3007   myTabWidget = new QTabWidget( this );
3008
3009   // base info
3010
3011   myBaseInfo = new SMESHGUI_BaseInfo( myTabWidget );
3012   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
3013
3014   // elem info 
3015
3016   QWidget* w = new QWidget( myTabWidget );
3017
3018   myMode = new QButtonGroup( this );
3019   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
3020   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
3021   myMode->addButton( new QRadioButton( tr( "GROUP_MODE" ), w ), GroupMode );
3022   myMode->button( NodeMode )->setChecked( true );
3023   myID = new QLineEdit( w );
3024   myID->setValidator( new SMESHGUI_IdValidator( this ) );
3025   myGroups = new GroupCombo( w );
3026   QStackedWidget* stack = new QStackedWidget( w );
3027   stack->addWidget( myID );
3028   stack->addWidget( myGroups );
3029   myIDPreviewCheck = new QCheckBox( tr( "SHOW_IDS" ), w );
3030   myIDPreview = new SMESHGUI_IdPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ) );
3031
3032   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
3033   mode = qMin( 1, qMax( 0, mode ) );
3034
3035   if ( mode == 0 )
3036     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
3037   else
3038     myElemInfo = new SMESHGUI_TreeElemInfo( w );
3039   stack->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
3040
3041   QGridLayout* elemLayout = new QGridLayout( w );
3042   elemLayout->setMargin( MARGIN );
3043   elemLayout->setSpacing( SPACING );
3044   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
3045   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
3046   elemLayout->addWidget( myMode->button( GroupMode ), 0, 2 );
3047   elemLayout->addWidget( stack, 0, 3 );
3048   elemLayout->addWidget( myIDPreviewCheck, 1, 0, 1, 4 );
3049   elemLayout->addWidget( myElemInfo, 2, 0, 1, 4 );
3050
3051   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
3052
3053   // additional info
3054
3055   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
3056   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
3057
3058   // controls info
3059
3060   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
3061   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
3062
3063   // buttons
3064
3065   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3066   okBtn->setAutoDefault( true );
3067   okBtn->setDefault( true );
3068   okBtn->setFocus();
3069   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3070   dumpBtn->setAutoDefault( true );
3071   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3072   helpBtn->setAutoDefault( true );
3073
3074   QHBoxLayout* btnLayout = new QHBoxLayout;
3075   btnLayout->setSpacing( SPACING );
3076   btnLayout->setMargin( 0 );
3077
3078   btnLayout->addWidget( okBtn );
3079   btnLayout->addWidget( dumpBtn );
3080   btnLayout->addStretch( 10 );
3081   btnLayout->addWidget( helpBtn );
3082
3083   // arrange widgets
3084
3085   QVBoxLayout* l = new QVBoxLayout ( this );
3086   l->setMargin( MARGIN );
3087   l->setSpacing( SPACING );
3088   l->addWidget( myTabWidget );
3089   l->addLayout( btnLayout );
3090
3091   // set initial page
3092
3093   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
3094
3095   // set-up connections
3096
3097   connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
3098   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3099   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3100   connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) );
3101   connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) );
3102   connect( myGroups, SIGNAL( currentIndexChanged( int ) ), this, SLOT( modeChanged() ) );
3103   connect( myID, SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
3104   connect( myIDPreviewCheck, SIGNAL( toggled( bool ) ), this, SLOT( idPreviewChange( bool ) ) );
3105   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3106   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) );
3107   connect( myElemInfo, SIGNAL( itemInfo( int, QString ) ), this, SLOT( showItemInfo( int, QString ) ) );
3108   connect( this, SIGNAL( switchMode( int ) ), stack, SLOT( setCurrentIndex( int ) ) );
3109
3110   // initialize
3111
3112   myIDPreviewCheck->setChecked( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "id_preview_resource", false ) );
3113   updateSelection();
3114 }
3115
3116 /*!
3117   \brief Destructor.
3118 */
3119 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
3120 {
3121   delete myIDPreview;
3122 }
3123
3124 /*!
3125   \brief Show mesh information on given object.
3126   \param io Interactive object.
3127 */
3128 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io )
3129 {
3130   if ( !io.IsNull() )
3131     showInfo( SMESH::SelectionProxy( io ) );
3132 }
3133
3134 /*!
3135   \brief Show mesh information on given object.
3136   \param proxy Selection proxy.
3137 */
3138 void SMESHGUI_MeshInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
3139 {
3140   SUIT_OverrideCursor wc;
3141
3142   if ( !proxy )
3143     return;
3144
3145   myProxy = proxy;
3146
3147   SMESH::SMESH_IDSource_var obj = myProxy.object();
3148
3149   // "Base info" tab
3150   myBaseInfo->showInfo( proxy );
3151
3152   // "Additional info" tab
3153   myAddInfo->showInfo( proxy );
3154
3155   // "Quality info" tab
3156   // Note: for performance reasons we update it only if it is currently active
3157   if ( myTabWidget->currentIndex() == CtrlInfo )
3158     myCtrlInfo->showInfo( proxy );
3159
3160   // "Element info" tab
3161   myGroups->setSource( proxy );
3162   if ( myMode->checkedId() == GroupMode ) {
3163     SMESH::SelectionProxy group = myGroups->currentGroup();
3164     if ( group )
3165       myElemInfo->showInfo( group );
3166     else
3167       myElemInfo->clear();
3168   }
3169   else {
3170     SVTK_Selector* selector = SMESH::GetSelector();
3171     QString ID;
3172     int nb = 0;
3173     if ( myProxy.actor() && selector ) { //todo: actor()?
3174       nb = myMode->checkedId() == NodeMode ?
3175         SMESH::GetNameOfSelectedElements( selector, myProxy.io(), ID ) :
3176         SMESH::GetNameOfSelectedNodes( selector, myProxy.io(), ID );
3177     }
3178     if ( nb > 0 ) {
3179       myID->setText( ID.trimmed() );
3180       QSet<uint> ids;
3181       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
3182       foreach ( ID, idTxt )
3183         ids << ID.trimmed().toUInt();
3184       myElemInfo->showInfo( proxy, ids, myMode->checkedId() == ElemMode );
3185     }
3186     else {
3187       myID->clear();
3188       myElemInfo->clear();
3189     }
3190   }
3191 }
3192
3193 /*!
3194   \brief Update information.
3195 */
3196 void SMESHGUI_MeshInfoDlg::updateInfo()
3197 {
3198   SALOME_ListIO selected;
3199   SMESHGUI::selectionMgr()->selectedObjects( selected );
3200
3201   if ( selected.Extent() == 1 )
3202     showInfo( selected.First() );
3203   else
3204     showInfo( myProxy );
3205 }
3206
3207 /*!
3208   \brief Clean-up on dialog closing.
3209 */
3210 void SMESHGUI_MeshInfoDlg::reject()
3211 {
3212   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3213   selMgr->clearFilters();
3214   SMESH::SetPointRepresentation( false );
3215   if ( SVTK_ViewWindow* viewWindow = SMESH::GetViewWindow() )
3216     viewWindow->SetSelectionMode( ActorSelection );
3217   QDialog::reject();
3218   myIDPreview->SetPointsLabeled( false );
3219 }
3220
3221 /*!
3222   \brief Process keyboard event.
3223   \param e Key press event.
3224 */
3225 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
3226 {
3227   QDialog::keyPressEvent( e );
3228   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
3229     e->accept();
3230     help();
3231   }
3232 }
3233
3234 /*!
3235   \brief Set-up selection mode for currently selected page.
3236 */
3237 void SMESHGUI_MeshInfoDlg::updateSelection()
3238 {
3239   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3240
3241   disconnect( selMgr, 0, this, 0 );
3242   selMgr->clearFilters();
3243
3244   int selMode = ActorSelection;
3245   if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == NodeMode )
3246     selMode = NodeSelection;
3247   else if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == ElemMode )
3248     selMode = CellSelection;
3249   SMESH::SetPointRepresentation( selMode == NodeSelection );
3250   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3251     aViewWindow->SetSelectionMode( selMode );
3252
3253   SMESH::SelectionProxy previous = myProxy;
3254   QString ids = myID->text().trimmed();
3255   myID->clear();
3256   
3257   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3258   updateInfo();
3259   
3260   if ( myProxy && myProxy == previous && !ids.isEmpty() ) {
3261     myID->setText( ids );
3262     idChanged();
3263   }
3264 }
3265
3266 /*!
3267   \brief Show documentation on selected dialog page.
3268 */
3269 void SMESHGUI_MeshInfoDlg::help()
3270 {
3271   QString helpPage = "mesh_infos.html";
3272   switch ( myTabWidget->currentIndex() )
3273   {
3274   case BaseInfo:
3275     helpPage += "#advanced-mesh-infos-anchor";
3276     break;
3277   case ElemInfo:
3278     helpPage += "#mesh-element-info-anchor";
3279     break;
3280   case AddInfo:
3281     helpPage += "#mesh-addition-info-anchor";
3282     break;
3283   case CtrlInfo:
3284     helpPage += "#mesh-quality-info-anchor";
3285     break;
3286   default:
3287     break;
3288   }
3289   SMESH::ShowHelpFile( helpPage );
3290 }
3291
3292 /*!
3293   \brief Deactivate dialog box.
3294 */
3295 void SMESHGUI_MeshInfoDlg::deactivate()
3296 {
3297   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3298 }
3299
3300 /*!
3301   \brief Called when users switches between node / element modes.
3302 */
3303 void SMESHGUI_MeshInfoDlg::modeChanged()
3304 {
3305   emit( switchMode( myMode->checkedId() == GroupMode ? 1 : 0 ) );
3306   myID->clear();
3307   updateSelection();
3308 }
3309
3310 /*!
3311   \brief Called when users prints mesh element ID in the corresponding field.
3312 */
3313 void SMESHGUI_MeshInfoDlg::idChanged()
3314 {
3315   myIDPreview->SetPointsLabeled( false );
3316
3317   if ( myProxy ) {
3318     TColStd_MapOfInteger ID;
3319     QSet<uint>           ids;
3320     std::vector<int>     idVec;
3321     std::list< gp_XYZ >  aGrCentersXYZ;
3322     SMESH::XYZ           xyz;
3323     const bool           isElem = ( myMode->checkedId() == ElemMode );
3324     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3325     foreach ( QString tid, idTxt ) {
3326       long id = tid.toUInt();
3327       if ( isElem ? myProxy.hasElement( id ) : myProxy.hasNode( id ))
3328       {
3329         ID.Add( id );
3330         ids << id;
3331         if ( isElem && myProxy.actor() && myProxy.elementGravityCenter( id, xyz ))
3332         {
3333           idVec.push_back( id );
3334           aGrCentersXYZ.push_back( xyz );
3335         }
3336       }
3337     }
3338     SVTK_Selector* selector = SMESH::GetSelector();
3339     if ( myProxy.actor() && selector ) {
3340       Handle(SALOME_InteractiveObject) IO = myProxy.actor()->getIO();
3341       selector->AddOrRemoveIndex( IO, ID, false );
3342       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3343       {
3344         if ( myMode->checkedId() == NodeMode )
3345           myIDPreview->SetPointsData( myProxy.actor()->GetObject()->GetMesh(), ID );
3346         else
3347           myIDPreview->SetElemsData( idVec, aGrCentersXYZ );
3348
3349         bool showIDs = ( !ID.IsEmpty() &&
3350                          myIDPreviewCheck->isChecked() &&
3351                          myTabWidget->currentIndex() == ElemInfo );
3352         myIDPreview->SetPointsLabeled( showIDs, myProxy.actor()->GetVisibility() );
3353
3354         aViewWindow->highlight( IO, true, true );
3355         aViewWindow->Repaint();
3356       }
3357     }
3358     myElemInfo->showInfo( myProxy, ids, isElem );
3359   }
3360 }
3361
3362 /*!
3363  * \brief Show IDs clicked
3364  */
3365 void SMESHGUI_MeshInfoDlg::idPreviewChange( bool isOn )
3366 {
3367   myIDPreview->SetPointsLabeled( isOn && !myID->text().simplified().isEmpty() );
3368   SMESHGUI::resourceMgr()->setValue("SMESH", "id_preview_resource", isOn );
3369   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3370     aViewWindow->Repaint();
3371 }
3372
3373 void SMESHGUI_MeshInfoDlg::showItemInfo( int type, const QString& ids )
3374 {
3375   if ( !ids.isEmpty() && ( type == NodeConnectivity || type == ElemConnectivity )) {
3376     myMode->button( type - NodeConnectivity )->click();
3377     myID->setText( ids );
3378   }
3379 }
3380
3381 /*!
3382   \brief Dump information to file.
3383 */
3384 void SMESHGUI_MeshInfoDlg::dump()
3385 {
3386   DumpFileDlg fd( this );
3387   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3388   fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) );
3389   fd.setChecked( BaseInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_base", true ) );
3390   fd.setChecked( ElemInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_elem", true ) );
3391   fd.setChecked( AddInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_add", true ) );
3392   fd.setChecked( CtrlInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_ctrl", true ) );
3393   if ( fd.exec() == QDialog::Accepted )
3394   {
3395     QString fileName = fd.selectedFile();
3396     if ( !fileName.isEmpty() ) {
3397       QFile file( fileName );
3398       if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
3399         return;
3400
3401       QTextStream out( &file );
3402       if ( fd.isChecked( BaseInfo ) ) myBaseInfo->saveInfo( out );
3403       if ( fd.isChecked( ElemInfo ) ) myElemInfo->saveInfo( out );
3404       if ( fd.isChecked( AddInfo ) )  myAddInfo->saveInfo( out );
3405       if ( fd.isChecked( CtrlInfo ) )
3406       {
3407         myCtrlInfo->showInfo( myProxy ); // it saves what is shown only
3408         myCtrlInfo->saveInfo( out );
3409       }
3410     }
3411   }
3412 }
3413
3414 ////////////////////////////////////////////////////////////////////////////////
3415 /// \class SMESHGUI_CtrlInfo
3416 /// \brief Show quality statistics information on selected object.
3417 ///
3418 /// Displays quality controls statistics about selected object: mesh, sub-mesh,
3419 /// group or arbitrary ID source.
3420 ////////////////////////////////////////////////////////////////////////////////
3421
3422 /*!
3423   \brief Constructor.
3424   \param parent Parent widget. Defaults to 0.
3425 */
3426 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent ): SMESHGUI_Info( parent )
3427 {
3428   QGridLayout* l = new QGridLayout( this );
3429   l->setMargin( MARGIN );
3430   l->setSpacing( SPACING );
3431
3432   QIcon aComputeIcon( SUIT_Session::session()->resourceMgr()->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3433   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3434
3435   // name
3436   QLabel* aNameLab = createLabel( tr( "NAME_LAB" ), this, Bold );
3437   QLabel* aName = createField( this, "ctrlName" );
3438   aName->setMinimumWidth( 150 );
3439   myWidgets << aName;
3440
3441   // nodes info
3442   QLabel* aNodesLab = createLabel( tr( "NODES_INFO" ), this, Bold );
3443   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3444   QLabel* aNodesFree = createField( this, "ctrlNodesFree" );
3445   myWidgets << aNodesFree;
3446   myPredicates << aFilterMgr->CreateFreeNodes();
3447   //
3448   QLabel* aNodesNbConnLab = new QLabel( tr( "MAX_NODE_CONNECTIVITY" ), this );
3449   QLabel* aNodesNbConn = createField( this, "ctrlNodesCnty" );
3450   myWidgets << aNodesNbConn;
3451   myNodeConnFunctor = aFilterMgr->CreateNodeConnectivityNumber();
3452   //
3453   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3454   QLabel* aNodesDouble = createField( this, "ctrlNodesDouble" );
3455   myWidgets << aNodesDouble;
3456   myPredicates << aFilterMgr->CreateEqualNodes();
3457   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3458   myToleranceWidget = new SMESHGUI_SpinBox( this );
3459   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3460   myToleranceWidget->setAcceptNames( false );
3461   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3462
3463   // edges info
3464   QLabel* anEdgesLab = createLabel( tr( "EDGES_INFO" ), this, Bold );
3465   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3466   QLabel* anEdgesDouble = createField( this, "ctrlEdgesDouble" );
3467   myWidgets << anEdgesDouble;
3468   myPredicates << aFilterMgr->CreateEqualEdges();
3469
3470   // faces info
3471   QLabel* aFacesLab = createLabel( tr( "FACES_INFO" ), this, Bold );
3472   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3473   QLabel* aFacesDouble = createField( this, "ctrlFacesDouble" );
3474   myWidgets << aFacesDouble;
3475   myPredicates << aFilterMgr->CreateEqualFaces();
3476   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3477   QLabel* aFacesOver = createField( this, "ctrlFacesOver" );
3478   myWidgets << aFacesOver;
3479   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3480   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3481   myPlot = createPlot( this );
3482   myAspectRatio = aFilterMgr->CreateAspectRatio();
3483  
3484   // volumes info
3485   QLabel* aVolumesLab = createLabel( tr( "VOLUMES_INFO" ), this, Bold );
3486   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3487   QLabel* aVolumesDouble = createField( this, "ctrlVolumesDouble" );
3488   myWidgets << aVolumesDouble;
3489   myPredicates << aFilterMgr->CreateEqualVolumes();
3490   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3491   QLabel* aVolumesOver = createField( this, "ctrlVolumesOver" );
3492   myWidgets << aVolumesOver;
3493   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3494   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3495   myPlot3D = createPlot( this );
3496   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3497
3498   QToolButton* aFreeNodesBtn = new QToolButton( this );
3499   aFreeNodesBtn->setIcon(aComputeIcon);
3500   myButtons << aFreeNodesBtn;       //0
3501
3502   QToolButton* aNodesNbConnBtn = new QToolButton( this );
3503   aNodesNbConnBtn->setIcon(aComputeIcon);
3504   myButtons << aNodesNbConnBtn;     //1
3505
3506   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3507   aDoubleNodesBtn->setIcon(aComputeIcon);
3508   myButtons << aDoubleNodesBtn;     //2
3509
3510   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3511   aDoubleEdgesBtn->setIcon(aComputeIcon);
3512   myButtons << aDoubleEdgesBtn;     //3
3513
3514   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3515   aDoubleFacesBtn->setIcon(aComputeIcon);
3516   myButtons << aDoubleFacesBtn;     //4
3517
3518   QToolButton* aOverContFacesBtn = new QToolButton( this );
3519   aOverContFacesBtn->setIcon(aComputeIcon);
3520   myButtons << aOverContFacesBtn;   //5
3521
3522   QToolButton* aComputeFaceBtn = new QToolButton( this );
3523   aComputeFaceBtn->setIcon(aComputeIcon);
3524   myButtons << aComputeFaceBtn;     //6
3525
3526   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3527   aDoubleVolumesBtn->setIcon(aComputeIcon);
3528   myButtons << aDoubleVolumesBtn;   //7
3529
3530   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3531   aOverContVolumesBtn->setIcon(aComputeIcon);
3532   myButtons << aOverContVolumesBtn; //8
3533
3534   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3535   aComputeVolumeBtn->setIcon(aComputeIcon);
3536   myButtons << aComputeVolumeBtn;   //9
3537
3538   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3539   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3540   connect( aFreeNodesBtn,     SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3541   connect( aNodesNbConnBtn,   SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ) );
3542   connect( aDoubleNodesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3543   connect( aDoubleEdgesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3544   connect( aDoubleFacesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3545   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3546   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3547   connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3548   connect( myToleranceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( setTolerance( double ) ) );
3549
3550   l->addWidget( aNameLab,           0, 0 );       //0
3551   l->addWidget( aName,              0, 1, 1, 2 ); //1
3552   l->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3553   l->addWidget( aNodesFreeLab,      2, 0 );       //3
3554   l->addWidget( aNodesFree,         2, 1 );       //4
3555   l->addWidget( aFreeNodesBtn,      2, 2 );       //5
3556   l->addWidget( aNodesNbConnLab,    3, 0 );       //6
3557   l->addWidget( aNodesNbConn,       3, 1 );       //7
3558   l->addWidget( aNodesNbConnBtn,    3, 2 );       //8
3559   l->addWidget( aNodesDoubleLab,    4, 0 );       //9
3560   l->addWidget( aNodesDouble,       4, 1 );       //10
3561   l->addWidget( aDoubleNodesBtn,    4, 2 );       //11
3562   l->addWidget( aToleranceLab,      5, 0 );       //12
3563   l->addWidget( myToleranceWidget,  5, 1 );       //13
3564   l->addWidget( anEdgesLab,         6, 0, 1, 3 ); //14
3565   l->addWidget( anEdgesDoubleLab,   7, 0 );       //15
3566   l->addWidget( anEdgesDouble,      7, 1 );       //16
3567   l->addWidget( aDoubleEdgesBtn,    7, 2 );       //17
3568   l->addWidget( aFacesLab,          8, 0, 1, 3 ); //18
3569   l->addWidget( aFacesDoubleLab,    9, 0 );       //19
3570   l->addWidget( aFacesDouble,       9, 1 );       //20
3571   l->addWidget( aDoubleFacesBtn,    9, 2 );       //21
3572   l->addWidget( aFacesOverLab,      10, 0 );      //22
3573   l->addWidget( aFacesOver,         10, 1 );      //23
3574   l->addWidget( aOverContFacesBtn,  10, 2 );      //24
3575   l->addWidget( anAspectRatioLab,   11, 0 );      //25
3576   l->addWidget( aComputeFaceBtn,    11, 2 );      //26
3577   l->addWidget( myPlot,             12, 0, 1, 3 );//27
3578   l->addWidget( aVolumesLab,        13, 0, 1, 3 );//28
3579   l->addWidget( aVolumesDoubleLab,  14, 0 );      //29
3580   l->addWidget( aVolumesDouble,     14, 1 );      //30
3581   l->addWidget( aDoubleVolumesBtn,  14, 2 );      //31
3582   l->addWidget( aVolumesOverLab,    15, 0 );      //32
3583   l->addWidget( aVolumesOver,       15, 1 );      //33
3584   l->addWidget( aOverContVolumesBtn,15, 2 );      //34
3585   l->addWidget( anAspectRatio3DLab, 16, 0 );      //35
3586   l->addWidget( aComputeVolumeBtn,  16, 2 );      //36
3587   l->addWidget( myPlot3D,           17, 0, 1, 3 );//37
3588  
3589   l->setColumnStretch(  0,  0 );
3590   l->setColumnStretch(  1,  5 );
3591   l->setRowStretch   ( 12,  5 );
3592   l->setRowStretch   ( 17,  5 );
3593   l->setRowStretch   ( 18,  1 );
3594
3595   clearInternal();
3596 }
3597
3598 /*!
3599   \brief Destructor.
3600 */
3601 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3602 {
3603 }
3604
3605 /*!
3606   \brief Create plot widget.
3607   \param parent Parent widget.
3608   \return New plot widget.
3609 */
3610 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3611 {
3612   QwtPlot* aPlot = new QwtPlot( parent );
3613   aPlot->setMinimumSize( 100, 100 );
3614   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3615   xFont.setPointSize( 5 );
3616   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3617   yFont.setPointSize( 5 );
3618   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3619   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3620   aPlot->replot();
3621   return aPlot;
3622 }
3623
3624 /*!
3625   \brief Show information on given object.
3626   \param proxy Object to show information on (mesh, sub-mesh, group, ID source).
3627 */
3628 void SMESHGUI_CtrlInfo::showInfo( const SMESH::SelectionProxy& proxy )
3629 {
3630   clearInternal();
3631
3632   if ( !proxy )
3633     return;
3634
3635   myProxy = proxy;
3636   SMESH::SMESH_IDSource_var obj = proxy.object();
3637
3638   myWidgets[0]->setText( proxy.name() );
3639
3640   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3641   if ( mesh->_is_nil() ) return;
3642
3643   const bool meshLoaded = mesh->IsLoaded();
3644   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3645     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3646     for ( int i = 0; i < myButtons.count(); ++i )
3647       myButtons[i]->setEnabled( true );
3648
3649   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3650   if ( ! &nbElemsByType.in() ) return;
3651
3652   const CORBA::Long ctrlLimit =
3653     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3654
3655   // nodes info
3656   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3657   // const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3658   //                               nbElemsByType[ SMESH::FACE ] +
3659   //                               nbElemsByType[ SMESH::VOLUME ] );
3660   if ( nbNodes > 0 ) {
3661     if ( nbNodes <= ctrlLimit ) {
3662       // free nodes
3663       computeFreeNodesInfo();
3664       // node connectivity number
3665       computeNodesNbConnInfo();
3666       // double nodes
3667       computeDoubleNodesInfo();
3668     }
3669     else {
3670       myButtons[0]->setEnabled( true );
3671       myButtons[1]->setEnabled( true );
3672       myButtons[2]->setEnabled( true );
3673     }
3674   }
3675   else {
3676     for( int i=2; i<=13; i++)
3677       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3678   }
3679
3680   // edges info
3681   if ( nbElemsByType[ SMESH::EDGE ] > 0 ) {
3682     // double edges
3683     if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit )
3684       computeDoubleEdgesInfo();
3685     else
3686       myButtons[3]->setEnabled( true );
3687   }
3688   else {
3689     for( int i=14; i<=17; i++)
3690       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3691   }
3692
3693   // faces info
3694   if ( nbElemsByType[ SMESH::FACE ] > 0 ) {
3695     if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) {
3696       // double faces
3697       computeDoubleFacesInfo();
3698       // over constrained faces
3699       computeOverConstrainedFacesInfo();
3700       // aspect Ratio histogram
3701       computeAspectRatio();
3702     }
3703     else {
3704       myButtons[4]->setEnabled( true );
3705       myButtons[5]->setEnabled( true );
3706       myButtons[6]->setEnabled( true );
3707     }
3708 #ifdef DISABLE_PLOT2DVIEWER
3709     for( int i=25; i<=27; i++)
3710       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3711 #endif
3712   }
3713   else {
3714     for( int i=18; i<=27; i++)
3715       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3716   }
3717
3718   // volumes info
3719   if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) {
3720     if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) {
3721       // double volumes
3722       computeDoubleVolumesInfo();
3723       // over constrained volumes
3724       computeOverConstrainedVolumesInfo();
3725       // aspect Ratio 3D histogram
3726       computeAspectRatio3D();
3727     }
3728     else {
3729       myButtons[7]->setEnabled( true );
3730       myButtons[8]->setEnabled( true );
3731       myButtons[9]->setEnabled( true );
3732     }
3733 #ifdef DISABLE_PLOT2DVIEWER
3734     for( int i=35; i<=37; i++)
3735       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3736 #endif
3737   }
3738   else {
3739     for( int i=28; i<=37; i++)
3740       dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( false );
3741   }
3742 }
3743
3744 //================================================================================
3745 /*!
3746  * \brief Computes and shows nb of elements satisfying a given predicate
3747  *  \param [in] ft - a predicate type (SMESH::FunctorType)
3748  *  \param [in] iBut - index of one of myButtons to disable
3749  *  \param [in] iWdg - index of one of myWidgets to show the computed number
3750  */
3751 //================================================================================
3752
3753 void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg )
3754 {
3755   myButtons[ iBut ]->setEnabled( false );
3756   myWidgets[ iWdg ]->setText( "" );
3757
3758   if ( !myProxy )
3759     return;
3760
3761   SUIT_OverrideCursor wc;
3762
3763   SMESH::SMESH_IDSource_var obj = myProxy.object();
3764   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3765
3766   if ( !mesh->_is_nil() && !mesh->IsLoaded() )
3767   {
3768     mesh->Load();
3769     showInfo( myProxy ); // try to show all values
3770     if ( !myWidgets[ iWdg ]->text().isEmpty() )
3771       return; // <ft> predicate already computed
3772   }
3773   // look for a predicate of type <ft>
3774   for ( int i = 0; i < myPredicates.count(); ++i )
3775     if ( myPredicates[i]->GetFunctorType() == ft )
3776     {
3777       CORBA::Long nb = myPredicates[i]->NbSatisfying( obj );
3778       myWidgets[ iWdg ]->setText( QString::number( nb ) );
3779     }
3780 }
3781
3782 void SMESHGUI_CtrlInfo::computeFreeNodesInfo()
3783 {
3784   computeNb( SMESH::FT_FreeNodes, 0, 1 );
3785 }
3786
3787 void SMESHGUI_CtrlInfo::computeDoubleNodesInfo()
3788 {
3789   computeNb( SMESH::FT_EqualNodes, 2, 3 );
3790 }
3791
3792 void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo()
3793 {
3794   computeNb( SMESH::FT_EqualEdges, 3, 4 );
3795 }
3796
3797 void SMESHGUI_CtrlInfo::computeDoubleFacesInfo()
3798 {
3799   computeNb( SMESH::FT_EqualFaces, 4, 5 );
3800 }
3801
3802 void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo()
3803 {
3804   computeNb( SMESH::FT_OverConstrainedFace, 5, 6 );
3805 }
3806
3807 void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo()
3808 {
3809   computeNb( SMESH::FT_EqualVolumes, 7, 7 );
3810 }
3811
3812 void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo()
3813 {
3814   computeNb( SMESH::FT_OverConstrainedVolume, 8, 8 );
3815 }
3816
3817 void SMESHGUI_CtrlInfo::computeNodesNbConnInfo()
3818 {
3819   myButtons[ 1 ]->setEnabled( false );
3820   myWidgets[ 2 ]->setText( "" );
3821
3822   if ( !myProxy )
3823     return;
3824
3825   SUIT_OverrideCursor wc;
3826
3827   SMESH::SMESH_IDSource_var obj = myProxy.object();
3828   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3829
3830   if ( !mesh->IsLoaded() )
3831   {
3832     mesh->Load();
3833     showInfo( myProxy ); // try to show all values
3834     if ( !myWidgets[ 2 ]->text().isEmpty() )
3835       return; // already computed
3836   }
3837   myNodeConnFunctor->SetMesh( mesh );
3838   SMESH::Histogram_var histogram =
3839     myNodeConnFunctor->GetLocalHistogram( 1, /*isLogarithmic=*/false, obj );
3840
3841   myWidgets[ 2 ]->setText( QString::number( histogram[0].max ) );
3842 }
3843
3844 void SMESHGUI_CtrlInfo::computeAspectRatio()
3845 {
3846 #ifndef DISABLE_PLOT2DVIEWER
3847   myButtons[6]->setEnabled( false );
3848
3849   if ( !myProxy )
3850     return;
3851
3852   SUIT_OverrideCursor wc;
3853
3854   SMESH::SMESH_IDSource_var obj = myProxy.object();
3855   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3856
3857   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio );
3858   if ( aHistogram && !aHistogram->isEmpty() ) {
3859     QwtPlotItem* anItem = aHistogram->createPlotItem();
3860     anItem->attach( myPlot );
3861     myPlot->replot();
3862   }
3863   delete aHistogram;
3864 #endif
3865 }
3866
3867 void SMESHGUI_CtrlInfo::computeAspectRatio3D()
3868 {
3869 #ifndef DISABLE_PLOT2DVIEWER
3870   myButtons[9]->setEnabled( false );
3871
3872   if ( !myProxy )
3873     return;
3874
3875   SUIT_OverrideCursor wc;
3876
3877   SMESH::SMESH_IDSource_var obj = myProxy.object();
3878   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3879
3880   Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D );
3881   if ( aHistogram && !aHistogram->isEmpty() ) {
3882     QwtPlotItem* anItem = aHistogram->createPlotItem();
3883     anItem->attach( myPlot3D );
3884     myPlot3D->replot();
3885   }
3886   delete aHistogram;
3887 #endif
3888 }
3889
3890 /*!
3891   \brief Internal clean-up (reset widget)
3892 */
3893 void SMESHGUI_CtrlInfo::clearInternal()
3894 {
3895   for( int i=0; i<=37; i++)
3896     dynamic_cast<QGridLayout*>(layout())->itemAt(i)->widget()->setVisible( true );
3897   for( int i=0; i<=9; i++)
3898     myButtons[i]->setEnabled( false );
3899   myPlot->detachItems();
3900   myPlot3D->detachItems();
3901   myPlot->replot();
3902   myPlot3D->replot();
3903   myWidgets[0]->setText( QString() );
3904   for ( int i = 1; i < myWidgets.count(); i++ )
3905     myWidgets[i]->setText( "" );
3906 }
3907
3908 void SMESHGUI_CtrlInfo::setTolerance( double theTolerance )
3909 {
3910   myButtons[2]->setEnabled( true );
3911   myWidgets[3]->setText("");
3912   for ( int i = 0; i < myPredicates.count(); ++i )
3913     if ( myPredicates[i]->GetFunctorType() == SMESH::FT_EqualNodes )
3914     {
3915       SMESH::EqualNodes_var functor = SMESH::EqualNodes::_narrow( myPredicates[i] );
3916       if ( !functor->_is_nil() )
3917         functor->SetTolerance( theTolerance );
3918     }
3919 }
3920
3921 #ifndef DISABLE_PLOT2DVIEWER
3922 Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun )
3923 {
3924   SUIT_OverrideCursor wc;
3925
3926   SMESH::SMESH_IDSource_var obj = myProxy.object();
3927   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3928
3929   if ( !mesh->IsLoaded() )
3930     mesh->Load();
3931   aNumFun->SetMesh( mesh );
3932
3933   CORBA::Long cprecision = 6;
3934   if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) )
3935     cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 );
3936   aNumFun->SetPrecision( cprecision );
3937
3938   int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false );
3939
3940   SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals,
3941                                                                   /*isLogarithmic=*/false,
3942                                                                   obj );
3943   Plot2d_Histogram* aHistogram = new Plot2d_Histogram();
3944   aHistogram->setColor( palette().color( QPalette::Highlight ) );
3945   if ( &histogramVar.in() )
3946   {
3947     for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ )
3948       aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents );
3949     if ( histogramVar->length() >= 2 )
3950       aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 );
3951   }
3952   return aHistogram;
3953 }
3954 #endif
3955
3956 void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out )
3957 {
3958   // title
3959   QString title = tr( "CTRL_INFO" );
3960   out << ruler( title.size() ) << endl;
3961   out << title << endl;
3962   out << ruler( title.size() ) << endl;
3963   out << endl;
3964
3965   // info
3966   out << tr( "NAME_LAB" ) << "  " << myWidgets[0]->text() << endl;
3967   out << tr( "NODES_INFO" ) << endl;
3968   out << indent() << tr( "NUMBER_OF_THE_FREE_NODES" ) << ": " << myWidgets[1]->text() << endl;
3969   out << indent() << tr( "NUMBER_OF_THE_DOUBLE_NODES" ) << ": " << myWidgets[3]->text() << endl;
3970   out << tr( "EDGES_INFO" ) << endl;
3971   out << indent() << tr( "NUMBER_OF_THE_DOUBLE_EDGES" ) << ": " << myWidgets[4]->text() << endl;
3972   out << tr( "FACES_INFO" ) << endl;
3973   out << indent() << tr( "NUMBER_OF_THE_DOUBLE_FACES" ) << ": " << myWidgets[5]->text() << endl;
3974   out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[6]->text() << endl;
3975   out << tr( "VOLUMES_INFO" ) << endl;
3976   out << indent() << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ) << ": " << myWidgets[7]->text() << endl;
3977   out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[8]->text() << endl;
3978 }
3979
3980 ////////////////////////////////////////////////////////////////////////////////
3981 /// \class SMESHGUI_CtrlInfoDlg
3982 /// \brief Overall Mesh Quality dialog.
3983 /// \todo Add selection button to reactivate selection on move from other dlg.
3984 ////////////////////////////////////////////////////////////////////////////////
3985
3986 /*!
3987   \brief Constructor
3988   \param parent parent widget
3989 */
3990 SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent )
3991   : QDialog( parent )
3992 {
3993   setAttribute( Qt::WA_DeleteOnClose, true );
3994   setWindowTitle( tr( "CTRL_INFO" ) );
3995   setMinimumSize( 400, 600 );
3996
3997   myCtrlInfo = new SMESHGUI_CtrlInfo( this );
3998   
3999   // buttons
4000   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
4001   okBtn->setAutoDefault( true );
4002   okBtn->setDefault( true );
4003   okBtn->setFocus();
4004   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
4005   dumpBtn->setAutoDefault( true );
4006   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
4007   helpBtn->setAutoDefault( true );
4008
4009   QHBoxLayout* btnLayout = new QHBoxLayout;
4010   btnLayout->setSpacing( SPACING );
4011   btnLayout->setMargin( 0 );
4012
4013   btnLayout->addWidget( okBtn );
4014   btnLayout->addWidget( dumpBtn );
4015   btnLayout->addStretch( 10 );
4016   btnLayout->addWidget( helpBtn );
4017
4018   QVBoxLayout* l = new QVBoxLayout ( this );
4019   l->setMargin( 0 );
4020   l->setSpacing( SPACING );
4021   l->addWidget( myCtrlInfo );
4022   l->addLayout( btnLayout );
4023
4024   connect( okBtn,   SIGNAL( clicked() ), this, SLOT( reject() ) );
4025   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
4026   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
4027   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
4028   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ),        this, SLOT( reject() ) );
4029
4030   updateSelection();
4031 }
4032
4033 /*!
4034   \brief Destructor
4035 */
4036 SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg()
4037 {
4038 }
4039
4040 /*!
4041   \brief Show mesh quality information on given object.
4042   \param io Interactive object.
4043 */
4044 void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io )
4045 {  
4046   if ( !io.IsNull() )
4047     showInfo( SMESH::SelectionProxy( io ) );
4048 }
4049
4050 /*!
4051   \brief Show mesh quality information on given object.
4052   \param proxy Selection proxy.
4053 */
4054 void SMESHGUI_CtrlInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
4055 {
4056   SUIT_OverrideCursor wc;
4057
4058   if ( !proxy )
4059     return;
4060
4061   myProxy = proxy;
4062   myCtrlInfo->showInfo( proxy );
4063 }
4064
4065 /*!
4066   \brief Show mesh information
4067 */
4068 void SMESHGUI_CtrlInfoDlg::updateInfo()
4069 {
4070   SALOME_ListIO selected;
4071   SMESHGUI::selectionMgr()->selectedObjects( selected );
4072
4073   if ( selected.Extent() == 1 )
4074     showInfo( selected.First() );
4075   else
4076     showInfo( myProxy );
4077 }
4078
4079 /*!
4080   \brief Perform clean-up actions on the dialog box closing.
4081 */
4082 void SMESHGUI_CtrlInfoDlg::reject()
4083 {
4084   SMESH::SetPointRepresentation( false );
4085   QDialog::reject();
4086 }
4087
4088 /*!
4089   \brief Setup selection mode depending on the current dialog box state.
4090 */
4091 void SMESHGUI_CtrlInfoDlg::updateSelection()
4092 {
4093   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
4094   disconnect( selMgr, 0, this, 0 );
4095   SMESH::SetPointRepresentation( false );  
4096   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
4097   updateInfo();  
4098 }
4099
4100 /*!
4101   \brief Deactivate dialog box.
4102 */
4103 void SMESHGUI_CtrlInfoDlg::deactivate()
4104 {
4105   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
4106 }
4107
4108 /*!
4109   \brief Dump information to file.
4110 */
4111 void SMESHGUI_CtrlInfoDlg::dump()
4112 {
4113   DumpFileDlg fd( this, false );
4114   fd.setWindowTitle( tr( "SAVE_INFO" ) );
4115   fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) );
4116   if ( fd.exec() == QDialog::Accepted )
4117   {
4118     QString fileName = fd.selectedFile();
4119     if ( !fileName.isEmpty() ) {
4120       QFile file( fileName );
4121       if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
4122         return;
4123
4124       QTextStream out( &file );
4125       myCtrlInfo->saveInfo( out );
4126     }
4127   }
4128 }
4129
4130 /*!
4131   \brief Show documentation on dialog.
4132 */
4133 void SMESHGUI_CtrlInfoDlg::help()
4134 {
4135   SMESH::ShowHelpFile( "mesh_infos.html#mesh-quality-info-anchor" );
4136 }