Salome HOME
bcbd1b86876eab3b62d283980cc41494ef1aa0ed
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_MeshInfo.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "SMESHGUI_MeshInfo.h"
24
25 #include "SMDS_Mesh.hxx"
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. Defauls 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 Stringifed 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 }
978
979 /*!
980   \brief Register widget in a grid.
981   \param w Widget being added.
982   \param row Row index in a grid.
983   \param column Column index in a grid.
984   \param colspan Number of columns to span in a grid. Defaults to 1.
985   \return Just added widget.
986 */
987 QWidget* SMESHGUI_BaseInfo::addWidget( QWidget* w, int row, int column, int colspan )
988 {
989   if ( !myWidgets.contains( row ) )
990     myWidgets[row] = wlist();
991   myWidgets[row][column] = w;
992   dynamic_cast<QGridLayout*>( layout() )->addWidget( w, row, column, 1, colspan );
993   return w;
994 }
995
996 /*!
997   \brief Get registered widget.
998   \param row Row index in a grid.
999   \param column Column index in a grid.
1000   \return Widget stored in a given grid cell (0 if there's no widget).
1001 */
1002 QWidget* SMESHGUI_BaseInfo::widget( int row, int column ) const
1003 {
1004   return myWidgets.contains( row ) && myWidgets[row].contains( column ) ? myWidgets[row][column] : 0;
1005 }
1006
1007 /*!
1008   \brief Get text value from registered widget.
1009   \param row Row index in a grid.
1010   \param column Column index in a grid.
1011   \return Value string (empty string if no label in given cell).
1012 */
1013 QString SMESHGUI_BaseInfo::value( int row, int column ) const
1014 {
1015   return widgetValue( widget( row, column ) );
1016 }
1017
1018 /*!
1019   \brief Show/hide group(s) of widgets.
1020   \param startRow Starting grid row.
1021   \param lastRow Last grid row.
1022   \param on Visibility flag.
1023 */
1024 void SMESHGUI_BaseInfo::setFieldsVisible( int startRow, int lastRow, bool on )
1025 {
1026   startRow = qMax( 0, startRow );
1027   lastRow = qMin( lastRow, (int)iEnd );
1028   for ( int i = startRow; i <= lastRow; i++ )
1029   {
1030     wlist widgets = myWidgets[i];
1031     foreach ( QWidget* w, widgets )
1032       w->setVisible( on );
1033   }
1034 }
1035
1036 /*!
1037   \brief Write information from panel to ouput stream.
1038   \param out Text stream output.
1039 */
1040 void SMESHGUI_BaseInfo::saveInfo( QTextStream& out )
1041 {
1042   // title
1043   QString title = tr( "BASE_INFO" );
1044   out << ruler( title.size() ) << endl;
1045   out << title << endl;
1046   out << ruler( title.size() ) << endl;
1047   out << endl;
1048
1049   // object info
1050   // - name
1051   out << tr( "NAME_LAB" ) << spacing() << value( iName, iSingle ) << endl;
1052   // - type
1053   out << tr( "OBJECT_LAB" ) << spacing() << value( iObject, iSingle ) << endl;
1054   // - --- (separator)
1055   out << endl;
1056
1057   // node info
1058   out << tr( "NODES_LAB" ) << spacing() << value( iNodes, iTotal ) << endl;
1059   // - --- (separator)
1060   out << endl;
1061
1062   // element info
1063   QString lin = tr( "LINEAR_LAB" ) + ":" + spacing();
1064   QString qua = tr( "QUADRATIC_LAB" ) + ":" + spacing();
1065   QString biq = tr( "BI_QUADRATIC_LAB" ) + ":" + spacing();
1066   // - summary
1067   out << tr( "ELEMENTS_LAB" ) << spacing() << value( iElementsTotal, iTotal ) << endl;
1068   out << indent(1) << lin << value( iElementsTotal, iLinear ) << endl;
1069   out << indent(1) << qua << value( iElementsTotal, iQuadratic ) << endl;
1070   out << indent(1) << biq << value( iElementsTotal, iBiQuadratic ) << endl;
1071   // - --- (separator)
1072   out << endl;
1073   // - 0D elements info
1074   out << indent(1) << tr( "0D_LAB" ) << spacing() << value( i0D, iTotal ) << endl;
1075   // - --- (separator)
1076   out << endl;
1077   // - balls info
1078   out << indent(1) << tr( "BALL_LAB" ) << spacing() << value( iBalls, iTotal ) << endl;
1079   // - --- (separator)
1080   out << endl;
1081   // - 1D elements info
1082   out << indent(1) << tr( "1D_LAB" ) << spacing() << value( i1D, iTotal ) << endl;
1083   out << indent(2) << lin << value( i1D, iLinear ) << endl;
1084   out << indent(2) << qua << value( i1D, iQuadratic ) << endl;
1085   // - --- (separator)
1086   out << endl;
1087   // - 2D elements info
1088   // - summary
1089   out << indent(1) << tr( "2D_LAB" ) << spacing() << value( i2D, iTotal ) << endl;
1090   out << indent(2) << lin << value( i2D, iLinear ) << endl;
1091   out << indent(2) << qua << value( i2D, iQuadratic ) << endl;
1092   out << indent(2) << biq << value( i2D, iBiQuadratic ) << endl;
1093   // - --- (separator)
1094   out << endl;
1095   // --+ triangles
1096   out << indent(2) << tr( "TRIANGLES_LAB" ) << spacing() << value( i2DTriangles, iTotal ) << endl;
1097   out << indent(3) << lin << value( i2DTriangles, iLinear ) << endl;
1098   out << indent(3) << qua << value( i2DTriangles, iQuadratic ) << endl;
1099   out << indent(3) << biq << value( i2DTriangles, iBiQuadratic ) << endl;
1100   // --+ quadrangles
1101   out << indent(2) << tr( "QUADRANGLES_LAB" ) << spacing() << value( i2DQuadrangles, iTotal ) << endl;
1102   out << indent(3) << lin << value( i2DQuadrangles, iLinear ) << endl;
1103   out << indent(3) << qua << value( i2DQuadrangles, iQuadratic ) << endl;
1104   out << indent(3) << biq << value( i2DQuadrangles, iBiQuadratic ) << endl;
1105   // --+ polygons
1106   out << indent(2) << tr( "POLYGONS_LAB" ) << spacing() << value( i2DPolygons, iTotal ) << endl;
1107   out << indent(3) << lin << value( i2DPolygons, iLinear ) << endl;
1108   out << indent(3) << qua << value( i2DPolygons, iQuadratic ) << endl;
1109   // - --- (separator)
1110   out << endl;
1111   // - 3D elements info
1112   // --+ summary
1113   out << indent(1) << tr( "3D_LAB" ) << spacing() << value( i3D, iTotal ) << endl;
1114   out << indent(2) << lin << value( i3D, iLinear ) << endl;
1115   out << indent(2) << qua << value( i3D, iQuadratic ) << endl;
1116   out << indent(2) << biq << value( i3D, iBiQuadratic ) << endl;
1117   // - --- (separator)
1118   out << endl;
1119   // --+ tetras
1120   out << indent(2) << tr( "TETRAHEDRONS_LAB" ) << spacing() << value( i3DTetrahedrons, iTotal ) << endl;
1121   out << indent(3) << lin << value( i3DTetrahedrons, iLinear ) << endl;
1122   out << indent(3) << qua << value( i3DTetrahedrons, iQuadratic ) << endl;
1123   // --+ hexas
1124   out << indent(2) << tr( "HEXAHEDONRS_LAB" ) << spacing() << value( i3DHexahedrons, iTotal ) << endl;
1125   out << indent(3) << lin << value( i3DHexahedrons, iLinear ) << endl;
1126   out << indent(3) << qua << value( i3DHexahedrons, iQuadratic ) << endl;
1127   out << indent(3) << biq << value( i3DHexahedrons, iBiQuadratic ) << endl;
1128   // --+ pyramids
1129   out << indent(2) << tr( "PYRAMIDS_LAB" ) << spacing() << value( i3DPyramids, iTotal ) << endl;
1130   out << indent(3) << lin << value( i3DPyramids, iLinear ) << endl;
1131   out << indent(3) << qua << value( i3DPyramids, iQuadratic ) << endl;
1132   // --+ prisms
1133   out << indent(2) << tr( "PRISMS_LAB" ) << spacing() << value( i3DPrisms, iTotal ) << endl;
1134   out << indent(3) << lin << value( i3DPrisms, iLinear ) << endl;
1135   out << indent(3) << qua << value( i3DPrisms, iQuadratic ) << endl;
1136   out << indent(3) << biq << value( i3DPrisms, iBiQuadratic ) << endl;
1137   // --+ hexagonal prisms
1138   out << indent(2) << tr( "HEX_PRISMS_LAB" ) << spacing() << value( i3DHexaPrisms, iTotal ) << endl;
1139   // --+ polyhedrons
1140   out << indent(2) << tr( "POLYHEDRONS_LAB" ) << spacing() << value( i3DPolyhedrons, iTotal ) << endl;
1141   // - --- (separator)
1142   out << endl;
1143 }
1144
1145 ////////////////////////////////////////////////////////////////////////////////
1146 /// \class InfoWriter
1147 /// \brief Base info writer class.
1148 /// \internal
1149 ////////////////////////////////////////////////////////////////////////////////
1150
1151 class InfoWriter
1152 {
1153 protected:
1154   int myPrecision;
1155   bool myRecursive;
1156 public:
1157   InfoWriter( bool = false );
1158   void write( const QString&, bool = false );
1159   void write( const QString&, const QString&, bool = false );
1160   void write( const QString&, int, bool = false );
1161   void write( const QString&, double, bool = false );
1162   void write( const QString&, const SMESH::XYZ&, bool = false );
1163   virtual void indent() {}
1164   virtual void unindent() {}
1165   virtual void separator() {}
1166 protected:
1167   virtual void put( const QString&, const QString&, bool = false ) = 0;
1168 };
1169
1170 InfoWriter::InfoWriter( bool r ): myRecursive(r)
1171 {
1172   myPrecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
1173 }
1174
1175 void InfoWriter::write( const QString& key, bool emphasize )
1176 {
1177   put( key, QString(), emphasize );
1178 }
1179
1180 void InfoWriter::write( const QString& key, const QString& value, bool emphasize )
1181 {
1182   put( key, value, emphasize );
1183 }
1184
1185 void InfoWriter::write( const QString& key, int value, bool emphasize )
1186 {
1187   put( key, QString::number( value ), emphasize );
1188 }
1189
1190 void InfoWriter::write( const QString& key, double value, bool emphasize )
1191 {
1192   put( key, QString::number( value, myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ), emphasize );
1193 }
1194
1195 void InfoWriter::write( const QString& key, const SMESH::XYZ& value, bool emphasize )
1196 {
1197   if ( myRecursive )
1198   {
1199     write( key, emphasize );
1200     indent();
1201     write( "X", value.x() );
1202     write( "Y", value.y() );
1203     write( "Z", value.z() );
1204     unindent(); 
1205   }
1206   else
1207   {
1208     QStringList vl;
1209     vl << QString::number( value.x(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
1210     vl << QString::number( value.y(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
1211     vl << QString::number( value.z(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) );
1212     put( key, vl.join( ", " ), emphasize );
1213   }
1214 }
1215
1216 ////////////////////////////////////////////////////////////////////////////////
1217 /// \class SimpleWriter
1218 /// \brief Base text writer.
1219 /// \internal
1220 ////////////////////////////////////////////////////////////////////////////////
1221
1222 class SimpleWriter: public InfoWriter
1223 {
1224 protected:
1225   int myIndent;
1226 public:
1227   SimpleWriter();
1228   void indent();
1229   void unindent();
1230   void separator();
1231 protected:
1232   void put( const QString&, const QString&, bool );
1233   virtual QString spacer() const;
1234   virtual QString decorate( const QString& ) const;
1235   virtual void dumpLine( const QString& ) = 0;
1236 };
1237
1238 SimpleWriter::SimpleWriter(): InfoWriter(false), myIndent(0)
1239 {
1240 }
1241
1242 void SimpleWriter::indent()
1243 {
1244   myIndent += 1;
1245 }
1246
1247 void SimpleWriter::unindent()
1248 {
1249   myIndent = qMax( myIndent-1, 0 );
1250 }
1251
1252 void SimpleWriter::separator()
1253 {
1254   write( "" );
1255 }
1256
1257 QString SimpleWriter::spacer() const
1258 {
1259   return " ";
1260 }
1261
1262 QString SimpleWriter::decorate( const QString& s ) const
1263 {
1264   return s;
1265 }
1266
1267 void SimpleWriter::put( const QString& key, const QString& value, bool emphasize )
1268 {
1269   QString line;
1270   line += ::indent( spacer(), myIndent*4 );
1271   line += decorate( key );
1272   if ( !value.isEmpty() )
1273   {
1274     line += ":";
1275     line += emphasize ? decorate( value ) : value;
1276   }
1277   dumpLine( line );
1278 }
1279
1280 ////////////////////////////////////////////////////////////////////////////////
1281 /// \class StreamWriter
1282 /// \brief Writer for QTextStream.
1283 /// \internal
1284 ////////////////////////////////////////////////////////////////////////////////
1285
1286 class StreamWriter: public SimpleWriter
1287 {
1288   QTextStream& myOut;
1289 public:
1290   StreamWriter( QTextStream& );
1291 protected:
1292   void dumpLine( const QString& );
1293 };
1294
1295 StreamWriter::StreamWriter( QTextStream& out ): SimpleWriter(), myOut(out)
1296 {
1297 }
1298
1299 void StreamWriter::dumpLine( const QString& line )
1300 {
1301   myOut << line;
1302   myOut << endl;
1303 }
1304
1305 ////////////////////////////////////////////////////////////////////////////////
1306 /// \class TextWriter
1307 /// \brief Writer for QTextBrowser.
1308 /// \internal
1309 ////////////////////////////////////////////////////////////////////////////////
1310
1311 class TextWriter: public SimpleWriter
1312 {
1313   QTextBrowser* myInfo;
1314 public:
1315   TextWriter( QTextBrowser* );
1316 protected:
1317   QString spacer() const;
1318   QString decorate( const QString& ) const;
1319   void dumpLine( const QString& );
1320 };
1321
1322 TextWriter::TextWriter( QTextBrowser* w ): SimpleWriter(), myInfo(w)
1323 {
1324 }
1325
1326 QString TextWriter::spacer() const
1327 {
1328   return "&nbsp;";
1329 }
1330
1331 QString TextWriter::decorate( const QString& s ) const
1332 {
1333   return bold( s );
1334 }
1335
1336 void TextWriter::dumpLine( const QString& line )
1337 {
1338   myInfo->append( line );
1339 }
1340
1341 ////////////////////////////////////////////////////////////////////////////////
1342 /// \class TreeWriter
1343 /// \brief Writer for QTreeWidget.
1344 /// \internal
1345 ////////////////////////////////////////////////////////////////////////////////
1346
1347 class TreeWriter: public InfoWriter
1348 {
1349   QTreeWidget* myInfo;
1350   QTreeWidgetItem* myCurrentItem;
1351   TreeItemCreator* myCreator;
1352 public:
1353   TreeWriter( QTreeWidget*, TreeItemCreator* );
1354   ~TreeWriter();
1355   void indent();
1356   void unindent();
1357 protected:
1358   void put( const QString&, const QString&, bool = false );
1359 };
1360
1361 TreeWriter::TreeWriter( QTreeWidget* w, TreeItemCreator* c ):
1362   InfoWriter(true), myInfo(w), myCurrentItem(0), myCreator(c)
1363 {
1364 }
1365
1366 TreeWriter::~TreeWriter()
1367 {
1368   delete myCreator;
1369 }
1370
1371 void TreeWriter::put( const QString& key, const QString& value, bool emphasize )
1372 {
1373   //std::string sss = myCurrentItem ? myCurrentItem->text(0).toStdString() : "";
1374   int options = Bold;
1375   if ( emphasize ) options |= AllColumns;
1376   QTreeWidgetItem* item = myCreator->createItem( myCurrentItem, options );
1377   item->setText( 0, key );
1378   if ( !value.isEmpty() )
1379   {
1380     QString val = value;
1381     if ( value.startsWith( "<a href" )) // connectivity encoded as: <a href = "nodes://host/1 2">1 2</a>
1382     {
1383       int role = ( value[11] == 'n' ) ? NodeConnectivity : ElemConnectivity;
1384       val = value.mid( value.lastIndexOf( '>', -5 ) + 1 ); // ==>   1 2</a>
1385       val.chop( 4 );
1386       item->setData( 1, TypeRole, role );
1387     }
1388     item->setText( 1, val );
1389   }
1390 }
1391
1392 void TreeWriter::indent()
1393 {
1394   QTreeWidgetItem* item = myCurrentItem ? myCurrentItem : myInfo->invisibleRootItem();
1395   if ( item->childCount() > 0 )
1396     myCurrentItem = item->child( item->childCount()-1 );
1397 }
1398
1399 void TreeWriter::unindent()
1400 {
1401   if ( myCurrentItem )
1402     myCurrentItem = myCurrentItem->parent();
1403 }
1404
1405 ////////////////////////////////////////////////////////////////////////////////
1406 /// \class SMESHGUI_ElemInfo
1407 /// \brief Base class for the mesh element information widget.
1408 ///
1409 /// Displays the detail information about given mesh node(s) or element(s).
1410 /// Default class does not provide working implementation but onle general
1411 /// functionalities; main work is done in sub-classes.
1412 ////////////////////////////////////////////////////////////////////////////////
1413
1414 /*!
1415   \brief Constructor.
1416   \param parent Parent widget. Defaults to 0.
1417 */
1418 SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ): SMESHGUI_Info( parent ), myWhat( ShowNone )
1419 {
1420   myFrame = new QWidget( this );
1421   myExtra = new ExtraWidget( this );
1422
1423   QVBoxLayout* vbl = new QVBoxLayout( this );
1424   vbl->setMargin( 0 );
1425   vbl->setSpacing( SPACING );
1426   vbl->addWidget( myFrame );
1427   vbl->addWidget( myExtra );
1428
1429   connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) );
1430   connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) );
1431
1432   clear();
1433 }
1434
1435 /*!
1436   \brief Destructor.
1437 */
1438 SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo()
1439 {
1440 }
1441
1442 /*!
1443   \brief Show information on given node / element.
1444   \param proxy Object to compute information on (mesh, sub-mesh, group, ID source).
1445   \param id Mesh node / element ID.
1446   \param isElement If \c true, show element info; otherwise show node info.
1447 */
1448 void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, uint id, bool isElement )
1449 {
1450   QSet<uint> ids;
1451   ids << id;
1452   showInfo( proxy, ids, isElement );
1453 }
1454
1455 /*!
1456   \brief Show information on given nodes / elements.
1457   \param proxy Object to compute information on (mesh, sub-mesh, group, ID source).
1458   \param ids Mesh nodes / elements IDs.
1459   \param isElement If \c true, show element info; otherwise show node info.
1460 */
1461 void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, QSet<uint> ids, bool isElement )
1462 {
1463   if ( !proxy )
1464   {
1465     clear();
1466     return;
1467   }
1468
1469   QList<uint> newIds = ids.toList();
1470   qSort( newIds );
1471   int what = isElement ? ShowElements : ShowNodes;
1472   
1473   if ( myProxy == proxy && myIDs == newIds && myWhat == what )
1474     return;
1475   
1476   myProxy = proxy;
1477   myProxy.refresh(); // try to re-initialize actor
1478
1479   clear();
1480
1481   myIDs = newIds;
1482   myWhat = what;
1483   myIndex = 0;
1484   
1485   updateControls();
1486   information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
1487 }
1488
1489 /*!
1490   \brief Show information on given group.
1491   \param proxy Object to compute information on (group).
1492 */
1493 void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy )
1494 {
1495   if ( !proxy || proxy.groupElementType() == SMESH::ALL ) // null proxy or not a group
1496   {
1497     clear();
1498     return;
1499   }
1500
1501   showInfo( proxy, proxy.ids(), proxy.groupElementType() != SMESH::NODE );
1502 }
1503
1504 /*!
1505   \brief Reset panel (clear all data).
1506 */
1507 void SMESHGUI_ElemInfo::clear()
1508 {
1509   myIDs.clear();
1510   myIndex = 0;
1511   clearInternal();
1512   updateControls();
1513 }
1514
1515 /*!
1516   \brief Get central area widget.
1517   \return Central widget.
1518 */
1519 QWidget* SMESHGUI_ElemInfo::centralWidget() const
1520 {
1521   return myFrame;
1522 }
1523
1524 /*!
1525   \brief Get current mesh proxy object information is shown on.
1526   \return Current proxy.
1527 */
1528 SMESH::SelectionProxy SMESHGUI_ElemInfo::proxy() const
1529 {
1530   return myProxy;
1531 }
1532
1533 /*!
1534   \brief Get current info mode.
1535   \return Current panel mode.
1536 */
1537 int SMESHGUI_ElemInfo::what() const
1538 {
1539   return myWhat;
1540 }
1541
1542 /*!
1543   \brief Get title for given element type.
1544   \param type Mesh element type.
1545   \param multiple Use plural form. Defaults to \c false.
1546   \return Element type's title.
1547 */
1548 QString SMESHGUI_ElemInfo::type2str( int type, bool multiple )
1549 {
1550   QString title;
1551   switch ( type )
1552   {
1553   case SMDSAbs_Edge:
1554     title = multiple ? tr( "EDGES" ) : tr( "EDGE" ) ; break;
1555   case SMDSAbs_Face:
1556     title = multiple ? tr( "FACES" ) : tr( "FACE" ); break;
1557   case SMDSAbs_Volume:
1558     title = multiple ? tr( "VOLUMES" ) : tr( "VOLUME" ); break;
1559   case SMDSAbs_0DElement:
1560     title = multiple ? tr( "0D_ELEMENTS" ) : tr( "0D_ELEMENT" ); break;
1561   case SMDSAbs_Ball:
1562     title = multiple ? tr( "BALL_ELEMENTS" ) : tr( "BALL" ); break;
1563   default:
1564     break;
1565   }
1566   return title;
1567 }
1568
1569 /*!
1570   \brief Get title for given shape type.
1571   \param type Shape type.
1572   \return Shape type's title.
1573 */
1574 QString SMESHGUI_ElemInfo::stype2str( int type )
1575 {
1576   QString title;
1577   switch ( type )
1578   {
1579   case GEOM::VERTEX:
1580     title = tr( "GEOM_VERTEX" ); break;
1581   case GEOM::EDGE:
1582     title = tr( "GEOM_EDGE" ); break;
1583   case GEOM::FACE:
1584     title = tr( "GEOM_FACE" ); break;
1585   case GEOM::SOLID:
1586   default:
1587     title = tr( "GEOM_SOLID" ); break;
1588     break;
1589   }
1590   return title;
1591 }
1592
1593 /*!
1594   \brief Get title for given element type.
1595   \param type Mesh element type.
1596   \return Element type's title.
1597 */
1598 QString SMESHGUI_ElemInfo::etype2str( int type )
1599 {
1600   QString title;
1601   switch ( type )
1602   {
1603   case SMESH::Entity_0D:
1604     title = tr( "SMESH_ELEM0D" ); break;
1605   case SMESH::Entity_Edge:
1606     title = tr( "SMESH_EDGE" ); break;
1607   case SMESH::Entity_Quad_Edge:
1608     title = tr( "SMESH_QUADRATIC_EDGE" ); break;
1609   case SMESH::Entity_Triangle:
1610     title = tr( "SMESH_TRIANGLE" ); break;
1611   case SMESH::Entity_Quad_Triangle:
1612     title = tr( "SMESH_QUADRATIC_TRIANGLE" ); break;
1613   case SMESH::Entity_BiQuad_Triangle:
1614     title = tr( "SMESH_BIQUADRATIC_TRIANGLE" ); break;
1615   case SMESH::Entity_Quadrangle:
1616     title = tr( "SMESH_QUADRANGLE" ); break;
1617   case SMESH::Entity_Quad_Quadrangle:
1618     title = tr( "SMESH_QUADRATIC_QUADRANGLE" ); break;
1619   case SMESH::Entity_BiQuad_Quadrangle:
1620     title = tr( "SMESH_BIQUADRATIC_QUADRANGLE" ); break;
1621   case SMESH::Entity_Polygon:
1622     title = tr( "SMESH_POLYGON" ); break;
1623   case SMESH::Entity_Quad_Polygon:
1624     title = tr( "SMESH_QUADRATIC_POLYGON" ); break;
1625   case SMESH::Entity_Tetra:
1626     title = tr( "SMESH_TETRAHEDRON" ); break;
1627   case SMESH::Entity_Quad_Tetra:
1628     title = tr( "SMESH_QUADRATIC_TETRAHEDRON" ); break;
1629   case SMESH::Entity_Pyramid:
1630     title = tr( "SMESH_PYRAMID" ); break;
1631   case SMESH::Entity_Quad_Pyramid:
1632     title = tr( "SMESH_QUADRATIC_PYRAMID" ); break;
1633   case SMESH::Entity_Hexa:
1634     title = tr( "SMESH_HEXAHEDRON" ); break;
1635   case SMESH::Entity_Quad_Hexa:
1636     title = tr( "SMESH_QUADRATIC_HEXAHEDRON" ); break;
1637   case SMESH::Entity_TriQuad_Hexa:
1638     title = tr( "SMESH_TRIQUADRATIC_HEXAHEDRON" ); break;
1639   case SMESH::Entity_Penta:
1640     title = tr( "SMESH_PENTA" ); break;
1641   case SMESH::Entity_Quad_Penta:
1642     title = tr( "SMESH_QUADRATIC_PENTAHEDRON" ); break;
1643   case SMESH::Entity_BiQuad_Penta:
1644     title = tr( "SMESH_BIQUADRATIC_PENTAHEDRON" ); break;
1645   case SMESH::Entity_Hexagonal_Prism:
1646     title = tr( "SMESH_HEX_PRISM" ); break;
1647   case SMESH::Entity_Polyhedra:
1648     title = tr( "SMESH_POLYEDRON" ); break;
1649   case SMESH::Entity_Quad_Polyhedra:
1650     title = tr( "SMESH_QUADRATIC_POLYEDRON" ); break;
1651   case SMESH::Entity_Ball:
1652     title = tr( "SMESH_BALL" ); break;
1653   default:
1654     break;
1655   }
1656   return title;
1657 }
1658
1659 /*!
1660   \brief Get title for given quality control.
1661   \param type Mesh control type.
1662   \return Quality control's title.
1663 */
1664 QString SMESHGUI_ElemInfo::ctrl2str( int control )
1665 {
1666   QString title;
1667   switch ( control )
1668   {
1669   case SMESH::FT_AspectRatio:
1670     title = tr( "ASPECTRATIO_ELEMENTS" ); break;
1671   case SMESH::FT_AspectRatio3D:
1672     title = tr( "ASPECTRATIO_3D_ELEMENTS" ); break;
1673   case SMESH::FT_Warping:
1674     title = tr( "WARP_ELEMENTS" ); break;
1675   case SMESH::FT_MinimumAngle:
1676     title = tr( "MINIMUMANGLE_ELEMENTS" ); break;
1677   case SMESH::FT_Taper:
1678     title = tr( "TAPER_ELEMENTS" ); break;
1679   case SMESH::FT_Skew:
1680     title = tr( "SKEW_ELEMENTS" ); break;
1681   case SMESH::FT_Area:
1682     title = tr( "AREA_ELEMENTS" ); break;
1683   case SMESH::FT_Volume3D:
1684     title = tr( "VOLUME_3D_ELEMENTS" ); break;
1685   case SMESH::FT_MaxElementLength2D:
1686     title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
1687   case SMESH::FT_MaxElementLength3D:
1688     title = tr( "MAX_ELEMENT_LENGTH_3D" ); break;
1689   case SMESH::FT_Length:
1690     title = tr( "LENGTH_EDGES" ); break;
1691   case SMESH::FT_Length2D:
1692   case SMESH::FT_Length3D:
1693     title = tr( "MIN_ELEM_EDGE" ); break;
1694   case SMESH::FT_BallDiameter:
1695     title = tr( "BALL_DIAMETER" ); break;
1696   default:
1697     break;
1698   }
1699   return title;
1700 }
1701
1702 /*!
1703   \brief Write information on given mesh nodes / elements.
1704   \param writer Information writer.
1705   \param ids Nodes / elements IDs.
1706 */
1707 void SMESHGUI_ElemInfo::writeInfo( InfoWriter* writer, const QList<uint>& ids )
1708 {
1709   if ( !proxy() )
1710     return;
1711
1712   bool grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false );
1713   int cprecision = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ? 
1714     SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ) : -1;
1715
1716   SMESH::XYZ xyz;
1717   SMESH::Connectivity connectivity;
1718   SMESH::Position position;
1719   bool ok;
1720
1721   foreach ( uint id, ids )
1722   {
1723     writer->separator();
1724
1725     if ( what() == ShowNodes )
1726     {
1727       // show node info
1728       // - check that node exists
1729       if ( !proxy().hasNode( id ) )
1730         continue;
1731       // - id
1732       writer->write( tr( "NODE" ), (int)id, true );
1733       writer->indent();
1734       // - coordinates
1735       ok = proxy().nodeCoordinates( id, xyz );
1736       if ( ok )
1737       {
1738         writer->write( tr( "COORDINATES" ), xyz );
1739       }
1740       // - connectivity
1741       ok = proxy().nodeConnectivity( id, connectivity );
1742       if ( ok )
1743       {
1744         if ( !connectivity.isEmpty() )
1745         {
1746           writer->write( tr( "CONNECTIVITY" ) );
1747           writer->indent();
1748           for ( int i = SMDSAbs_Edge; i <= SMDSAbs_Ball; i++ )
1749           {
1750             QString formatted = formatConnectivity( connectivity, i );
1751             if ( !formatted.isEmpty() )
1752               writer->write( type2str( i, true ), formatted );
1753           }
1754           writer->unindent();
1755         }
1756         else
1757         {
1758           writer->write( tr( "CONNECTIVITY" ), tr( "FREE_NODE" ) );
1759         }
1760       }
1761       // - position
1762       ok = proxy().nodePosition( id, position );
1763       if ( ok && position.isValid() )
1764       {
1765         writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
1766         writer->indent();
1767         if ( position.hasU() )
1768           writer->write( tr("U_POSITION"), position.u() );
1769         if ( position.hasV() )
1770           writer->write( tr("V_POSITION"), position.v() );
1771         writer->unindent();
1772       }
1773       // - groups node belongs to
1774       QList<SMESH::SelectionProxy> groups = proxy().nodeGroups( id );
1775       bool topCreated = false;
1776       foreach( SMESH::SelectionProxy group, groups )
1777       {
1778         if ( group && !group.name().isEmpty() )
1779         {
1780           if ( !topCreated )
1781           {
1782             writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
1783             writer->indent();
1784             topCreated = true;
1785           }
1786           writer->write( group.name().trimmed() ); // trim name
1787           if ( grp_details )
1788           {
1789             writer->indent();
1790             int type = group.type();
1791             if ( type == SMESH::SelectionProxy::GroupStd )
1792             {
1793               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1794             }
1795             else if ( type == SMESH::SelectionProxy::GroupGeom )
1796             {
1797               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1798               writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
1799             }
1800             else if ( type == SMESH::SelectionProxy::GroupFilter )
1801             {
1802               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1803             }
1804             int size = group.size();
1805             if ( size != -1 );
1806             writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
1807             QColor color = group.color();
1808             if ( color.isValid() )
1809               writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
1810             writer->unindent();
1811           }
1812         }
1813       }
1814       if ( topCreated )
1815         writer->unindent();
1816       writer->unindent();
1817     }
1818     else if ( what() == ShowElements )
1819     {
1820       // show element info
1821       // - check that element exists
1822       if ( !proxy().hasElement( id ) )
1823         continue;
1824       // - id & type
1825       int type = proxy().elementType( id );
1826       if  ( type == SMESH::ALL )
1827         continue;
1828       writer->write( type2str( type ), (int)id, true );
1829       writer->indent();
1830       // - geometry type
1831       type = proxy().elementEntityType( id );
1832       writer->write( tr( "TYPE" ), etype2str( type ) );
1833       // - connectivity
1834       if ( type == SMESH::Entity_Polyhedra ||
1835            type == SMESH::Entity_Quad_Polyhedra )
1836       {
1837         int nbNodes;
1838         ok = proxy().perFaceConnectivity( id, connectivity, nbNodes );
1839         if ( ok && !connectivity.isEmpty() )
1840         {
1841           writer->write( tr( "NB_NODES" ), nbNodes );
1842           writer->write( tr( "CONNECTIVITY" ) );
1843           writer->indent();
1844           int nbFaces = connectivity.size();
1845           for ( int iF = 1; iF <= nbFaces; ++iF )
1846           {
1847             QString formatted = formatConnectivity( connectivity, -iF );
1848             writer->write(( type2str( SMDSAbs_Face, 0 ) + " %1 / %2" ).arg( iF ).arg( nbFaces ),
1849                           formatted );
1850           }
1851           writer->unindent();
1852         }
1853       }
1854       else
1855       {
1856         ok = proxy().elementConnectivity( id, connectivity );
1857         if ( ok && !connectivity.isEmpty() )
1858         {
1859           QString formatted = formatConnectivity( connectivity, SMDSAbs_Node );
1860           if ( !formatted.isEmpty() )
1861           {
1862             writer->write( tr( "NB_NODES" ), connectivity[ SMDSAbs_Node ].size() );
1863             writer->write( tr( "CONNECTIVITY" ), formatted ); //todo: TypeRole: ElemConnectivity
1864           }
1865         }
1866       }
1867       // - position
1868       ok = proxy().elementPosition( id, position );
1869       if ( ok && position.isValid() )
1870       {
1871         writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) );
1872       }
1873       // - gravity center
1874       ok = proxy().elementGravityCenter( id, xyz );
1875       if ( ok )
1876       {
1877         writer->write( tr( "GRAVITY_CENTER" ), xyz );
1878       }
1879       // - normal vector
1880       ok = proxy().elementNormal( id, xyz );
1881       if ( ok )
1882       {
1883         writer->write( tr( "NORMAL_VECTOR" ), xyz );
1884       }
1885       // - controls
1886       bool topCreated = false;
1887       for ( int i = SMESH::FT_AspectRatio; i < SMESH::FT_Undefined; i++ )
1888       {
1889         QString ctrlTitle = ctrl2str( i );
1890         if ( ctrlTitle.isEmpty() )
1891           continue;
1892         if ( !topCreated )
1893         {
1894           writer->write( tr( "CONTROLS" ) );
1895           writer->indent();
1896           topCreated = true;
1897         }
1898         double value;
1899         if ( proxy().elementControl( id, i, cprecision, value ) )
1900           writer->write( ctrlTitle, value );
1901       }
1902       if ( topCreated )
1903         writer->unindent();
1904       // - groups element belongs to
1905       QList<SMESH::SelectionProxy> groups = proxy().elementGroups( id );
1906       topCreated = false;
1907       foreach( SMESH::SelectionProxy group, groups )
1908       {
1909         if ( group && !group.name().isEmpty() )
1910         {
1911           if ( !topCreated )
1912           {
1913             writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) );
1914             writer->indent();
1915             topCreated = true;
1916           }
1917           writer->write( group.name().trimmed() ); // trim name
1918           if ( grp_details )
1919           {
1920             writer->indent();
1921             int type = group.type();
1922             if ( type == SMESH::SelectionProxy::GroupStd )
1923             {
1924               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) );
1925             }
1926             else if ( type == SMESH::SelectionProxy::GroupGeom )
1927             {
1928               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) );
1929               writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() );
1930             }
1931             else if ( type == SMESH::SelectionProxy::GroupFilter )
1932             {
1933               writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) );
1934             }
1935             int size = group.size();
1936             if ( size != -1 );
1937               writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size );
1938             QColor color = group.color();
1939             if ( color.isValid() )
1940               writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() );
1941             writer->unindent();
1942           }
1943         }
1944       }
1945       if ( topCreated )
1946         writer->unindent();
1947       writer->unindent();
1948     }
1949   }  
1950 }
1951
1952 /*!
1953   \fn void SMESHGUI_ElemInfo::information( const QList<uint>& ids )
1954   \brief Show information on given mesh nodes / elements.
1955
1956   This function has to be redefined in sub-classes.
1957
1958   \param ids Nodes / elements IDs.
1959 */
1960
1961 /*!
1962   \brief Internal clean-up (reset panel).
1963
1964   Default implementation does nothing; the method has to be redefined
1965   in sub-classes to perform internal clean-up.
1966 */
1967 void SMESHGUI_ElemInfo::clearInternal()
1968 {
1969 }
1970
1971 /*!
1972   \brief Show previous chunk of information.
1973 */
1974 void SMESHGUI_ElemInfo::showPrevious()
1975 {
1976   myIndex = qMax( 0, myIndex-1 );
1977   updateControls();
1978   information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
1979 }
1980
1981 /*!
1982   \brief Show next chunk of information.
1983 */
1984 void SMESHGUI_ElemInfo::showNext()
1985 {
1986   myIndex = qMin( myIndex+1, myIDs.count() / blockSize() );
1987   updateControls();
1988   information( myIDs.mid( myIndex*blockSize(), blockSize() ) );
1989 }
1990
1991 /*!
1992   \brief Update control widget state.
1993 */
1994 void SMESHGUI_ElemInfo::updateControls()
1995 {
1996   myExtra->updateControls( myIDs.count(), myIndex );
1997 }
1998
1999 /*!
2000   \brief Write information from panel to ouput stream.
2001   \param out Text stream output.
2002 */
2003 void SMESHGUI_ElemInfo::saveInfo( QTextStream &out )
2004 {
2005   // title
2006   QString title = tr( "ELEM_INFO" );
2007   out << ruler( title.size() ) << endl;
2008   out << title << endl;
2009   out << ruler( title.size() ) << endl;
2010   //  out << endl;
2011
2012   // info
2013   StreamWriter writer( out );
2014   writeInfo( &writer, myIDs );
2015   out << endl;
2016 }
2017
2018 ////////////////////////////////////////////////////////////////////////////////
2019 /// \class SMESHGUI_SimpleElemInfo
2020 /// \brief Show mesh element information in the simple text area.
2021 ////////////////////////////////////////////////////////////////////////////////
2022
2023 /*!
2024   \brief Constructor.
2025   \param parent Parent widget. Defaults to 0.
2026 */
2027 SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent )
2028   : SMESHGUI_ElemInfo( parent )
2029 {
2030   myInfo = new QTextBrowser( centralWidget() );
2031   QVBoxLayout* l = new QVBoxLayout( centralWidget() );
2032   l->setMargin( 0 );
2033   l->addWidget( myInfo );
2034
2035   connect( myInfo, SIGNAL( anchorClicked(QUrl)), this, SLOT( connectivityClicked( QUrl )));
2036 }
2037
2038 /*!
2039   \brief Show mesh element information.
2040   \param ids Nodes / elements IDs.
2041 */
2042 void SMESHGUI_SimpleElemInfo::information( const QList<uint>& ids )
2043 {
2044   clearInternal();
2045   TextWriter writer( myInfo );
2046   writeInfo( &writer, ids );
2047 }
2048
2049 /*!
2050   \brief Internal clean-up (reset widget)
2051 */
2052 void SMESHGUI_SimpleElemInfo::clearInternal()
2053 {
2054   myInfo->clear();
2055 }
2056
2057 void SMESHGUI_SimpleElemInfo::connectivityClicked(const QUrl & url)
2058 {
2059   int type = ( url.scheme()[0] == 'n' ) ? NodeConnectivity : ElemConnectivity;
2060   QString ids = url.path(); // excess chars will be filtered off by SMESHGUI_IdValidator
2061   emit( itemInfo( type, ids ));
2062 }
2063
2064 ////////////////////////////////////////////////////////////////////////////////
2065 /// \class SMESHGUI_TreeElemInfo::ItemDelegate
2066 /// \brief Item delegate for tree mesh info widget.
2067 /// \internal
2068 ////////////////////////////////////////////////////////////////////////////////
2069
2070 class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate
2071 {
2072 public:
2073   ItemDelegate( QObject* );
2074   QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
2075 };
2076
2077 /*!
2078   \brief Constructor.
2079   \internal
2080 */
2081 SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ): QItemDelegate( parent )
2082 {
2083 }
2084
2085 /*!
2086   \brief Redefined from QItemDelegate.
2087   \internal
2088 */
2089 QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
2090 {
2091   QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index );
2092   if ( qobject_cast<QLineEdit*>( w ) )
2093     qobject_cast<QLineEdit*>( w )->setReadOnly( true );
2094   return w;
2095 }
2096
2097 ////////////////////////////////////////////////////////////////////////////////
2098 /// \class SMESHGUI_TreeElemInfo::ItemCreator
2099 /// \brief Item creator for tree mesh info widget.
2100 /// \internal
2101 ////////////////////////////////////////////////////////////////////////////////
2102
2103 class SMESHGUI_TreeElemInfo::ItemCreator : public TreeItemCreator
2104 {
2105   SMESHGUI_TreeElemInfo* myView;
2106 public:
2107   ItemCreator( SMESHGUI_TreeElemInfo* );
2108   QTreeWidgetItem* createItem( QTreeWidgetItem*, int );
2109 };
2110
2111 /*!
2112   \brief Constructor.
2113   \param view Parent view.
2114   \internal
2115 */
2116 SMESHGUI_TreeElemInfo::ItemCreator::ItemCreator( SMESHGUI_TreeElemInfo* view ): TreeItemCreator(), myView( view )
2117 {
2118 }
2119
2120 /*!
2121   \brief Create new tree item.
2122   \param parent Parent tree item.
2123   \param options Item options.
2124   \return New tree widget item.
2125   \internal
2126 */
2127 QTreeWidgetItem* SMESHGUI_TreeElemInfo::ItemCreator::createItem( QTreeWidgetItem* parent, int options )
2128 {
2129   return myView->createItem( parent, options );
2130 }
2131
2132 ////////////////////////////////////////////////////////////////////////////////
2133 /// \class SMESHGUI_TreeElemInfo
2134 /// \brief Show mesh element information as the tree.
2135 ////////////////////////////////////////////////////////////////////////////////
2136
2137 /*!
2138   \brief Constructor.
2139   \param parent Parent widget. Defaults to 0.
2140 */
2141 SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent )
2142   : SMESHGUI_ElemInfo( parent )
2143 {
2144   myInfo = new QTreeWidget( centralWidget() );
2145   myInfo->setColumnCount( 2 );
2146   myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) );
2147   myInfo->header()->setStretchLastSection( true );
2148 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
2149   myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2150 #else
2151   myInfo->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2152 #endif
2153   myInfo->setItemDelegate( new ItemDelegate( myInfo ) );
2154   QVBoxLayout* l = new QVBoxLayout( centralWidget() );
2155   l->setMargin( 0 );
2156   l->addWidget( myInfo );
2157   connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) );
2158   connect( myInfo, SIGNAL( itemCollapsed( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
2159   connect( myInfo, SIGNAL( itemExpanded( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) );
2160 }
2161
2162 /*!
2163   \brief Show mesh element information.
2164   \param ids Nodes / elements IDs.
2165 */
2166 void SMESHGUI_TreeElemInfo::information( const QList<uint>& ids )
2167 {
2168   clearInternal();
2169   TreeWriter writer( myInfo, new ItemCreator( this ) );
2170   writeInfo( &writer, ids );
2171 }
2172
2173 /*!
2174   \brief Show node information
2175   \param node mesh node for showing
2176   \param index index of current node
2177   \param nbNodes number of unique nodes in element
2178   \param parentItem parent item of tree
2179 */
2180 void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* node, int index,
2181                                       int nbNodes, QTreeWidgetItem* parentItem )
2182 {
2183   // int precision   = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 );
2184   // // node number and ID
2185   // QTreeWidgetItem* nodeItem = createItem( parentItem, Bold );
2186   // nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( index ).arg( nbNodes ));
2187   // nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ));
2188   // nodeItem->setData( 1, TypeRole, ElemConnectivity );
2189   // nodeItem->setData( 1, IdRole, node->GetID() );
2190   // nodeItem->setExpanded( false );
2191   // // node coordinates
2192   // QTreeWidgetItem* coordItem = createItem( nodeItem );
2193   // coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" ));
2194   // QTreeWidgetItem* xItem = createItem( coordItem );
2195   // xItem->setText( 0, "X" );
2196   // xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2197   // QTreeWidgetItem* yItem = createItem( coordItem );
2198   // yItem->setText( 0, "Y" );
2199   // yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2200   // QTreeWidgetItem* zItem = createItem( coordItem );
2201   // zItem->setText( 0, "Z" );
2202   // zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) );
2203   // // node connectivity
2204   // QTreeWidgetItem* nconItem = createItem( nodeItem );
2205   // nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" ));
2206   // Connectivity connectivity = nodeConnectivity( node );
2207   // if ( !connectivity.isEmpty() ) {
2208   //   QString con = formatConnectivity( connectivity, SMDSAbs_0DElement );
2209   //   if ( !con.isEmpty() ) {
2210   //     QTreeWidgetItem* i = createItem( nconItem );
2211   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" ));
2212   //     i->setText( 1, con );
2213   //   }
2214   //   con = formatConnectivity( connectivity, SMDSAbs_Edge );
2215   //   if ( !con.isEmpty() ) {
2216   //     QTreeWidgetItem* i = createItem( nconItem );
2217   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" ));
2218   //     i->setText( 1, con );
2219   //     i->setData( 1, TypeRole, NodeConnectivity );
2220   //   }
2221   //   con = formatConnectivity( connectivity, SMDSAbs_Ball );
2222   //   if ( !con.isEmpty() ) {
2223   //     QTreeWidgetItem* i = createItem( nconItem );
2224   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" ));
2225   //     i->setText( 1, con );
2226   //     i->setData( 1, TypeRole, NodeConnectivity );
2227   //   }
2228   //   con = formatConnectivity( connectivity, SMDSAbs_Face );
2229   //   if ( !con.isEmpty() ) {
2230   //     QTreeWidgetItem* i = createItem( nconItem );
2231   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" ));
2232   //     i->setText( 1, con );
2233   //     i->setData( 1, TypeRole, NodeConnectivity );
2234   //   }
2235   //   con = formatConnectivity( connectivity, SMDSAbs_Volume );
2236   //   if ( !con.isEmpty() ) {
2237   //     QTreeWidgetItem* i = createItem( nconItem );
2238   //     i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" ));
2239   //     i->setText( 1, con );
2240   //     i->setData( 1, TypeRole, NodeConnectivity );
2241   //   }
2242   // }
2243 }
2244 /*!
2245   \brief Internal clean-up (reset widget)
2246 */
2247 void SMESHGUI_TreeElemInfo::clearInternal()
2248 {
2249   myInfo->clear();
2250   myInfo->repaint();
2251 }
2252
2253 /*!
2254   \brief Create new item and add it to the tree.
2255   \param parent Parent tree widget item. Defaults to 0 (top-level item).
2256   \param options Item flags. Defaults to 0 (none).
2257   \return New tree widget item.
2258 */
2259 QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int options )
2260 {
2261   QTreeWidgetItem* item = new QTreeWidgetItem( parent ? parent : myInfo->invisibleRootItem() );
2262   setTreeItemAttributes( item, options | Expanded | Editable );
2263
2264   if ( parent && parent->childCount() == 1 && itemDepth( parent ) == 1 )
2265   {
2266     QString resName = expandedResource( parent );
2267     parent->setExpanded( SMESHGUI::resourceMgr()->booleanValue("SMESH", resName, true ));
2268   }
2269   
2270   return item;
2271 }
2272
2273 void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e )
2274 {
2275   QList< QTreeWidgetItem* > widgets = myInfo->selectedItems();
2276   if ( widgets.isEmpty() ) return;
2277   QTreeWidgetItem* aTreeItem = widgets.first();
2278   int type = aTreeItem->data( 1, TypeRole ).toInt();
2279   if (( type == ElemConnectivity || type == NodeConnectivity ) &&
2280       ( !aTreeItem->text( 1 ).isEmpty() ))
2281   {
2282     QMenu menu;
2283     QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" ));
2284     if ( menu.exec( e->globalPos() ) == a )
2285       emit( itemInfo( type, aTreeItem->text( 1 )) );
2286   }
2287 }
2288
2289 void SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn )
2290 {
2291   if ( theItem ) {
2292     int type = theItem->data( 1, TypeRole ).toInt();
2293     emit( itemInfo( type, theItem->text( 1 )) );
2294   }
2295 }
2296
2297 void SMESHGUI_TreeElemInfo::saveExpanded( QTreeWidgetItem* theItem )
2298 {
2299   if ( theItem )
2300     SMESHGUI::resourceMgr()->setValue("SMESH", expandedResource( theItem ), theItem->isExpanded() );
2301 }
2302
2303 QString SMESHGUI_TreeElemInfo::expandedResource( QTreeWidgetItem* theItem )
2304 {
2305   return QString("Expanded_") + ( what()==ShowElements ? "E_" : "N_" ) + theItem->text(0);
2306 }
2307
2308 ////////////////////////////////////////////////////////////////////////////////
2309 /// \class InfoComputor
2310 /// \brief Mesh information computor.
2311 /// \internal
2312 ///
2313 /// The class is created for different computation operations. Currently it is
2314 /// used to compute size and number of underlying nodes for given group.
2315 ////////////////////////////////////////////////////////////////////////////////
2316
2317 /*!
2318   \brief Constructor.
2319   \param parent Parent object.
2320   \param proxy Object to compute information on (group).
2321   \param item Tree widget item, referenced by this computer.
2322   \param operation Value to compute.
2323   \internal
2324 */
2325 InfoComputor::InfoComputor( QObject* parent, const SMESH::SelectionProxy& proxy, int operation )
2326   : QObject( parent ), myProxy( proxy ), myOperation( operation )
2327 {
2328 }
2329
2330 /*!
2331   \brief Compute requested information.
2332   \internal
2333 */
2334 void InfoComputor::compute()
2335 {
2336   if ( myProxy )
2337   {
2338     SUIT_OverrideCursor wc;
2339     switch ( myOperation )
2340     {
2341     case GrpSize:
2342       myProxy.size( true ); // force size computation
2343       emit computed();
2344       break;
2345     case GrpNbNodes:
2346       myProxy.nbNodes( true ); // force size computation
2347       emit computed();
2348       break;
2349     default:
2350       break;
2351     }
2352   }
2353 }
2354
2355 ////////////////////////////////////////////////////////////////////////////////
2356 /// \class SMESHGUI_AddInfo
2357 /// \brief Show additional information on selected object.
2358 ///
2359 /// Displays an additional information about selected object: mesh, sub-mesh
2360 /// or group.
2361 ///
2362 /// \todo Rewrite saveInfo() method to print all data, not currently shown only.
2363 ////////////////////////////////////////////////////////////////////////////////
2364
2365 /*!
2366   \brief Constructor.
2367   \param parent Parent widget. Defaults to 0.
2368 */
2369 SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent ): SMESHGUI_Info( parent )
2370 {
2371   QVBoxLayout* l = new QVBoxLayout( this );
2372   l->setMargin( 0 );
2373   l->setSpacing( SPACING );
2374
2375   myTree = new QTreeWidget( this );
2376
2377   myTree->setColumnCount( 2 );
2378   myTree->header()->setStretchLastSection( true );
2379 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
2380   myTree->header()->setResizeMode( 0, QHeaderView::ResizeToContents );
2381 #else
2382   myTree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
2383 #endif
2384   myTree->header()->hide();
2385
2386   l->addWidget( myTree );
2387 }
2388
2389 /*!
2390   \brief Destructor.
2391 */
2392 SMESHGUI_AddInfo::~SMESHGUI_AddInfo()
2393 {
2394 }
2395
2396 /*!
2397   \brief Show information on given object.
2398   \param proxy Object to show information on (mesh, sub-mesh, group).
2399 */
2400 void SMESHGUI_AddInfo::showInfo( const SMESH::SelectionProxy& proxy )
2401 {
2402   // reset panel
2403   setProperty( "group_index", 0 );
2404   setProperty( "submesh_index",  0 );
2405   myComputors.clear();
2406   myTree->clear();
2407
2408   // then fill panel with data if object is not null
2409   if ( proxy )
2410   {
2411     myProxy = proxy;
2412
2413     // name
2414     QTreeWidgetItem* nameItem = createItem( 0, Bold | AllColumns );
2415     nameItem->setText( 0, tr( "NAME" ) );
2416     nameItem->setText( 1, proxy.name() );
2417
2418     // object info
2419     if ( proxy.type() == SMESH::SelectionProxy::Mesh )
2420       meshInfo( proxy, nameItem );
2421     else if ( proxy.type() == SMESH::SelectionProxy::Submesh )
2422       subMeshInfo( proxy, nameItem );
2423     else if ( proxy.type() >= SMESH::SelectionProxy::Group )
2424       groupInfo( proxy, nameItem );
2425   }
2426 }
2427
2428 /*!
2429   \brief Update information in panel.
2430 */
2431 void SMESHGUI_AddInfo::updateInfo()
2432 {
2433   showInfo( myProxy );
2434 }
2435
2436 /*!
2437   \brief Reset panel (clear all data).
2438 */
2439 void SMESHGUI_AddInfo::clear()
2440 {
2441   myTree->clear();
2442 }
2443
2444 /*!
2445   \brief Create new item and add it to the tree.
2446   \param parent Parent tree widget item. Defaults to 0 (top-level item).
2447   \param options Item flags. Defaults to 0 (none).
2448   \return New tree widget item.
2449 */
2450 QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int options )
2451 {
2452   QTreeWidgetItem* item = parent ? new QTreeWidgetItem( parent ) : 
2453     new QTreeWidgetItem( myTree->invisibleRootItem() );
2454   setTreeItemAttributes( item, options | Expanded );
2455   return item;
2456 }
2457
2458 /*!
2459   \brief Show information on mesh.
2460   \param proxy Proxy object (mesh).
2461   \param parent Parent tree item.
2462 */
2463 void SMESHGUI_AddInfo::meshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2464 {
2465   if ( !proxy )
2466     return;
2467
2468   QString shapeName = proxy.shapeName();
2469   SMESH::MedInfo inf = proxy.medFileInfo();
2470
2471   // type
2472   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2473   typeItem->setText( 0, tr( "TYPE" ) );
2474   if ( !shapeName.isEmpty() )
2475   {
2476     typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) );
2477     // shape
2478     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2479     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2480     gobjItem->setText( 1, shapeName );
2481   }
2482   else if ( inf.isValid() )
2483   {
2484     typeItem->setText( 1, tr( "MESH_FROM_FILE" ) );
2485     // med file information
2486     QTreeWidgetItem* fileItem = createItem( parent, Bold );
2487     fileItem->setText( 0, tr( "FILE_NAME" ) );
2488     fileItem->setText( 1, inf.fileName() );
2489     QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2490     sizeItem->setText( 0, tr( "FILE_SIZE" ) );
2491     sizeItem->setText( 1, QString::number( inf.size() ) );
2492     QTreeWidgetItem* versionItem = createItem( parent, Bold );
2493     versionItem->setText( 0, tr( "FILE_VERSION" ) );
2494     versionItem->setText( 1, inf.version() != "0" ? inf.version() : tr( "VERSION_UNKNOWN" ) );
2495   }
2496   else
2497   {
2498     typeItem->setText( 1, tr( "STANDALONE_MESH" ) );
2499   }
2500   
2501   // groups
2502   myGroups = proxy.groups();
2503   showGroups();
2504
2505   // sub-meshes
2506   mySubMeshes = proxy.submeshes();
2507   showSubMeshes();
2508 }
2509
2510 /*!
2511   \brief Show information on sub-mesh.
2512   \param proxy Proxy object (sub-mesh).
2513   \param parent Parent tree item.
2514 */
2515 void SMESHGUI_AddInfo::subMeshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2516 {
2517   if ( !proxy )
2518     return;
2519
2520   bool isShort = parent->parent() != 0;
2521
2522   if ( !isShort )
2523   {
2524     // parent mesh
2525     SMESH::SelectionProxy meshProxy = proxy.mesh();
2526     if ( meshProxy )
2527     {
2528       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2529       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2530       nameItem->setText( 1, meshProxy.name() );
2531     }
2532   }
2533   
2534   // shape
2535   QString shapeName = proxy.shapeName();
2536   if ( !shapeName.isEmpty() )
2537   {
2538     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2539     gobjItem->setText( 1, shapeName );
2540   }
2541 }
2542
2543 /*!
2544   \brief Show information on group.
2545   \param proxy Proxy object (group).
2546   \param parent Parent tree item.
2547 */
2548 void SMESHGUI_AddInfo::groupInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent )
2549 {
2550   if ( !proxy )
2551     return;
2552
2553   bool isShort = parent->parent() != 0;
2554
2555   if ( !isShort )
2556   {
2557     // parent mesh
2558     SMESH::SelectionProxy meshProxy = proxy.mesh();
2559     if ( meshProxy )
2560     {
2561       QTreeWidgetItem* nameItem = createItem( parent, Bold );
2562       nameItem->setText( 0, tr( "PARENT_MESH" ) );
2563       nameItem->setText( 1, meshProxy.name() );
2564     }
2565   }
2566
2567   // type
2568   SMESH::SelectionProxy::Type type = proxy.type();
2569   QTreeWidgetItem* typeItem = createItem( parent, Bold );
2570   typeItem->setText( 0, tr( "TYPE" ) );
2571   if ( type == SMESH::SelectionProxy::GroupStd )
2572   {
2573     typeItem->setText( 1, tr( "STANDALONE_GROUP" ) );
2574   }
2575   else if ( type == SMESH::SelectionProxy::GroupGeom )
2576   {
2577     typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) );
2578     // shape
2579     QTreeWidgetItem* gobjItem = createItem( parent, Bold );
2580     gobjItem->setText( 0, tr( "GEOM_OBJECT" ) );
2581     gobjItem->setText( 1, proxy.shapeName() );
2582   }
2583   else if ( type == SMESH::SelectionProxy::GroupFilter )
2584   {
2585     typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) );
2586   }
2587
2588   // element type
2589   int etype = proxy.groupElementType();
2590   if ( !isShort )
2591   {
2592     QString typeName = tr( "UNKNOWN" );
2593     switch( etype )
2594     {
2595     case SMESH::NODE:
2596       typeName = tr( "NODE" );
2597       break;
2598     case SMESH::EDGE:
2599       typeName = tr( "EDGE" );
2600       break;
2601     case SMESH::FACE:
2602       typeName = tr( "FACE" );
2603       break;
2604     case SMESH::VOLUME:
2605       typeName = tr( "VOLUME" );
2606       break;
2607     case SMESH::ELEM0D:
2608       typeName = tr( "0DELEM" );
2609       break;
2610     case SMESH::BALL:
2611       typeName = tr( "BALL" );
2612       break;
2613     default:
2614       break;
2615     }
2616     QTreeWidgetItem* etypeItem = createItem( parent, Bold );
2617     etypeItem->setText( 0, tr( "ENTITY_TYPE" ) );
2618     etypeItem->setText( 1, typeName );
2619   }
2620
2621   // size
2622   // note: size is not computed for group on filter for performance reasons, see IPAL52831
2623   bool meshLoaded = proxy.isMeshLoaded();
2624   int size = proxy.size();
2625
2626   QTreeWidgetItem* sizeItem = createItem( parent, Bold );
2627   sizeItem->setText( 0, tr( "SIZE" ) );
2628   if ( size >= 0 )
2629   {
2630     sizeItem->setText( 1, QString::number( size ) );
2631   }
2632   else
2633   {
2634     QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
2635     myTree->setItemWidget( sizeItem, 1, btn );
2636     InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpSize );
2637     connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2638     connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
2639     myComputors.append( comp );
2640   }
2641
2642   // color
2643   QTreeWidgetItem* colorItem = createItem( parent, Bold );
2644   colorItem->setText( 0, tr( "COLOR" ) );
2645   colorItem->setBackground( 1, proxy.color() );
2646
2647   // nb of underlying nodes
2648   if ( etype != SMESH::NODE )
2649   {
2650     QTreeWidgetItem* nodesItem = createItem( parent, Bold );
2651     nodesItem->setText( 0, tr( "NB_NODES" ) );
2652
2653     int nbNodes = proxy.nbNodes();
2654     if ( nbNodes >= 0 )
2655     {
2656       nodesItem->setText( 1, QString::number( nbNodes ) );
2657     }
2658     else
2659     {
2660       QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this );
2661       myTree->setItemWidget( nodesItem, 1, btn );
2662       InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpNbNodes ); 
2663       connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) );
2664       connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) );
2665       myComputors.append( comp );
2666     }
2667   }
2668 }
2669
2670 /*!
2671   \brief Update information on child groups.
2672 */
2673 void SMESHGUI_AddInfo::showGroups()
2674 {
2675   // remove all computors
2676   myComputors.clear();
2677
2678   // tree root should be the first top level item
2679   QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
2680   if ( !parent )
2681     return;
2682
2683   int idx = property( "group_index" ).toInt();
2684
2685   // find sub-meshes top-level container item
2686   QTreeWidgetItem* itemGroups = 0;
2687   for ( int i = 0; i < parent->childCount() && !itemGroups; i++ )
2688   {
2689     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GroupsId )
2690     {
2691       itemGroups = parent->child( i );
2692       // update controls
2693       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemGroups, 1 ) );
2694       if ( extra )
2695         extra->updateControls( myGroups.count(), idx );
2696       // clear: remove all group items
2697       while ( itemGroups->childCount() )
2698         delete itemGroups->child( 0 );
2699     }
2700   }
2701
2702   QMap<int, QTreeWidgetItem*> grpItems;
2703   for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), (int)myGroups.count() ); i++ )
2704   {
2705     SMESH::SelectionProxy grp = myGroups[i];
2706     if ( !grp )
2707       continue;
2708
2709     int grpType = grp.groupElementType();
2710
2711     // create top-level groups container item if it does not exist
2712     if ( !itemGroups )
2713     {
2714       itemGroups = createItem( parent, Bold | AllColumns );
2715       itemGroups->setText( 0, tr( "GROUPS" ) );
2716       itemGroups->setData( 0, Qt::UserRole, GroupsId );
2717
2718       // if necessary, create extra widget to show information by chunks
2719       if ( myGroups.count() > blockSize() )
2720       {
2721         ExtraWidget* extra = new ExtraWidget( this, true );
2722         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) );
2723         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) );
2724         myTree->setItemWidget( itemGroups, 1, extra );
2725         extra->updateControls( myGroups.count(), idx );
2726       }
2727     }
2728
2729     // create container item corresponding to particular element type
2730     if ( !grpItems.contains( grpType ) )
2731     {
2732       grpItems[ grpType ] = createItem( itemGroups, Bold | AllColumns );
2733       grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) );
2734       itemGroups->insertChild( grpType-1, grpItems[ grpType ] ); // -1 needed since 0 corresponds to SMESH::ALL
2735     }
2736   
2737     // name
2738     QTreeWidgetItem* nameItem = createItem( grpItems[ grpType ] );
2739     nameItem->setText( 0, grp.name().trimmed() ); // trim name
2740
2741     // group info
2742     groupInfo( grp, nameItem );
2743   }
2744 }
2745
2746 /*!
2747   \brief Update information on child sub-meshes.
2748 */
2749 void SMESHGUI_AddInfo::showSubMeshes()
2750 {
2751   // tree root should be the first top level item
2752   QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0;
2753   if ( !parent )
2754     return;
2755
2756   int idx = property( "submesh_index" ).toInt();
2757
2758   // find sub-meshes top-level container item
2759   QTreeWidgetItem* itemSubMeshes = 0;
2760   for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ )
2761   {
2762     if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SubMeshesId )
2763     {
2764       itemSubMeshes = parent->child( i );
2765       // update controls
2766       ExtraWidget* extra = dynamic_cast<ExtraWidget*>( myTree->itemWidget( itemSubMeshes, 1 ) );
2767       if ( extra )
2768         extra->updateControls( mySubMeshes.count(), idx );
2769       // clear: remove all sub-mesh items
2770       while ( itemSubMeshes->childCount() )
2771         delete itemSubMeshes->child( 0 );
2772     }
2773   }
2774
2775   QMap<int, QTreeWidgetItem*> smItems;
2776   for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), mySubMeshes.count() ); i++ )
2777   {
2778     SMESH::SelectionProxy sm = mySubMeshes[i];
2779     if ( !sm )
2780       continue;
2781     
2782     int smType = sm.shapeType();
2783     if ( smType < 0 )
2784       continue;
2785     else if ( smType == GEOM::COMPSOLID )
2786       smType = GEOM::COMPOUND;
2787
2788     // create top-level sub-meshes container item if it does not exist
2789     if ( !itemSubMeshes )
2790     {
2791       itemSubMeshes = createItem( parent, Bold | AllColumns );
2792       itemSubMeshes->setText( 0, tr( "SUBMESHES" ) );
2793       itemSubMeshes->setData( 0, Qt::UserRole, SubMeshesId );
2794
2795       // if necessary, create extra widget to show information by chunks
2796       if ( mySubMeshes.count() > blockSize() )
2797       {
2798         ExtraWidget* extra = new ExtraWidget( this, true );
2799         connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) );
2800         connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) );
2801         myTree->setItemWidget( itemSubMeshes, 1, extra );
2802         extra->updateControls( mySubMeshes.count(), idx );
2803       }
2804     }
2805
2806     // create container item corresponding to particular shape type
2807     if ( !smItems.contains( smType ) )
2808     {
2809       smItems[ smType ] = createItem( itemSubMeshes, Bold | AllColumns );
2810       smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) );
2811       itemSubMeshes->insertChild( smType, smItems[ smType ] );
2812     }
2813     
2814     // name
2815     QTreeWidgetItem* nameItem = createItem( smItems[ smType ] );
2816     nameItem->setText( 0, sm.name().trimmed() ); // trim name
2817     
2818     // submesh info
2819     subMeshInfo( sm, nameItem );
2820   }
2821 }
2822
2823 /*!
2824   \brief Show previous chunk of information on child groups.
2825 */
2826 void SMESHGUI_AddInfo::showPreviousGroups()
2827 {
2828   int idx = property( "group_index" ).toInt();
2829   setProperty( "group_index", idx-1 );
2830   showGroups();
2831 }
2832
2833 /*!
2834   \brief Show next chunk of information on child groups.
2835 */
2836 void SMESHGUI_AddInfo::showNextGroups()
2837 {
2838   int idx = property( "group_index" ).toInt();
2839   setProperty( "group_index", idx+1 );
2840   showGroups();
2841 }
2842
2843 /*!
2844   \brief Show previous chunk of information on child sub-meshes.
2845 */
2846 void SMESHGUI_AddInfo::showPreviousSubMeshes()
2847 {
2848   int idx = property( "submesh_index" ).toInt();
2849   setProperty( "submesh_index", idx-1 );
2850   showSubMeshes();
2851 }
2852
2853 /*!
2854   \brief Show next chunk of information on child sub-meshes.
2855 */
2856 void SMESHGUI_AddInfo::showNextSubMeshes()
2857 {
2858   int idx = property( "submesh_index" ).toInt();
2859   setProperty( "submesh_index", idx+1 );
2860   showSubMeshes();
2861 }
2862
2863 /*!
2864   \brief Write information from panel to ouput stream.
2865   \param out Text stream output.
2866 */
2867 void SMESHGUI_AddInfo::saveInfo( QTextStream &out )
2868 {
2869   // title
2870   QString title = tr( "ADDITIONAL_INFO" );
2871   out << ruler( title.size() ) << endl;
2872   out << title << endl;
2873   out << ruler( title.size() ) << endl;
2874   out << endl;
2875
2876   // info
2877   QTreeWidgetItemIterator it( myTree );
2878   while ( *it )
2879   {
2880     if ( !( ( *it )->text(0) ).isEmpty() )
2881     {
2882       out << indent( itemDepth( *it ) ) << ( *it )->text(0);
2883       if ( ( *it )->text(0)  == tr( "COLOR" ) )
2884         out << ":" << spacing() << ( ( ( *it )->background(1) ).color() ).name();
2885       else if ( !( ( *it )->text(1) ).isEmpty() )
2886         out << ":" << spacing() << ( *it )->text(1);
2887       out << endl;
2888     }
2889     ++it;
2890   }
2891   out << endl;
2892 }
2893
2894 ////////////////////////////////////////////////////////////////////////////////
2895 /// \class GroupCombo
2896 /// \brief Customized combo box to manage list of mesh groups.
2897 /// \internal
2898 ////////////////////////////////////////////////////////////////////////////////
2899
2900 class GroupCombo: public QComboBox
2901 {
2902   class Item: public QStandardItem
2903   {
2904   public:
2905     SMESH::SelectionProxy myGroup;
2906     Item( const SMESH::SelectionProxy& group )
2907     {
2908       myGroup = group;
2909       setText( myGroup.name() );
2910     }
2911     SMESH::SelectionProxy group()
2912     {
2913       return myGroup;
2914     }
2915   };
2916
2917   SMESH::SelectionProxy myProxy;
2918
2919 public:
2920   GroupCombo( QWidget* );
2921   void setSource( const SMESH::SelectionProxy& );
2922   SMESH::SelectionProxy currentGroup() const;
2923 };
2924
2925 /*!
2926   \brief Contructor.
2927   \param parent Parent widget.
2928   \internal
2929 */
2930 GroupCombo::GroupCombo( QWidget* parent ): QComboBox( parent )
2931 {
2932   setModel( new QStandardItemModel( this ) );
2933 }
2934
2935 /*!
2936   \brief Set mesh source.
2937   \param obj Mesh source.
2938   \internal
2939 */
2940 void GroupCombo::setSource( const SMESH::SelectionProxy& proxy )
2941 {
2942   if ( myProxy == proxy )
2943     return;
2944
2945   myProxy = proxy;
2946
2947   bool blocked = blockSignals( true );
2948   QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
2949   m->clear();
2950
2951   if ( myProxy )
2952   {
2953     if ( myProxy.type() == SMESH::SelectionProxy::Mesh )
2954     {
2955       QList<SMESH::SelectionProxy> groups = myProxy.groups();
2956       for ( int i = 0; i < groups.count(); ++i )
2957       {
2958         if ( groups[i] )
2959         {
2960           QString name = groups[i].name();
2961           if ( !name.isEmpty() )
2962             m->appendRow( new Item( groups[i] ) );
2963         }
2964       }
2965       setCurrentIndex( -1 ); // for performance reasons
2966     }
2967     else if ( myProxy.type() >= SMESH::SelectionProxy::Group )
2968     {
2969       m->appendRow( new Item( myProxy ) );
2970       setCurrentIndex( 0 );
2971     }
2972   }
2973
2974   blockSignals( blocked );
2975 }
2976
2977 /*!
2978   \brief Get currently selected group.
2979   \return Selected group.
2980   \internal
2981 */
2982 SMESH::SelectionProxy GroupCombo::currentGroup() const
2983 {
2984   SMESH::SelectionProxy group;
2985   QStandardItemModel* m = dynamic_cast<QStandardItemModel*>( model() );
2986   if ( currentIndex() >= 0 )
2987     group = dynamic_cast<Item*>( m->item( currentIndex() ) )->group();
2988   return group;
2989 }
2990
2991 ////////////////////////////////////////////////////////////////////////////////
2992 /// \class SMESHGUI_MeshInfoDlg
2993 /// \brief Mesh information dialog box
2994 ///
2995 /// \todo Move all business logic for element info to SMESHGUI_ElemInfo class.
2996 /// \todo Add selection button to reactivate selection on move from other dlg.
2997 ////////////////////////////////////////////////////////////////////////////////
2998
2999 /*!
3000   \brief Constructor
3001   \param parent Parent widget.
3002   \param page Dialog page to show at start-up. Defaults to \c BaseInfo.
3003 */
3004 SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page )
3005   : QDialog( parent )
3006 {
3007   setModal( false );
3008   setAttribute( Qt::WA_DeleteOnClose, true );
3009   setWindowTitle( tr( "MESH_INFO" ) );
3010   setSizeGripEnabled( true );
3011
3012   myTabWidget = new QTabWidget( this );
3013
3014   // base info
3015
3016   myBaseInfo = new SMESHGUI_BaseInfo( myTabWidget );
3017   myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) );
3018
3019   // elem info 
3020
3021   QWidget* w = new QWidget( myTabWidget );
3022
3023   myMode = new QButtonGroup( this );
3024   myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode );
3025   myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode );
3026   myMode->addButton( new QRadioButton( tr( "GROUP_MODE" ), w ), GroupMode );
3027   myMode->button( NodeMode )->setChecked( true );
3028   myID = new QLineEdit( w );
3029   myID->setValidator( new SMESHGUI_IdValidator( this ) );
3030   myGroups = new GroupCombo( w );
3031   QStackedWidget* stack = new QStackedWidget( w );
3032   stack->addWidget( myID );
3033   stack->addWidget( myGroups );
3034   myIDPreviewCheck = new QCheckBox( tr( "SHOW_IDS" ), w );
3035   myIDPreview = new SMESHGUI_IdPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ) );
3036
3037   int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 );
3038   mode = qMin( 1, qMax( 0, mode ) );
3039
3040   if ( mode == 0 )
3041     myElemInfo = new SMESHGUI_SimpleElemInfo( w );
3042   else
3043     myElemInfo = new SMESHGUI_TreeElemInfo( w );
3044   stack->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
3045
3046   QGridLayout* elemLayout = new QGridLayout( w );
3047   elemLayout->setMargin( MARGIN );
3048   elemLayout->setSpacing( SPACING );
3049   elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 );
3050   elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 );
3051   elemLayout->addWidget( myMode->button( GroupMode ), 0, 2 );
3052   elemLayout->addWidget( stack, 0, 3 );
3053   elemLayout->addWidget( myIDPreviewCheck, 1, 0, 1, 4 );
3054   elemLayout->addWidget( myElemInfo, 2, 0, 1, 4 );
3055
3056   myTabWidget->addTab( w, tr( "ELEM_INFO" ) );
3057
3058   // additional info
3059
3060   myAddInfo = new SMESHGUI_AddInfo( myTabWidget );
3061   myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) );
3062
3063   // controls info
3064
3065   myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget );
3066   myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) );
3067
3068   // buttons
3069
3070   QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this );
3071   okBtn->setAutoDefault( true );
3072   okBtn->setDefault( true );
3073   okBtn->setFocus();
3074   QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this );
3075   dumpBtn->setAutoDefault( true );
3076   QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this );
3077   helpBtn->setAutoDefault( true );
3078
3079   QHBoxLayout* btnLayout = new QHBoxLayout;
3080   btnLayout->setSpacing( SPACING );
3081   btnLayout->setMargin( 0 );
3082
3083   btnLayout->addWidget( okBtn );
3084   btnLayout->addWidget( dumpBtn );
3085   btnLayout->addStretch( 10 );
3086   btnLayout->addWidget( helpBtn );
3087
3088   // arrange widgets
3089
3090   QVBoxLayout* l = new QVBoxLayout ( this );
3091   l->setMargin( MARGIN );
3092   l->setSpacing( SPACING );
3093   l->addWidget( myTabWidget );
3094   l->addLayout( btnLayout );
3095
3096   // set initial page
3097
3098   myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) );
3099
3100   // set-up connections
3101
3102   connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
3103   connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) );
3104   connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) );
3105   connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) );
3106   connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) );
3107   connect( myGroups, SIGNAL( currentIndexChanged( int ) ), this, SLOT( modeChanged() ) );
3108   connect( myID, SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) );
3109   connect( myIDPreviewCheck, SIGNAL( toggled( bool ) ), this, SLOT( idPreviewChange( bool ) ) );
3110   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) );
3111   connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) );
3112   connect( myElemInfo, SIGNAL( itemInfo( int, QString ) ), this, SLOT( showItemInfo( int, QString ) ) );
3113   connect( this, SIGNAL( switchMode( int ) ), stack, SLOT( setCurrentIndex( int ) ) );
3114
3115   // initialize
3116
3117   myIDPreviewCheck->setChecked( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "id_preview_resource", false ) );
3118   updateSelection();
3119 }
3120
3121 /*!
3122   \brief Destructor.
3123 */
3124 SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg()
3125 {
3126   delete myIDPreview;
3127 }
3128
3129 /*!
3130   \brief Show mesh information on given object.
3131   \param io Interactive object.
3132 */
3133 void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io )
3134 {
3135   if ( !io.IsNull() )
3136     showInfo( SMESH::SelectionProxy( io ) );
3137 }
3138
3139 /*!
3140   \brief Show mesh information on given object.
3141   \param proxy Selection proxy.
3142 */
3143 void SMESHGUI_MeshInfoDlg::showInfo( const SMESH::SelectionProxy& proxy )
3144 {
3145   SUIT_OverrideCursor wc;
3146
3147   if ( !proxy )
3148     return;
3149
3150   myProxy = proxy;
3151
3152   SMESH::SMESH_IDSource_var obj = myProxy.object();
3153
3154   // "Base info" tab
3155   myBaseInfo->showInfo( proxy );
3156
3157   // "Additional info" tab
3158   myAddInfo->showInfo( proxy );
3159
3160   // "Quality info" tab
3161   // Note: for performance reasons we update it only if it is currently active
3162   if ( myTabWidget->currentIndex() == CtrlInfo )
3163     myCtrlInfo->showInfo( proxy );
3164
3165   // "Element info" tab
3166   myGroups->setSource( proxy );
3167   if ( myMode->checkedId() == GroupMode ) {
3168     SMESH::SelectionProxy group = myGroups->currentGroup();
3169     if ( group )
3170       myElemInfo->showInfo( group );
3171     else
3172       myElemInfo->clear();
3173   }
3174   else {
3175     SVTK_Selector* selector = SMESH::GetSelector();
3176     QString ID;
3177     int nb = 0;
3178     if ( myProxy.actor() && selector ) { //todo: actor()?
3179       nb = myMode->checkedId() == NodeMode ?
3180         SMESH::GetNameOfSelectedElements( selector, myProxy.io(), ID ) :
3181         SMESH::GetNameOfSelectedNodes( selector, myProxy.io(), ID );
3182     }
3183     if ( nb > 0 ) {
3184       myID->setText( ID.trimmed() );
3185       QSet<uint> ids;
3186       QStringList idTxt = ID.split( " ", QString::SkipEmptyParts );
3187       foreach ( ID, idTxt )
3188         ids << ID.trimmed().toUInt();
3189       myElemInfo->showInfo( proxy, ids, myMode->checkedId() == ElemMode );
3190     }
3191     else {
3192       myID->clear();
3193       myElemInfo->clear();
3194     }
3195   }
3196 }
3197
3198 /*!
3199   \brief Update information.
3200 */
3201 void SMESHGUI_MeshInfoDlg::updateInfo()
3202 {
3203   SALOME_ListIO selected;
3204   SMESHGUI::selectionMgr()->selectedObjects( selected );
3205
3206   if ( selected.Extent() == 1 )
3207     showInfo( selected.First() );
3208   else
3209     showInfo( myProxy );
3210 }
3211
3212 /*!
3213   \brief Clean-up on dialog closing.
3214 */
3215 void SMESHGUI_MeshInfoDlg::reject()
3216 {
3217   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3218   selMgr->clearFilters();
3219   SMESH::SetPointRepresentation( false );
3220   if ( SVTK_ViewWindow* viewWindow = SMESH::GetViewWindow() )
3221     viewWindow->SetSelectionMode( ActorSelection );
3222   QDialog::reject();
3223   myIDPreview->SetPointsLabeled( false );
3224 }
3225
3226 /*!
3227   \brief Process keyboard event.
3228   \param e Key press event.
3229 */
3230 void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e )
3231 {
3232   QDialog::keyPressEvent( e );
3233   if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) {
3234     e->accept();
3235     help();
3236   }
3237 }
3238
3239 /*!
3240   \brief Set-up selection mode for currently selected page.
3241 */
3242 void SMESHGUI_MeshInfoDlg::updateSelection()
3243 {
3244   LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr();
3245
3246   disconnect( selMgr, 0, this, 0 );
3247   selMgr->clearFilters();
3248
3249   int selMode = ActorSelection;
3250   if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == NodeMode )
3251     selMode = NodeSelection;
3252   else if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == ElemMode )
3253     selMode = CellSelection;
3254   SMESH::SetPointRepresentation( selMode == NodeSelection );
3255   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3256     aViewWindow->SetSelectionMode( selMode );
3257
3258   SMESH::SelectionProxy previous = myProxy;
3259   QString ids = myID->text().trimmed();
3260   myID->clear();
3261   
3262   connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3263   updateInfo();
3264   
3265   if ( myProxy && myProxy == previous && !ids.isEmpty() ) {
3266     myID->setText( ids );
3267     idChanged();
3268   }
3269 }
3270
3271 /*!
3272   \brief Show documentation on selected dialog page.
3273 */
3274 void SMESHGUI_MeshInfoDlg::help()
3275 {
3276   QString helpPage = "mesh_infos.html";
3277   switch ( myTabWidget->currentIndex() )
3278   {
3279   case BaseInfo:
3280     helpPage += "#advanced-mesh-infos-anchor";
3281     break;
3282   case ElemInfo:
3283     helpPage += "#mesh-element-info-anchor";
3284     break;
3285   case AddInfo:
3286     helpPage += "#mesh-addition-info-anchor";
3287     break;
3288   case CtrlInfo:
3289     helpPage += "#mesh-quality-info-anchor";
3290     break;
3291   default:
3292     break;
3293   }
3294   SMESH::ShowHelpFile( helpPage );
3295 }
3296
3297 /*!
3298   \brief Deactivate dialog box.
3299 */
3300 void SMESHGUI_MeshInfoDlg::deactivate()
3301 {
3302   disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) );
3303 }
3304
3305 /*!
3306   \brief Called when users switches between node / element modes.
3307 */
3308 void SMESHGUI_MeshInfoDlg::modeChanged()
3309 {
3310   emit( switchMode( myMode->checkedId() == GroupMode ? 1 : 0 ) );
3311   myID->clear();
3312   updateSelection();
3313 }
3314
3315 /*!
3316   \brief Called when users prints mesh element ID in the corresponding field.
3317 */
3318 void SMESHGUI_MeshInfoDlg::idChanged()
3319 {
3320   myIDPreview->SetPointsLabeled( false );
3321
3322   if ( myProxy ) {
3323     TColStd_MapOfInteger ID;
3324     QSet<uint>           ids;
3325     std::vector<int>     idVec;
3326     std::list< gp_XYZ >  aGrCentersXYZ;
3327     SMESH::XYZ           xyz;
3328     const bool           isElem = ( myMode->checkedId() == ElemMode );
3329     QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts );
3330     foreach ( QString tid, idTxt ) {
3331       long id = tid.toUInt();
3332       if ( isElem ? myProxy.hasElement( id ) : myProxy.hasNode( id ))
3333       {
3334         ID.Add( id );
3335         ids << id;
3336         if ( isElem && myProxy.actor() && myProxy.elementGravityCenter( id, xyz ))
3337         {
3338           idVec.push_back( id );
3339           aGrCentersXYZ.push_back( xyz );
3340         }
3341       }
3342     }
3343     SVTK_Selector* selector = SMESH::GetSelector();
3344     if ( myProxy.actor() && selector ) {
3345       Handle(SALOME_InteractiveObject) IO = myProxy.actor()->getIO();
3346       selector->AddOrRemoveIndex( IO, ID, false );
3347       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3348       {
3349         if ( myMode->checkedId() == NodeMode )
3350           myIDPreview->SetPointsData( myProxy.actor()->GetObject()->GetMesh(), ID );
3351         else
3352           myIDPreview->SetElemsData( idVec, aGrCentersXYZ );
3353
3354         bool showIDs = ( !ID.IsEmpty() &&
3355                          myIDPreviewCheck->isChecked() &&
3356                          myTabWidget->currentIndex() == ElemInfo );
3357         myIDPreview->SetPointsLabeled( showIDs, myProxy.actor()->GetVisibility() );
3358
3359         aViewWindow->highlight( IO, true, true );
3360         aViewWindow->Repaint();
3361       }
3362     }
3363     myElemInfo->showInfo( myProxy, ids, isElem );
3364   }
3365 }
3366
3367 /*!
3368  * \brief Show IDs clicked
3369  */
3370 void SMESHGUI_MeshInfoDlg::idPreviewChange( bool isOn )
3371 {
3372   myIDPreview->SetPointsLabeled( isOn && !myID->text().simplified().isEmpty() );
3373   SMESHGUI::resourceMgr()->setValue("SMESH", "id_preview_resource", isOn );
3374   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() )
3375     aViewWindow->Repaint();
3376 }
3377
3378 void SMESHGUI_MeshInfoDlg::showItemInfo( int type, const QString& ids )
3379 {
3380   if ( !ids.isEmpty() && ( type == NodeConnectivity || type == ElemConnectivity )) {
3381     myMode->button( type - NodeConnectivity )->click();
3382     myID->setText( ids );
3383   }
3384 }
3385
3386 /*!
3387   \brief Dump information to file.
3388 */
3389 void SMESHGUI_MeshInfoDlg::dump()
3390 {
3391   DumpFileDlg fd( this );
3392   fd.setWindowTitle( tr( "SAVE_INFO" ) );
3393   fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) );
3394   fd.setChecked( BaseInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_base", true ) );
3395   fd.setChecked( ElemInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_elem", true ) );
3396   fd.setChecked( AddInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_add", true ) );
3397   fd.setChecked( CtrlInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_ctrl", true ) );
3398   if ( fd.exec() == QDialog::Accepted )
3399   {
3400     QString fileName = fd.selectedFile();
3401     if ( !fileName.isEmpty() ) {
3402       QFile file( fileName );
3403       if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) )
3404         return;
3405
3406       QTextStream out( &file );
3407       if ( fd.isChecked( BaseInfo ) ) myBaseInfo->saveInfo( out );
3408       if ( fd.isChecked( ElemInfo ) ) myElemInfo->saveInfo( out );
3409       if ( fd.isChecked( AddInfo ) )  myAddInfo->saveInfo( out );
3410       if ( fd.isChecked( CtrlInfo ) ) myCtrlInfo->saveInfo( out );
3411     }
3412   }
3413 }
3414
3415 ////////////////////////////////////////////////////////////////////////////////
3416 /// \class SMESHGUI_CtrlInfo
3417 /// \brief Show quality statistics information on selected object.
3418 ///
3419 /// Displays quality controls statistics about selected object: mesh, sub-mesh,
3420 /// group or arbitrary ID source.
3421 ////////////////////////////////////////////////////////////////////////////////
3422
3423 /*!
3424   \brief Constructor.
3425   \param parent Parent widget. Defaults to 0.
3426 */
3427 SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent ): SMESHGUI_Info( parent )
3428 {
3429   QGridLayout* l = new QGridLayout( this );
3430   l->setMargin( MARGIN );
3431   l->setSpacing( SPACING );
3432
3433   QIcon aComputeIcon( SUIT_Session::session()->resourceMgr()->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) );
3434   SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager();
3435
3436   // name
3437   QLabel* aNameLab = createLabel( tr( "NAME_LAB" ), this, Bold );
3438   QLabel* aName = createField( this, "ctrlName" );
3439   aName->setMinimumWidth( 150 );
3440   myWidgets << aName;
3441
3442   // nodes info
3443   QLabel* aNodesLab = createLabel( tr( "NODES_INFO" ), this, Bold );
3444   QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this );
3445   QLabel* aNodesFree = createField( this, "ctrlNodesFree" );
3446   myWidgets << aNodesFree;
3447   myPredicates << aFilterMgr->CreateFreeNodes();
3448   //
3449   QLabel* aNodesNbConnLab = new QLabel( tr( "MAX_NODE_CONNECTIVITY" ), this );
3450   QLabel* aNodesNbConn = createField( this, "ctrlNodesCnty" );
3451   myWidgets << aNodesNbConn;
3452   myNodeConnFunctor = aFilterMgr->CreateNodeConnectivityNumber();
3453   //
3454   QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this );
3455   QLabel* aNodesDouble = createField( this, "ctrlNodesDouble" );
3456   myWidgets << aNodesDouble;
3457   myPredicates << aFilterMgr->CreateEqualNodes();
3458   QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this );
3459   myToleranceWidget = new SMESHGUI_SpinBox( this );
3460   myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" );
3461   myToleranceWidget->setAcceptNames( false );
3462   myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) );
3463
3464   // edges info
3465   QLabel* anEdgesLab = createLabel( tr( "EDGES_INFO" ), this, Bold );
3466   QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ),     this );
3467   QLabel* anEdgesDouble = createField( this, "ctrlEdgesDouble" );
3468   myWidgets << anEdgesDouble;
3469   myPredicates << aFilterMgr->CreateEqualEdges();
3470
3471   // faces info
3472   QLabel* aFacesLab = createLabel( tr( "FACES_INFO" ), this, Bold );
3473   QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this );
3474   QLabel* aFacesDouble = createField( this, "ctrlFacesDouble" );
3475   myWidgets << aFacesDouble;
3476   myPredicates << aFilterMgr->CreateEqualFaces();
3477   QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3478   QLabel* aFacesOver = createField( this, "ctrlFacesOver" );
3479   myWidgets << aFacesOver;
3480   myPredicates << aFilterMgr->CreateOverConstrainedFace();
3481   QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this );
3482   myPlot = createPlot( this );
3483   myAspectRatio = aFilterMgr->CreateAspectRatio();
3484  
3485   // volumes info
3486   QLabel* aVolumesLab = createLabel( tr( "VOLUMES_INFO" ), this, Bold );
3487   QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this );
3488   QLabel* aVolumesDouble = createField( this, "ctrlVolumesDouble" );
3489   myWidgets << aVolumesDouble;
3490   myPredicates << aFilterMgr->CreateEqualVolumes();
3491   QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this );
3492   QLabel* aVolumesOver = createField( this, "ctrlVolumesOver" );
3493   myWidgets << aVolumesOver;
3494   myPredicates << aFilterMgr->CreateOverConstrainedVolume();
3495   QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this );
3496   myPlot3D = createPlot( this );
3497   myAspectRatio3D = aFilterMgr->CreateAspectRatio3D();
3498
3499   QToolButton* aFreeNodesBtn = new QToolButton( this );
3500   aFreeNodesBtn->setIcon(aComputeIcon);
3501   myButtons << aFreeNodesBtn;       //0
3502
3503   QToolButton* aNodesNbConnBtn = new QToolButton( this );
3504   aNodesNbConnBtn->setIcon(aComputeIcon);
3505   myButtons << aNodesNbConnBtn;     //1
3506
3507   QToolButton* aDoubleNodesBtn = new QToolButton( this );
3508   aDoubleNodesBtn->setIcon(aComputeIcon);
3509   myButtons << aDoubleNodesBtn;     //2
3510
3511   QToolButton* aDoubleEdgesBtn = new QToolButton( this );
3512   aDoubleEdgesBtn->setIcon(aComputeIcon);
3513   myButtons << aDoubleEdgesBtn;     //3
3514
3515   QToolButton* aDoubleFacesBtn = new QToolButton( this );
3516   aDoubleFacesBtn->setIcon(aComputeIcon);
3517   myButtons << aDoubleFacesBtn;     //4
3518
3519   QToolButton* aOverContFacesBtn = new QToolButton( this );
3520   aOverContFacesBtn->setIcon(aComputeIcon);
3521   myButtons << aOverContFacesBtn;   //5
3522
3523   QToolButton* aComputeFaceBtn = new QToolButton( this );
3524   aComputeFaceBtn->setIcon(aComputeIcon);
3525   myButtons << aComputeFaceBtn;     //6
3526
3527   QToolButton* aDoubleVolumesBtn = new QToolButton( this );
3528   aDoubleVolumesBtn->setIcon(aComputeIcon);
3529   myButtons << aDoubleVolumesBtn;   //7
3530
3531   QToolButton* aOverContVolumesBtn = new QToolButton( this );
3532   aOverContVolumesBtn->setIcon(aComputeIcon);
3533   myButtons << aOverContVolumesBtn; //8
3534
3535   QToolButton* aComputeVolumeBtn = new QToolButton( this );
3536   aComputeVolumeBtn->setIcon(aComputeIcon);
3537   myButtons << aComputeVolumeBtn;   //9
3538
3539   connect( aComputeFaceBtn,   SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) );
3540   connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) );
3541   connect( aFreeNodesBtn,     SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) );
3542   connect( aNodesNbConnBtn,   SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ) );
3543   connect( aDoubleNodesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) );
3544   connect( aDoubleEdgesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) );
3545   connect( aDoubleFacesBtn,   SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) );
3546   connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) );
3547   connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) );
3548   connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) );
3549   connect( myToleranceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( setTolerance( double ) ) );
3550
3551   l->addWidget( aNameLab,           0, 0 );       //0
3552   l->addWidget( aName,              0, 1, 1, 2 ); //1
3553   l->addWidget( aNodesLab,          1, 0, 1, 3 ); //2
3554   l->addWidget( aNodesFreeLab,      2, 0 );       //3
3555   l->addWidget( aNodesFree,         2, 1 );       //4
3556   l->addWidget( aFreeNodesBtn,      2, 2 );       //5
3557   l->addWidget( aNodesNbConnLab,    3, 0 );       //6
3558   l->addWidget( aNodesNbConn,       3, 1 );       //7
3559   l->addWidget( aNodesNbConnBtn,    3, 2 );       //8
3560   l->addWidget( aNodesDoubleLab,    4, 0 );       //9
3561   l->addWidget( aNodesDouble,       4, 1 );       //10
3562   l->addWidget( aDoubleNodesBtn,    4, 2 );       //11
3563   l->addWidget( aToleranceLab,      5, 0 );       //12
3564   l->addWidget( myToleranceWidget,  5, 1 );       //13
3565   l->addWidget( anEdgesLab,         6, 0, 1, 3 ); //14
3566   l->addWidget( anEdgesDoubleLab,   7, 0 );       //15
3567   l->addWidget( anEdgesDouble,      7, 1 );       //16
3568   l->addWidget( aDoubleEdgesBtn,    7, 2 );       //17
3569   l->addWidget( aFacesLab,          8, 0, 1, 3 ); //18
3570   l->addWidget( aFacesDoubleLab,    9, 0 );       //19
3571   l->addWidget( aFacesDouble,       9, 1 );       //20
3572   l->addWidget( aDoubleFacesBtn,    9, 2 );       //21
3573   l->addWidget( aFacesOverLab,      10, 0 );      //22
3574   l->addWidget( aFacesOver,         10, 1 );      //23
3575   l->addWidget( aOverContFacesBtn,  10, 2 );      //24
3576   l->addWidget( anAspectRatioLab,   11, 0 );      //25
3577   l->addWidget( aComputeFaceBtn,    11, 2 );      //26
3578   l->addWidget( myPlot,             12, 0, 1, 3 );//27
3579   l->addWidget( aVolumesLab,        13, 0, 1, 3 );//28
3580   l->addWidget( aVolumesDoubleLab,  14, 0 );      //29
3581   l->addWidget( aVolumesDouble,     14, 1 );      //30
3582   l->addWidget( aDoubleVolumesBtn,  14, 2 );      //31
3583   l->addWidget( aVolumesOverLab,    15, 0 );      //32
3584   l->addWidget( aVolumesOver,       15, 1 );      //33
3585   l->addWidget( aOverContVolumesBtn,15, 2 );      //34
3586   l->addWidget( anAspectRatio3DLab, 16, 0 );      //35
3587   l->addWidget( aComputeVolumeBtn,  16, 2 );      //36
3588   l->addWidget( myPlot3D,           17, 0, 1, 3 );//37
3589  
3590   l->setColumnStretch(  0,  0 );
3591   l->setColumnStretch(  1,  5 );
3592   l->setRowStretch   ( 12,  5 );
3593   l->setRowStretch   ( 17,  5 );
3594   l->setRowStretch   ( 18,  1 );
3595
3596   clearInternal();
3597 }
3598
3599 /*!
3600   \brief Destructor.
3601 */
3602 SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo()
3603 {
3604 }
3605
3606 /*!
3607   \brief Create plot widget.
3608   \param parent Parent widget.
3609   \return New plot widget.
3610 */
3611 QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent )
3612 {
3613   QwtPlot* aPlot = new QwtPlot( parent );
3614   aPlot->setMinimumSize( 100, 100 );
3615   QFont xFont = aPlot->axisFont( QwtPlot::xBottom );
3616   xFont.setPointSize( 5 );
3617   QFont yFont = aPlot->axisFont( QwtPlot::yLeft );
3618   yFont.setPointSize( 5 );
3619   aPlot->setAxisFont( QwtPlot::xBottom, xFont );
3620   aPlot->setAxisFont( QwtPlot::yLeft, yFont );
3621   aPlot->replot();
3622   return aPlot;
3623 }
3624
3625 /*!
3626   \brief Show information on given object.
3627   \param proxy Object to show information on (mesh, sub-mesh, group, ID source).
3628 */
3629 void SMESHGUI_CtrlInfo::showInfo( const SMESH::SelectionProxy& proxy )
3630 {
3631   clearInternal();
3632
3633   if ( !proxy )
3634     return;
3635
3636   myProxy = proxy;
3637   SMESH::SMESH_IDSource_var obj = proxy.object();
3638
3639   myWidgets[0]->setText( proxy.name() );
3640
3641   SMESH::SMESH_Mesh_var mesh = obj->GetMesh();
3642   if ( mesh->_is_nil() ) return;
3643
3644   const bool meshLoaded = mesh->IsLoaded();
3645   if ( !meshLoaded ) // mesh not yet loaded from the hdf file
3646     // enable Compute buttons, just in case obj->GetNbElementsByType() fails
3647     for ( int i = 0; i < myButtons.count(); ++i )
3648       myButtons[i]->setEnabled( true );
3649
3650   SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType();
3651   if ( ! &nbElemsByType.in() ) return;
3652
3653   const CORBA::Long ctrlLimit =
3654     meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1;
3655
3656   // nodes info
3657   const CORBA::Long nbNodes =   nbElemsByType[ SMESH::NODE ];
3658   // const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] +
3659   //                               nbElemsByType[ SMESH::FACE ] +
3660   //                               nbElemsByType[ SMESH::VOLUME ] );
3661   if ( nbNodes > 0 ) {
3662     if ( nbNodes <= ctrlLimit ) {
3663       // free nodes
3664       computeFreeNodesInfo();
3665       // node connectivity number
3666       computeNodesNbConnInfo();
3667       // double nodes
3668       computeDoubleNodesInfo();
3669     }
3670     else {
3671       myButtons[0]->setEnabled( true );
3672       myButtons[1]->setEnabled( true );
3673       myButtons[2]->setEnabled( true );
3674     }
3675   }