X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESHGUI%2FSMESHGUI_MeshInfo.cxx;h=192b1440d5500d5f583e3010c9a9df3277de258b;hp=25ee42a9a2fed54b7a64af2d5f9e320c3e8ef57d;hb=341e363240adfbf291dbeeaa6ab989ffe46eb874;hpb=bd4e115a78b52e3fbc016e5e30bb0e19b2a9e7d6 diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx index 25ee42a9a..192b1440d 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,31 +19,33 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// File : SMESHGUI_MeshInfo.cxx -// Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) #include "SMESHGUI_MeshInfo.h" +#include "SMDS_Mesh.hxx" #include "SMESH_Actor.h" #include "SMESHGUI.h" +#include "SMESHGUI_FilterUtils.h" +#include "SMESHGUI_IdPreview.h" #include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_SpinBox.h" #include "SMESHGUI_Utils.h" #include "SMESHGUI_VTKUtils.h" -#include "SMDSAbs_ElementType.hxx" -#include "SMDS_Mesh.hxx" -#include "SMDS_BallElement.hxx" -#include "SMDS_EdgePosition.hxx" -#include "SMDS_FacePosition.hxx" -#include +#include #include #include +#include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -51,51 +53,408 @@ #include #include #include +#include #include #include +#include +#include #include #include +#include +#include +#include #include -#include "utilities.h" +//////////////////////////////////////////////////////////////////////////////// +/// \class Field +/// \brief Field widget. +/// \internal +//////////////////////////////////////////////////////////////////////////////// -#include -#include CORBA_SERVER_HEADER(GEOM_Gen) +class Field : public QLabel +{ +public: + Field( QWidget*, const QString& = QString() ); + bool event( QEvent* ); +}; -const int SPACING = 6; -const int MARGIN = 9; -const int MAXITEMS = 10; -const int GROUPS_ID = 100; -const int SUBMESHES_ID = 200; +/*! + \brief Constructor. + \param parent Parent widget. + \param name Field name. Defauls to null string. +*/ +Field::Field( QWidget* parent, const QString& name ): QLabel( parent ) +{ + setFrameStyle( QLabel::StyledPanel | QLabel::Sunken ); + setAlignment( Qt::AlignCenter ); + setAutoFillBackground( true ); + QPalette pal = palette(); + QColor base = QApplication::palette().color( QPalette::Active, QPalette::Base ); + pal.setColor( QPalette::Window, base ); + setPalette( pal ); + setMinimumWidth( 60 ); + if ( !name.isEmpty() ) + setObjectName( name ); +} /*! - \class ExtraWidget - \internal + \brief Event handler. Redefined from QLabel. +*/ +bool Field::event( QEvent* e ) +{ + if ( e->type() == QEvent::DynamicPropertyChange ) + { + QDynamicPropertyChangeEvent* ce = (QDynamicPropertyChangeEvent*)e; + if ( ce->propertyName() == "value" && property( "value" ).isValid() ) + { + setText( QString::number( property( "value" ).toInt() ) ); + setProperty( "value", QVariant() ); + return true; + } + } + return QLabel::event( e ); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class TreeItemCreator +/// \brief Generic tree item creator. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class TreeItemCreator +{ +public: + TreeItemCreator() {} + virtual ~TreeItemCreator() {} + virtual QTreeWidgetItem* createItem( QTreeWidgetItem*, int ) = 0; +}; + +//////////////////////////////////////////////////////////////////////////////// +// General purpose services. +//////////////////////////////////////////////////////////////////////////////// + +namespace +{ + const int SPACING = 6; + const int MARGIN = 9; + + enum + { + Bold = 0x01, + Italic = 0x02, + AllColumns = 0x04, + Expanded = 0x08, + Editable = 0x10 + }; + + enum + { + GroupsId = 100, + SubMeshesId + }; + + enum + { + TypeRole = Qt::UserRole + 10, + IdRole, + }; + + enum + { + NodeConnectivity = 100, + ElemConnectivity, + }; + + /*! + \brief Get item's depth in the tree. + \param item Tree widget item. + \return Item's depth in the tree widget (top-level item has zero depth). + \internal + */ + int itemDepth( QTreeWidgetItem* item ) + { + QList parents; + parents << item; + while ( parents.last()->parent() ) + parents << parents.last()->parent(); + return parents.size()-1; + } + + /*! + \brief Get chunk size. + \return Chunk size. + \internal + */ + int blockSize() + { + return 10; + } + + /*! + \brief Get spacer. + \return Spacer string. + \internal + */ + QString spacing() + { + static int size = 1; + static QChar spacer = ' '; + return QString( size, spacer ); + } + + /*! + \brief Get indent. + \param length Indent size. Defaults to 1. + \return Indentation string. + \internal + */ + QString indent( int length = 1 ) + { + static int size = 4; + static QChar spacer = ' '; + return QString( size * length, spacer ); + } + + /*! + \brief Get indent. + \param spacer Spacer. + \param length Indent size. Defaults to 1. + \return Indentation string. + \internal + */ + QString indent( const QString& spacer, uint length = 1 ) + { + QString result; + while( length-- > 0 ) + result += spacer; + return result; + } + + /*! + \brief Get group separator. + \param length Length of ruler (number of symbols). Defaults to 80. + \return Ruler string. + \internal + */ + QString ruler( int length = 80 ) + { + static QChar ruler = '-'; + return QString( length, ruler ); + } + + /*! + \brief Get text value from label. + \param w Widget (QLabel). + \return Value string. + \internal + */ + QString widgetValue( QWidget* w ) + { + QString v; + if ( qobject_cast( w ) ) + v = qobject_cast( w )->text(); + return v; + } + + /*! + \brief Get font for given options. + \param font Initial font. + \param options Font attributes. + \return Font. + */ + QFont fontFromOptions( const QFont& font, int options ) + { + QFont f = font; + f.setBold( options & Bold ); + f.setItalic( options & Italic ); + return f; + } + + /*! + \brief Set font attributes to given widget. + \param w Widget. + \param options Font attributes. + */ + void setFontAttributes( QWidget* w, int options ) + { + if ( w ) + w->setFont( fontFromOptions( w->font(), options ) ); + } + + /*! + \brief Set attributes to given tree item. + \param item Tree widget item. + \param options Item attributes. + */ + void setTreeItemAttributes( QTreeWidgetItem* item, int options ) + { + if ( item && item->treeWidget() ) + { + for ( int i = 0; i < item->treeWidget()->columnCount(); i++ ) + { + if ( i == 0 || options & AllColumns ) + item->setFont( i, fontFromOptions( item->font( 0 ), options) ); + } + } + if ( options & Expanded ) + item->setExpanded( true ); + if ( options & Editable ) + item->setFlags( item->flags() | Qt::ItemIsEditable ); + } + + /*! + \brief Create label. + \param parent Parent widget. + \param options Label options. Defaults to 0 (none). + \return New label. + */ + QLabel* createLabel( QWidget* parent, int options = 0 ) + { + QLabel* lab = new QLabel( parent ); + setFontAttributes( lab, options ); + return lab; + } + + /*! + \brief Create label. + \param text Label text. + \param parent Parent widget. + \param options Label options. Defaults to 0 (none). + \return New label. + */ + QLabel* createLabel( const QString& text, QWidget* parent, int options = 0 ) + { + QLabel* lab = createLabel( parent, options ); + lab->setText( text ); + return lab; + } + + /*! + \brief Create information field. + \param parent Parent widget. + \param name Field's object. Default to null string. + \return New field. + */ + QLabel* createField( QWidget* parent, const QString& name = QString() ) + { + return new Field( parent, name ); + } + + /*! + \brief Create information field. + \param parent Parent widget. + \param options Label options. + \param name Field's object. Default to null string. + \return New field. + */ + QLabel* createField( QWidget* parent, int options, const QString& name = QString() ) + { + QLabel* field = createField( parent, name ); + setFontAttributes( field, options ); + return field; + } + + /*! + \brief Create ruler. + \param parent Parent widget. + \param orientation Ruler orientation. Defaults to horizontal. + \return New ruler. + */ + QWidget* createSeparator( QWidget* parent, Qt::Orientation orientation = Qt::Horizontal ) + { + QFrame* line = new QFrame( parent ); + line->setFrameShape( orientation == Qt::Horizontal ? QFrame::HLine : QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + return line; + } + + /*! + \brief Decorate text as bold. + \param text Initial text. + \return Decorated text. + */ + QString bold( const QString& text ) + { + return QString("%1").arg( text ); + } + + /*! + \brief Format connectivity data to string representation. + \param connectivity Connectivity map. + \param type Element type or face index if negative + \return Stringifed representation of the connectivity. + */ + QString formatConnectivity( SMESH::Connectivity connectivity, int type ) + { + QStringList str; + QString result; + bool isNodal = ( type == SMDSAbs_Node || type < 0 ); + type = qAbs( type ); + if ( connectivity.contains( type )) + { + QList elements = connectivity[ type ]; + if ( !isNodal ) // order of nodes is important + qSort( elements ); + foreach( int id, elements ) + str << QString::number( id ); + + // wrap IDs into an html link, to be treated by QTextBrowser used by SMESHGUI_SimpleElemInfo + QString s = str.join( " " ); + result = ( "" + // path + s + "" ); // anchor text + } + return result; + } +} // end of anonymous namespace + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_Info +/// \brief Base widget for all information panes. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. */ +SMESHGUI_Info::SMESHGUI_Info( QWidget* parent ): QWidget( parent ) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class ExtraWidget +/// \brief Auxiliary widget to browse between chunks of information. +/// \internal +//////////////////////////////////////////////////////////////////////////////// class ExtraWidget : public QWidget { public: ExtraWidget( QWidget*, bool = false ); - ~ExtraWidget(); - - void updateControls( int, int, int = MAXITEMS ); + void updateControls( int, int ); public: - QLabel* current; + QLabel* current; QPushButton* prev; QPushButton* next; - bool brief; + bool brief; }; -ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( b ) +/* + \brief Constructor. + \param parent Parent widget. + \param briefSummary Show summary in brief format. Defaults to \c false. +*/ +ExtraWidget::ExtraWidget( QWidget* parent, bool briefSummary ): QWidget( parent ), brief( briefSummary ) { current = new QLabel( this ); current->setAlignment( Qt::AlignRight | Qt::AlignVCenter ); - prev = new QPushButton( tr( "<<" ), this ); - next = new QPushButton( tr( ">>" ), this ); + prev = new QPushButton( "<<", this ); + next = new QPushButton( ">>", this ); QHBoxLayout* hbl = new QHBoxLayout( this ); - hbl->setContentsMargins( 0, SPACING, 0, 0 ); + hbl->setMargin( 0 ); hbl->setSpacing( SPACING ); hbl->addStretch(); hbl->addWidget( current ); @@ -103,1841 +462,3545 @@ ExtraWidget::ExtraWidget( QWidget* parent, bool b ) : QWidget( parent ), brief( hbl->addWidget( next ); } -ExtraWidget::~ExtraWidget() +/* + \brief Update controls. + \param total Total number of items. + \param index Current index. +*/ +void ExtraWidget::updateControls( int total, int index ) { + setVisible( total > blockSize() ); + QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" ); + current->setText( format.arg( index*blockSize()+1 ).arg( qMin( index*blockSize()+blockSize(), total ) ).arg( total ) ); + prev->setEnabled( index > 0 ); + next->setEnabled( (index+1)*blockSize() < total ); } -void ExtraWidget::updateControls( int total, int index, int blockSize ) +//////////////////////////////////////////////////////////////////////////////// +/// \class DumpFileDlg +/// \brief Standard Save File dialog box, customized for dump info operation. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class DumpFileDlg : public SUIT_FileDlg { - setVisible( total > blockSize ); - QString format = brief ? QString( "%1-%2 / %3" ) : SMESHGUI_MeshInfoDlg::tr( "X_FROM_Y_ITEMS_SHOWN" ); - current->setText( format.arg( index*blockSize+1 ).arg( qMin( index*blockSize+blockSize, total ) ).arg( total ) ); - prev->setEnabled( index > 0 ); - next->setEnabled( (index+1)*blockSize < total ); + QMap myControls; +public: + DumpFileDlg( QWidget*, bool = true ); + bool isChecked( int ) const; + void setChecked( int, bool ); +}; + +/*! + \brief Constructor. + \param parent Parent widget. + \param showControls Show additional controls. Defaults to \c true. + \internal +*/ +DumpFileDlg::DumpFileDlg( QWidget* parent, bool showControls ): SUIT_FileDlg( parent, false, true, true ) +{ + if ( showControls ) + { + QWidget* hB = new QWidget( this ); + myControls[SMESHGUI_MeshInfoDlg::BaseInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_BASE_INFO" ), hB ); + myControls[SMESHGUI_MeshInfoDlg::ElemInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ELEM_INFO" ), hB ); + myControls[SMESHGUI_MeshInfoDlg::AddInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_ADD_INFO" ), hB ); + myControls[SMESHGUI_MeshInfoDlg::CtrlInfo] = new QCheckBox( SMESHGUI::tr( "PREF_DUMP_CTRL_INFO" ), hB ); + + QGridLayout* layout = new QGridLayout( hB ); + layout->setMargin( 0 ); + layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::BaseInfo], 0, 0 ); + layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::ElemInfo], 0, 1 ); + layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::AddInfo], 1, 0 ); + layout->addWidget( myControls[SMESHGUI_MeshInfoDlg::CtrlInfo], 1, 1 ); + + addWidgets( 0, hB, 0 ); + } } /*! - \class SMESHGUI_MeshInfo - \brief Base mesh information widget - - Displays the base information about mesh object: mesh, sub-mesh, group or arbitrary ID source. + \brief Get control's value. + \param option Control identifier. + \return Control value. + \internal */ +bool DumpFileDlg::isChecked( int option ) const +{ + return myControls.contains( option ) ? myControls[option]->isChecked() : false; +} /*! - \brief Constructor. - \param parent parent widget + \brief Set control's initial value. + \param option Control identifier. + \param value Control value. + \internal */ -SMESHGUI_MeshInfo::SMESHGUI_MeshInfo( QWidget* parent ) - : QFrame( parent ), myWidgets( iElementsEnd ) +void DumpFileDlg::setChecked( int option, bool value ) { - setFrameStyle( StyledPanel | Sunken ); + if ( myControls.contains( option ) ) + myControls[option]->setChecked( value ); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_BaseInfo +/// \brief Show basic information on selected object. +/// +/// Displays the base information about selected object: mesh, sub-mesh, group +/// or arbitrary ID source. +/// \todo Hide unnecessary widgets (e.g. for mesh group). +//////////////////////////////////////////////////////////////////////////////// +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. +*/ +SMESHGUI_BaseInfo::SMESHGUI_BaseInfo( QWidget* parent ): SMESHGUI_Info( parent ) +{ QGridLayout* l = new QGridLayout( this ); l->setMargin( MARGIN ); l->setSpacing( SPACING ); - int index = 0; - - // object - QLabel* aNameLab = new QLabel( tr( "NAME_LAB" ), this ); - QLabel* aName = createField(); - aName->setMinimumWidth( 150 ); - QLabel* aObjLab = new QLabel( tr( "OBJECT_LAB" ), this ); - QLabel* aObj = createField(); - aObj->setMinimumWidth( 150 ); - myWidgets[ index++ ] << aNameLab << aName; - myWidgets[ index++ ] << aObjLab << aObj; - - // nodes - QWidget* aNodesLine = createLine(); - QLabel* aNodesLab = new QLabel( tr( "NODES_LAB" ), this ); - QLabel* aNodes = createField(); - myWidgets[ index++ ] << aNodesLine; - myWidgets[ index++ ] << aNodesLab << aNodes; - - // elements - QWidget* aElemLine = createLine(); - QLabel* aElemLab = new QLabel( tr( "ELEMENTS_LAB" ), this ); - QLabel* aElemTotal = new QLabel( tr( "TOTAL_LAB" ), this ); - QLabel* aElemLin = new QLabel( tr( "LINEAR_LAB" ), this ); - QLabel* aElemQuad = new QLabel( tr( "QUADRATIC_LAB" ), this ); - myWidgets[ index++ ] << aElemLine; - myWidgets[ index++ ] << aElemLab << aElemTotal << aElemLin << aElemQuad; - - // ... 0D elements - QWidget* a0DLine = createLine(); - QLabel* a0DLab = new QLabel( tr( "0D_LAB" ), this ); - QLabel* a0DTotal = createField(); - myWidgets[ index++ ] << a0DLine; - myWidgets[ index++ ] << a0DLab << a0DTotal; - - // ... Ball elements - QWidget* aBallLine = createLine(); - QLabel* aBallLab = new QLabel( tr( "BALL_LAB" ), this ); - QLabel* aBallTotal = createField(); - myWidgets[ index++ ] << aBallLine; - myWidgets[ index++ ] << aBallLab << aBallTotal; - - // ... 1D elements - QWidget* a1DLine = createLine(); - QLabel* a1DLab = new QLabel( tr( "1D_LAB" ), this ); - QLabel* a1DTotal = createField(); - QLabel* a1DLin = createField(); - QLabel* a1DQuad = createField(); - myWidgets[ index++ ] << a1DLine; - myWidgets[ index++ ] << a1DLab << a1DTotal << a1DLin << a1DQuad; - - // ... 2D elements - QWidget* a2DLine = createLine(); - QLabel* a2DLab = new QLabel( tr( "2D_LAB" ), this ); - QLabel* a2DTotal = createField(); - QLabel* a2DLin = createField(); - QLabel* a2DQuad = createField(); - QLabel* a2DTriLab = new QLabel( tr( "TRIANGLES_LAB" ), this ); - QLabel* a2DTriTotal = createField(); - QLabel* a2DTriLin = createField(); - QLabel* a2DTriQuad = createField(); - QLabel* a2DQuaLab = new QLabel( tr( "QUADRANGLES_LAB" ), this ); - QLabel* a2DQuaTotal = createField(); - QLabel* a2DQuaLin = createField(); - QLabel* a2DQuaQuad = createField(); - QLabel* a2DPolLab = new QLabel( tr( "POLYGONS_LAB" ), this ); - QLabel* a2DPolTotal = createField(); - myWidgets[ index++ ] << a2DLine; - myWidgets[ index++ ] << a2DLab << a2DTotal << a2DLin << a2DQuad; - myWidgets[ index++ ] << a2DTriLab << a2DTriTotal << a2DTriLin << a2DTriQuad; - myWidgets[ index++ ] << a2DQuaLab << a2DQuaTotal << a2DQuaLin << a2DQuaQuad; - myWidgets[ index++ ] << a2DPolLab << a2DPolTotal; - - // ... 3D elements - QWidget* a3DLine = createLine(); - QLabel* a3DLab = new QLabel( tr( "3D_LAB" ), this ); - QLabel* a3DTotal = createField(); - QLabel* a3DLin = createField(); - QLabel* a3DQuad = createField(); - QLabel* a3DTetLab = new QLabel( tr( "TETRAHEDRONS_LAB" ), this ); - QLabel* a3DTetTotal = createField(); - QLabel* a3DTetLin = createField(); - QLabel* a3DTetQuad = createField(); - QLabel* a3DHexLab = new QLabel( tr( "HEXAHEDONRS_LAB" ), this ); - QLabel* a3DHexTotal = createField(); - QLabel* a3DHexLin = createField(); - QLabel* a3DHexQuad = createField(); - QLabel* a3DPyrLab = new QLabel( tr( "PYRAMIDS_LAB" ), this ); - QLabel* a3DPyrTotal = createField(); - QLabel* a3DPyrLin = createField(); - QLabel* a3DPyrQuad = createField(); - QLabel* a3DPriLab = new QLabel( tr( "PRISMS_LAB" ), this ); - QLabel* a3DPriTotal = createField(); - QLabel* a3DPriLin = createField(); - QLabel* a3DPriQuad = createField(); - QLabel* a3DHexPriLab = new QLabel( tr( "HEX_PRISMS_LAB" ), this ); - QLabel* a3DHexPriTotal = createField(); - QLabel* a3DPolLab = new QLabel( tr( "POLYHEDRONS_LAB" ), this ); - QLabel* a3DPolTotal = createField(); - myWidgets[ index++ ] << a3DLine; - myWidgets[ index++ ] << a3DLab << a3DTotal << a3DLin << a3DQuad; - myWidgets[ index++ ] << a3DTetLab << a3DTetTotal << a3DTetLin << a3DTetQuad; - myWidgets[ index++ ] << a3DHexLab << a3DHexTotal << a3DHexLin << a3DHexQuad; - myWidgets[ index++ ] << a3DPyrLab << a3DPyrTotal << a3DPyrLin << a3DPyrQuad; - myWidgets[ index++ ] << a3DPriLab << a3DPriTotal << a3DPriLin << a3DPriQuad; - myWidgets[ index++ ] << a3DHexPriLab << a3DHexPriTotal; - myWidgets[ index++ ] << a3DPolLab << a3DPolTotal; - - myLoadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this ); - myLoadBtn->setAutoDefault( true ); - connect( myLoadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) ); - - setFontAttributes( aNameLab, Bold ); - setFontAttributes( aObjLab, Bold ); - setFontAttributes( aNodesLab, Bold ); - setFontAttributes( aElemLab, Bold ); - setFontAttributes( aElemTotal, Italic ); - setFontAttributes( aElemLin, Italic ); - setFontAttributes( aElemQuad, Italic ); - setFontAttributes( a0DLab, Bold ); - setFontAttributes( aBallLab, Bold ); - setFontAttributes( a1DLab, Bold ); - setFontAttributes( a2DLab, Bold ); - setFontAttributes( a3DLab, Bold ); - - l->addWidget( aNameLab, 0, 0 ); - l->addWidget( aName, 0, 1, 1, 3 ); - l->addWidget( aObjLab, 1, 0 ); - l->addWidget( aObj, 1, 1, 1, 3 ); - l->addWidget( aNodesLine, 2, 0, 1, 4 ); - l->addWidget( aNodesLab, 3, 0 ); - l->addWidget( aNodes, 3, 1 ); - l->addWidget( aElemLine, 4, 0, 1, 4 ); - l->addWidget( aElemLab, 5, 0 ); - l->addWidget( aElemTotal, 5, 1 ); - l->addWidget( aElemLin, 5, 2 ); - l->addWidget( aElemQuad, 5, 3 ); - l->addWidget( a0DLine, 6, 1, 1, 3 ); - l->addWidget( a0DLab, 7, 0 ); - l->addWidget( a0DTotal, 7, 1 ); - l->addWidget( aBallLine, 8, 1, 1, 3 ); - l->addWidget( aBallLab, 9, 0 ); - l->addWidget( aBallTotal, 9, 1 ); - l->addWidget( a1DLine, 10, 1, 1, 3 ); - l->addWidget( a1DLab, 11, 0 ); - l->addWidget( a1DTotal, 11, 1 ); - l->addWidget( a1DLin, 11, 2 ); - l->addWidget( a1DQuad, 11, 3 ); - l->addWidget( a2DLine, 12, 1, 1, 3 ); - l->addWidget( a2DLab, 13, 0 ); - l->addWidget( a2DTotal, 13, 1 ); - l->addWidget( a2DLin, 13, 2 ); - l->addWidget( a2DQuad, 13, 3 ); - l->addWidget( a2DTriLab, 14, 0 ); - l->addWidget( a2DTriTotal, 14, 1 ); - l->addWidget( a2DTriLin, 14, 2 ); - l->addWidget( a2DTriQuad, 14, 3 ); - l->addWidget( a2DQuaLab, 15, 0 ); - l->addWidget( a2DQuaTotal, 15, 1 ); - l->addWidget( a2DQuaLin, 15, 2 ); - l->addWidget( a2DQuaQuad, 15, 3 ); - l->addWidget( a2DPolLab, 16, 0 ); - l->addWidget( a2DPolTotal, 16, 1 ); - l->addWidget( a3DLine, 17, 1, 1, 3 ); - l->addWidget( a3DLab, 18, 0 ); - l->addWidget( a3DTotal, 18, 1 ); - l->addWidget( a3DLin, 18, 2 ); - l->addWidget( a3DQuad, 18, 3 ); - l->addWidget( a3DTetLab, 19, 0 ); - l->addWidget( a3DTetTotal, 19, 1 ); - l->addWidget( a3DTetLin, 19, 2 ); - l->addWidget( a3DTetQuad, 19, 3 ); - l->addWidget( a3DHexLab, 20, 0 ); - l->addWidget( a3DHexTotal, 20, 1 ); - l->addWidget( a3DHexLin, 20, 2 ); - l->addWidget( a3DHexQuad, 20, 3 ); - l->addWidget( a3DPyrLab, 21, 0 ); - l->addWidget( a3DPyrTotal, 21, 1 ); - l->addWidget( a3DPyrLin, 21, 2 ); - l->addWidget( a3DPyrQuad, 21, 3 ); - l->addWidget( a3DPriLab, 22, 0 ); - l->addWidget( a3DPriTotal, 22, 1 ); - l->addWidget( a3DPriLin, 22, 2 ); - l->addWidget( a3DPriQuad, 22, 3 ); - l->addWidget( a3DHexPriLab, 23, 0 ); - l->addWidget( a3DHexPriTotal, 23, 1 ); - l->addWidget( a3DPolLab, 24, 0 ); - l->addWidget( a3DPolTotal, 24, 1 ); - l->addWidget( myLoadBtn, 25, 1, 1, 3 ); - l->setColumnStretch( 0, 0 ); - l->setColumnStretch( 1, 5 ); - l->setColumnStretch( 2, 5 ); - l->setColumnStretch( 3, 5 ); - l->setRowStretch( 23, 5 ); - + // object info + // - name + addWidget( createLabel( tr( "NAME_LAB" ), this, Bold ), iName, iLabel ); + addWidget( createField( this, "meshName" ), iName, iSingle, 4 )->setMinimumWidth( 150 ); + // - type + addWidget( createLabel( tr( "OBJECT_LAB" ), this, Bold ), iObject, iLabel ); + addWidget( createField( this, "meshType" ), iObject, iSingle, 4 )->setMinimumWidth( 150 ); + // - --- (separator) + addWidget( createSeparator( this ), iObjectEnd, iLabel, 5 ); + + // node info + // - info + addWidget( createLabel( tr( "NODES_LAB" ), this, Bold ), iNodes, iLabel ); + addWidget( createField( this, "nbNodes" ), iNodes, iTotal ); + // - --- (separator) + addWidget( createSeparator( this ), iNodesEnd, iLabel, 5 ); + + // element info + // - title + addWidget( createLabel( tr( "ELEMENTS_LAB" ), this, Bold ), iElementsTitle, iLabel ); + addWidget( createLabel( tr( "TOTAL_LAB" ), this, Italic ), iElementsTitle, iTotal ); + addWidget( createLabel( tr( "LINEAR_LAB" ), this, Italic ), iElementsTitle, iLinear ); + addWidget( createLabel( tr( "QUADRATIC_LAB" ), this, Italic ), iElementsTitle, iQuadratic ); + addWidget( createLabel( tr( "BI_QUADRATIC_LAB" ), this, Italic ), iElementsTitle, iBiQuadratic ); + // - --- (separator) + addWidget( createSeparator( this ), iElementsTitleEnd, iTotal, 4 ); + // - summary + addWidget( createField( this, "totalNbElems" ), iElementsTotal, iTotal ); + addWidget( createField( this, "totalNbLinearElems" ), iElementsTotal, iLinear ); + addWidget( createField( this, "totalNbQuadraticElems" ), iElementsTotal, iQuadratic ); + addWidget( createField( this, "totalNbBiQuadraticElems" ), iElementsTotal, iBiQuadratic ); + // - --- (separator) + addWidget( createSeparator( this ), iElementsTotalEnd, iTotal, 4 ); + // - 0D elements info + addWidget( createLabel( tr( "0D_LAB" ), this, Bold | Italic ), i0D, iLabel ); + addWidget( createField( this, "nb0D" ), i0D, iTotal ); + // - --- (separator) + addWidget( createSeparator( this ), i0DEnd, iTotal, 4 ); + // - balls info + addWidget( createLabel( tr( "BALL_LAB" ), this, Bold | Italic ), iBalls, iLabel ); + addWidget( createField( this, "nbBall" ), iBalls, iTotal ); + // - --- (separator) + addWidget( createSeparator( this ), iBallsEnd, iTotal, 4 ); + // - 1D elements info + addWidget( createLabel( tr( "1D_LAB" ), this, Bold | Italic ), i1D, iLabel ); + addWidget( createField( this, "nb1D" ), i1D, iTotal ); + addWidget( createField( this, "nbLinear1D" ), i1D, iLinear ); + addWidget( createField( this, "nbQuadratic1D" ), i1D, iQuadratic ); + // - --- (separator) + addWidget( createSeparator( this ), i1DEnd, iTotal, 4 ); + // - 2D elements info + // --+ summary + addWidget( createLabel( tr( "2D_LAB" ), this, Bold | Italic ), i2D, iLabel ); + addWidget( createField( this, "nb2D" ), i2D, iTotal ); + addWidget( createField( this, "nbLinear2D" ), i2D, iLinear ); + addWidget( createField( this, "nbQuadratic2D" ), i2D, iQuadratic ); + addWidget( createField( this, "nbBiQuadratic2D" ), i2D, iBiQuadratic ); + // --+ triangles + addWidget( createLabel( tr( "TRIANGLES_LAB" ), this, Italic ), i2DTriangles, iLabel ); + addWidget( createField( this, Italic, "nbTriangle" ), i2DTriangles, iTotal ); + addWidget( createField( this, Italic, "nbLinearTriangle" ), i2DTriangles, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticTriangle" ), i2DTriangles, iQuadratic ); + addWidget( createField( this, Italic, "nbBiQuadraticTriangle" ), i2DTriangles, iBiQuadratic ); + // --+ quadrangles + addWidget( createLabel( tr( "QUADRANGLES_LAB" ), this, Italic ), i2DQuadrangles, iLabel ); + addWidget( createField( this, Italic, "nbQuadrangle" ), i2DQuadrangles, iTotal ); + addWidget( createField( this, Italic, "nbLinearQuadrangle" ), i2DQuadrangles, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticQuadrangle" ), i2DQuadrangles, iQuadratic ); + addWidget( createField( this, Italic, "nbBiQuadraticQuadrangle" ), i2DQuadrangles, iBiQuadratic ); + // --+ polygons + addWidget( createLabel( tr( "POLYGONS_LAB" ), this, Italic ), i2DPolygons, iLabel ); + addWidget( createField( this, Italic, "nbPolygon" ), i2DPolygons, iTotal ); + addWidget( createField( this, Italic, "nbLinearPolygon" ), i2DPolygons, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticPolygon" ), i2DPolygons, iQuadratic ); + // - --- (separator) + addWidget( createSeparator( this ), i2DEnd, iTotal, 4 ); + // - 3D elements info + // --+ summary + addWidget( createLabel( tr( "3D_LAB" ), this, Bold | Italic ), i3D, iLabel ); + addWidget( createField( this, "nb3D" ), i3D, iTotal ); + addWidget( createField( this, "nbLinear3D" ), i3D, iLinear ); + addWidget( createField( this, "nbQuadratic3D" ), i3D, iQuadratic ); + addWidget( createField( this, "nbBiQuadratic3D" ), i3D, iBiQuadratic ); + // --+ tetras + addWidget( createLabel( tr( "TETRAHEDRONS_LAB" ), this, Italic ), i3DTetrahedrons, iLabel ); + addWidget( createField( this, Italic, "nbTetrahedron" ), i3DTetrahedrons, iTotal ); + addWidget( createField( this, Italic, "nbLinearTetrahedron" ), i3DTetrahedrons, iLinear ); + addWidget( createField( this, Italic, "nbQudraticTetrahedron" ), i3DTetrahedrons, iQuadratic ); + // --+ hexas + addWidget( createLabel( tr( "HEXAHEDONRS_LAB" ), this, Italic ), i3DHexahedrons, iLabel ); + addWidget( createField( this, Italic, "nbHexahedron" ), i3DHexahedrons, iTotal ); + addWidget( createField( this, Italic, "nbLinearHexahedron" ), i3DHexahedrons, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticHexahedron" ), i3DHexahedrons, iQuadratic ); + addWidget( createField( this, Italic, "nbBiQuadraticHexahedron" ), i3DHexahedrons, iBiQuadratic ); + // --+ pyramids + addWidget( createLabel( tr( "PYRAMIDS_LAB" ), this, Italic ), i3DPyramids, iLabel ); + addWidget( createField( this, Italic, "nbPyramid" ), i3DPyramids, iTotal ); + addWidget( createField( this, Italic, "nbLinearPyramid" ), i3DPyramids, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticPyramid" ), i3DPyramids, iQuadratic ); + // --+ prisms + addWidget( createLabel( tr( "PRISMS_LAB" ), this, Italic ), i3DPrisms, iLabel ); + addWidget( createField( this, Italic, "nbPrism" ), i3DPrisms, iTotal ); + addWidget( createField( this, Italic, "nbLinearPrism" ), i3DPrisms, iLinear ); + addWidget( createField( this, Italic, "nbQuadraticPrism" ), i3DPrisms, iQuadratic ); + addWidget( createField( this, Italic, "nbBiQuadraticPrism" ), i3DPrisms, iBiQuadratic ); + // --+ hexagonal prisms + addWidget( createLabel( tr( "HEX_PRISMS_LAB" ), this, Italic ), i3DHexaPrisms, iLabel ); + addWidget( createField( this, Italic, "nbHexagonalPrism" ), i3DHexaPrisms, iTotal ); + // --+ polyhedrons + addWidget( createLabel( tr( "POLYHEDRONS_LAB" ), this, Italic ), i3DPolyhedrons, iLabel ); + addWidget( createField( this, Italic, "nbPolyhedron" ), i3DPolyhedrons, iTotal ); + + // load button + QPushButton* loadBtn = new QPushButton( tr( "BUT_LOAD_MESH" ), this ); + loadBtn->setAutoDefault( true ); + connect( loadBtn, SIGNAL( clicked() ), this, SLOT( loadMesh() ) ); + addWidget( loadBtn, iEnd, iSingle, 4 ); + + // additional layout set-up + l->setColumnStretch( iLabel, 0 ); + l->setColumnStretch( iTotal, 5 ); + l->setColumnStretch( iLinear, 5 ); + l->setColumnStretch( iQuadratic, 5 ); + l->setColumnStretch( iBiQuadratic, 5 ); + l->setRowStretch( iElementsEnd, 5 ); + + // set initial values clear(); } /*! - \brief Destructor + \brief Destructor. */ -SMESHGUI_MeshInfo::~SMESHGUI_MeshInfo() +SMESHGUI_BaseInfo::~SMESHGUI_BaseInfo() { } /*! - \brief Show information on the mesh object. - \param obj object being processed (mesh, sub-mesh, group, ID source) + \brief Show information on given object. + \param proxy Object to show information on (mesh, sub-mesh, group, ID source). */ -void SMESHGUI_MeshInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) +void SMESHGUI_BaseInfo::showInfo( const SMESH::SelectionProxy& proxy ) { + // reset panel clear(); - if ( !CORBA::is_nil( obj ) ) { - _PTR(SObject) sobj = SMESH::ObjectToSObject( obj ); - if ( sobj ) - myWidgets[iName][iSingle]->setProperty( "text", sobj->GetName().c_str() ); - SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( obj ); - SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( obj ); - SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( obj ); - if ( !aMesh->_is_nil() ) { - myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_MESH" ) ); + + // then fill panel with data if object is not null + if ( proxy ) + { + myProxy = proxy; + + SMESH::MeshInfo info = proxy.meshInfo(); + + // object info + // - name + widget( iName, iSingle )->setProperty( "text", proxy.name() ); + // - type + QString typeName; + SMESH::SelectionProxy::Type type = proxy.type(); + if ( type == SMESH::SelectionProxy::Mesh ) + { + typeName = tr( "OBJECT_MESH" ); } - else if ( !aSubMesh->_is_nil() ) { - myWidgets[iObject][iSingle]->setProperty( "text", tr( "OBJECT_SUBMESH" ) ); + else if ( type == SMESH::SelectionProxy::Submesh ) + { + typeName = tr( "OBJECT_SUBMESH" ); } - else if ( !aGroup->_is_nil() ) { - QString objType; - switch( aGroup->GetType() ) { - case SMESH::NODE: - objType = tr( "OBJECT_GROUP_NODES" ); - break; - case SMESH::EDGE: - objType = tr( "OBJECT_GROUP_EDGES" ); - break; - case SMESH::FACE: - objType = tr( "OBJECT_GROUP_FACES" ); - break; - case SMESH::VOLUME: - objType = tr( "OBJECT_GROUP_VOLUMES" ); - break; - case SMESH::ELEM0D: - objType = tr( "OBJECT_GROUP_0DELEMS" ); - break; - case SMESH::BALL: - objType = tr( "OBJECT_GROUP_BALLS" ); - break; - default: - objType = tr( "OBJECT_GROUP" ); - break; + else if ( type >= SMESH::SelectionProxy::Group ) + { + switch( proxy.groupElementType() ) + { + case SMESH::NODE: typeName = tr( "OBJECT_GROUP_NODES" ); break; + case SMESH::EDGE: typeName = tr( "OBJECT_GROUP_EDGES" ); break; + case SMESH::FACE: typeName = tr( "OBJECT_GROUP_FACES" ); break; + case SMESH::VOLUME: typeName = tr( "OBJECT_GROUP_VOLUMES" ); break; + case SMESH::ELEM0D: typeName = tr( "OBJECT_GROUP_0DELEMS" ); break; + case SMESH::BALL: typeName = tr( "OBJECT_GROUP_BALLS" ); break; + default: typeName = tr( "OBJECT_GROUP" ); break; } - myWidgets[iObject][iSingle]->setProperty( "text", objType ); + QString subType; + if ( type == SMESH::SelectionProxy::GroupStd ) + subType = tr( "OBJECT_GROUP_STANDALONE" ); + else if ( type == SMESH::SelectionProxy::GroupGeom ) + subType = tr( "OBJECT_GROUP_GEOM" ); + else if ( type == SMESH::SelectionProxy::GroupFilter ) + subType = tr( "OBJECT_GROUP_FILTER" ); + if ( !subType.isEmpty() ) + typeName = QString( "%1 %2" ).arg( typeName, subType ); } - SMESH::long_array_var info = obj->GetMeshInfo(); - myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Node] ) ); - myWidgets[i0D][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_0D] ) ); - myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Ball] ) ); - long nbEdges = info[SMDSEntity_Edge] + info[SMDSEntity_Quad_Edge]; - myWidgets[i1D][iTotal] ->setProperty( "text", QString::number( nbEdges ) ); - myWidgets[i1D][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Edge] ) ); - myWidgets[i1D][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Edge] ) ); - long nbTriangles = info[SMDSEntity_Triangle] + info[SMDSEntity_Quad_Triangle]; - long nbQuadrangles = info[SMDSEntity_Quadrangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle]; - long nb2DLinear = info[SMDSEntity_Triangle] + info[SMDSEntity_Quadrangle] + info[SMDSEntity_Polygon]; - long nb2DQuadratic = info[SMDSEntity_Quad_Triangle] + info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle]; - myWidgets[i2D][iTotal] ->setProperty( "text", QString::number( nb2DLinear + nb2DQuadratic ) ); - myWidgets[i2D][iLinear] ->setProperty( "text", QString::number( nb2DLinear ) ); - myWidgets[i2D][iQuadratic] ->setProperty( "text", QString::number( nb2DQuadratic ) ); - myWidgets[i2DTriangles][iTotal] ->setProperty( "text", QString::number( nbTriangles ) ); - myWidgets[i2DTriangles][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Triangle] ) ); - myWidgets[i2DTriangles][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Triangle] ) ); - myWidgets[i2DQuadrangles][iTotal] ->setProperty( "text", QString::number( nbQuadrangles ) ); - myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Quadrangle] ) ); - myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Quadrangle] + info[SMDSEntity_BiQuad_Quadrangle] )); - myWidgets[i2DPolygons][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Polygon] ) ); - long nbTetrahedrons = info[SMDSEntity_Tetra] + info[SMDSEntity_Quad_Tetra]; - long nbHexahedrons = info[SMDSEntity_Hexa] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa]; - long nbPyramids = info[SMDSEntity_Pyramid] + info[SMDSEntity_Quad_Pyramid]; - long nbPrisms = info[SMDSEntity_Penta] + info[SMDSEntity_Quad_Penta]; - long nb3DLinear = info[SMDSEntity_Tetra] + info[SMDSEntity_Hexa] + info[SMDSEntity_Pyramid] + info[SMDSEntity_Penta] + info[SMDSEntity_Polyhedra] + info[SMDSEntity_Hexagonal_Prism]; - long nb3DQuadratic = info[SMDSEntity_Quad_Tetra] + info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] + info[SMDSEntity_Quad_Pyramid] + info[SMDSEntity_Quad_Penta]; - myWidgets[i3D][iTotal] ->setProperty( "text", QString::number( nb3DLinear + nb3DQuadratic ) ); - myWidgets[i3D][iLinear] ->setProperty( "text", QString::number( nb3DLinear ) ); - myWidgets[i3D][iQuadratic] ->setProperty( "text", QString::number( nb3DQuadratic ) ); - myWidgets[i3DTetrahedrons][iTotal] ->setProperty( "text", QString::number( nbTetrahedrons ) ); - myWidgets[i3DTetrahedrons][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Tetra] ) ); - myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( info[SMDSEntity_Quad_Tetra] ) ); - myWidgets[i3DHexahedrons][iTotal] ->setProperty( "text", QString::number( nbHexahedrons ) ); - myWidgets[i3DHexahedrons][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Hexa] ) ); - myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Hexa] + info[SMDSEntity_TriQuad_Hexa] ) ); - myWidgets[i3DPyramids][iTotal] ->setProperty( "text", QString::number( nbPyramids ) ); - myWidgets[i3DPyramids][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Pyramid] ) ); - myWidgets[i3DPyramids][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Pyramid] ) ); - myWidgets[i3DPrisms][iTotal] ->setProperty( "text", QString::number( nbPrisms ) ); - myWidgets[i3DPrisms][iLinear] ->setProperty( "text", QString::number( info[SMDSEntity_Penta] ) ); - myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", QString::number( info[SMDSEntity_Quad_Penta] ) ); - myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Hexagonal_Prism] ) ); - myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", QString::number( info[SMDSEntity_Polyhedra] ) ); - - // before full loading from study file, type of elements in a sub-mesh can't be defined - // in some cases - bool infoOK = obj->IsMeshInfoCorrect(); - myLoadBtn->setVisible( !infoOK ); - if ( !infoOK ) + widget( iObject, iSingle )->setProperty( "text", typeName ); + + // node info + uint nbNodes = info[SMDSEntity_Node]; + widget( iNodes, iTotal )->setProperty( "value", nbNodes ); + + // element info + // - 0D elements info + uint nb0d = info[SMDSEntity_0D]; + widget( i0D, iTotal )->setProperty( "value", nb0d ); + // - balls info + uint nbBalls = info[SMDSEntity_Ball]; + widget( iBalls, iTotal )->setProperty( "value", nbBalls ); + // - 1D elements info + uint nb1dLin = info[SMDSEntity_Edge]; + uint nb1dQua = info[SMDSEntity_Quad_Edge]; + uint nb1d = nb1dLin + nb1dQua; + widget( i1D, iLinear )->setProperty( "value", nb1dLin ); + widget( i1D, iQuadratic )->setProperty( "value", nb1dQua ); + widget( i1D, iTotal )->setProperty( "value", nb1d ); + // - 2D elements info + // --+ triangles + uint nbTriLin = info[SMDSEntity_Triangle]; + uint nbTriQua = info[SMDSEntity_Quad_Triangle]; + uint nbTriBiq = info[SMDSEntity_BiQuad_Triangle]; + uint nbTri = nbTriLin + nbTriQua + nbTriBiq; + widget( i2DTriangles, iLinear )->setProperty( "value", nbTriLin ); + widget( i2DTriangles, iQuadratic )->setProperty( "value", nbTriQua ); + widget( i2DTriangles, iBiQuadratic )->setProperty( "value", nbTriBiq ); + widget( i2DTriangles, iTotal )->setProperty( "value", nbTri ); + // --+ quadrangles + uint nbQuadLin = info[SMDSEntity_Quadrangle]; + uint nbQuadQua = info[SMDSEntity_Quad_Quadrangle]; + uint nbQuadBiq = info[SMDSEntity_BiQuad_Quadrangle]; + uint nbQuad = nbQuadLin + nbQuadQua + nbQuadBiq; + widget( i2DQuadrangles, iLinear )->setProperty( "value", nbQuadLin ); + widget( i2DQuadrangles, iQuadratic )->setProperty( "value", nbQuadQua ); + widget( i2DQuadrangles, iBiQuadratic )->setProperty( "value", nbQuadBiq ); + widget( i2DQuadrangles, iTotal )->setProperty( "value", nbQuad ); + // --+ polygons + uint nbPolyLin = info[SMDSEntity_Polygon]; + uint nbPolyQua = info[SMDSEntity_Quad_Polygon]; + uint nbPoly = nbPolyLin + nbPolyQua; + widget( i2DPolygons, iLinear )->setProperty( "value", nbPolyLin ); + widget( i2DPolygons, iQuadratic )->setProperty( "value", nbPolyQua ); + widget( i2DPolygons, iTotal )->setProperty( "value", nbPoly ); + // --+ summary + uint nb2dLin = nbTriLin + nbQuadLin + nbPolyLin; + uint nb2dQua = nbTriQua + nbQuadQua + nbPolyQua; + uint nb2dBiq = nbTriBiq + nbQuadBiq; + uint nb2d = nb2dLin + nb2dQua + nb2dBiq; + widget( i2D, iLinear )->setProperty( "value", nb2dLin ); + widget( i2D, iQuadratic )->setProperty( "value", nb2dQua ); + widget( i2D, iBiQuadratic )->setProperty( "value", nb2dBiq ); + widget( i2D, iTotal )->setProperty( "value", nb2d ); + // - 3D elements info + // --+ tetras + uint nbTetraLin = info[SMDSEntity_Tetra]; + uint nbTetraQua = info[SMDSEntity_Quad_Tetra]; + uint nbTetra = nbTetraLin + nbTetraQua; + widget( i3DTetrahedrons, iLinear )->setProperty( "value", nbTetraLin ); + widget( i3DTetrahedrons, iQuadratic )->setProperty( "value", nbTetraQua ); + widget( i3DTetrahedrons, iTotal )->setProperty( "value", nbTetra ); + // --+ hexas + uint nbHexaLin = info[SMDSEntity_Hexa]; + uint nbHexaQua = info[SMDSEntity_Quad_Hexa]; + uint nbHexaBiq = info[SMDSEntity_TriQuad_Hexa]; + uint nbHexa = nbHexaLin + nbHexaQua + nbHexaBiq; + widget( i3DHexahedrons, iLinear )->setProperty( "value", nbHexaLin ); + widget( i3DHexahedrons, iQuadratic )->setProperty( "value", nbHexaQua ); + widget( i3DHexahedrons, iBiQuadratic )->setProperty( "value", nbHexaBiq ); + widget( i3DHexahedrons, iTotal )->setProperty( "value", nbHexa ); + // --+ pyramids + uint nbPyraLin = info[SMDSEntity_Pyramid]; + uint nbPyraQua = info[SMDSEntity_Quad_Pyramid]; + uint nbPyra = nbPyraLin + nbPyraQua; + widget( i3DPyramids, iLinear )->setProperty( "value", nbPyraLin ); + widget( i3DPyramids, iQuadratic )->setProperty( "value", nbPyraQua ); + widget( i3DPyramids, iTotal )->setProperty( "value", nbPyra ); + // --+ prisms + uint nbPentaLin = info[SMDSEntity_Penta]; + uint nbPentaQua = info[SMDSEntity_Quad_Penta]; + uint nbPentaBiq = info[SMDSEntity_BiQuad_Penta]; + uint nbPenta = nbPentaLin + nbPentaQua + nbPentaBiq; + widget( i3DPrisms, iLinear )->setProperty( "value", nbPentaLin ); + widget( i3DPrisms, iQuadratic )->setProperty( "value", nbPentaQua ); + widget( i3DPrisms, iBiQuadratic )->setProperty( "value", nbPentaBiq ); + widget( i3DPrisms, iTotal )->setProperty( "value", nbPenta ); + // --+ hexagonal prisms + uint nbHexaPri = info[SMDSEntity_Hexagonal_Prism]; + widget( i3DHexaPrisms, iTotal )->setProperty( "value", nbHexaPri ); + // --+ polyhedrons + uint nbPolyhedra = info[SMDSEntity_Polyhedra]; + widget( i3DPolyhedrons, iTotal )->setProperty( "value", nbPolyhedra ); + // --+ summary + uint nb3dLin = nbTetraLin + nbHexaLin + nbPyraLin + nbPentaLin + nbHexaPri + nbPolyhedra; + uint nb3dQua = nbTetraQua + nbHexaQua + nbPyraQua + nbPentaQua; + uint nb3dBiq = nbHexaBiq + nbPentaBiq; + uint nb3d = nb3dLin + nb3dQua + nb3dBiq; + widget( i3D, iLinear )->setProperty( "value", nb3dLin ); + widget( i3D, iQuadratic )->setProperty( "value", nb3dQua ); + widget( i3D, iBiQuadratic )->setProperty( "value", nb3dBiq ); + widget( i3D, iTotal )->setProperty( "value", nb3d ); + // - summary + uint nbElemLin = nb1dLin + nb2dLin + nb3dLin; + uint nbElemQua = nb1dQua + nb2dQua + nb3dQua; + uint nbElemBiq = nb2dBiq + nb3dBiq; + uint nbElem = nb0d + nbBalls + nb1d + nb2d + nb3d; + widget( iElementsTotal, iLinear )->setProperty( "value", nbElemLin ); + widget( iElementsTotal, iQuadratic )->setProperty( "value", nbElemQua ); + widget( iElementsTotal, iBiQuadratic )->setProperty( "value", nbElemBiq ); + widget( iElementsTotal, iTotal )->setProperty( "value", nbElem ); + + // show 'Load' button if data was not loaded yet + widget( iEnd, iSingle )->setVisible( !proxy.isValid() ); + + // until data is loaded from study file, type of elements in a sub-mesh or group + // can be undefined in some cases + if ( !proxy.isValid() ) { - // two options: - // 1. Type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh) - // 2. No info at all (for a group on geom or filter) - bool hasAnyInfo = false; - for ( size_t i = 0; i < info->length() && !hasAnyInfo; ++i ) - hasAnyInfo = info[i]; - if ( hasAnyInfo ) // believe it is a sub-mesh + // two cases are possible: + // 1. type of 2D or 3D elements is unknown but their nb is OK (for a sub-mesh) + // 2. there is no info at all (for a group on geom or on filter) + if ( info.count( SMDSEntity_Node, SMDSEntity_Last ) > 0 ) // believe it is a sub-mesh { - if ( nb2DLinear + nb2DQuadratic > 0 ) + if ( nb2dLin + nb2dQua + nb2dBiq > 0 ) { - myWidgets[i2D][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2D][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iTotal] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iTotal] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iQuadratic]->setProperty( "text", "?" ); - myWidgets[i2DPolygons][iTotal] ->setProperty( "text", "?" ); + // we know nothing about triangles, quadranges and polygons + for ( int i = i2DTriangles; i < i2DEnd; i++ ) + { + for ( int j = iTotal; j < iNbColumns; j++ ) + { + if ( widget( i, j ) ) + widget( i, j )->setProperty( "text", "?" ); + } + } + // we don't know if elements are linear, quadratic or bi-quadratic + for ( int j = iLinear; j < iNbColumns; j++ ) + { + if ( widget( i2D, j ) ) + widget( i2D, j )->setProperty( "text", "?" ); + if ( widget( iElementsTotal, j ) ) + widget( iElementsTotal, j )->setProperty( "text", "?" ); + } } - else if ( nb3DLinear + nb3DQuadratic > 0 ) + else if ( nb3dLin + nb3dQua + nb3dBiq > 0 ) { - myWidgets[i3D][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3D][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", "?" ); + // we know nothing about tetras, hexas, etc. + for ( int i = i3DTetrahedrons; i < i3DEnd; i++ ) + { + for ( int j = iTotal; j < iNbColumns; j++ ) + { + if ( widget( i, j ) ) + widget( i, j )->setProperty( "text", "?" ); + } + } + // we don't know if elements are linear, quadratic or bi-quadratic + for ( int j = iLinear; j < iNbColumns; j++ ) + { + if ( widget( i3D, j ) ) + widget( i3D, j )->setProperty( "text", "?" ); + if ( widget( iElementsTotal, j ) ) + widget( iElementsTotal, j )->setProperty( "text", "?" ); + } } } else { - myWidgets[iNodes][iTotal] ->setProperty( "text", "?" ); - myWidgets[i0D][iTotal] ->setProperty( "text", "?" ); - myWidgets[iBalls][iTotal] ->setProperty( "text", "?" ); - myWidgets[i1D][iTotal] ->setProperty( "text", "?" ); - myWidgets[i1D][iLinear] ->setProperty( "text", "?" ); - myWidgets[i1D][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2D][iTotal] ->setProperty( "text", "?" ); - myWidgets[i2D][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2D][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iTotal] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2DTriangles][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iTotal] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", "?" ); - myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i2DPolygons][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3D][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3D][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3D][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DPyramids][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iLinear] ->setProperty( "text", "?" ); - myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", "?" ); - myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", "?" ); - myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", "?" ); + // we know nothing about nodes :( + widget( iNodes, iTotal )->setProperty( "text", "?" ); + // we know nothing about elements :( + for ( int i = iElementsTotal; i < iElementsEnd; i++ ) + { + for ( int j = iTotal; j < iNbColumns; j++ ) + { + if ( widget( i, j ) ) + widget( i, j )->setProperty( "text", "?" ); + } + } } } } } /*! - \brief Load mesh from a study file + \brief Update information in panel. */ -void SMESHGUI_MeshInfo::loadMesh() +void SMESHGUI_BaseInfo::updateInfo() { - SUIT_OverrideCursor wc; - - SALOME_ListIO selected; - SMESHGUI::selectionMgr()->selectedObjects( selected ); - - if ( selected.Extent() == 1 ) { - Handle(SALOME_InteractiveObject) IO = selected.First(); - SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); - if ( !CORBA::is_nil( obj ) ) { - SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); - if ( !mesh->_is_nil() ) - { - mesh->Load(); - showInfo( obj ); - } - } - } + showInfo( myProxy ); } /*! - \brief Reset the widget to the initial state (nullify all fields). + \brief Load mesh from a study file. */ -void SMESHGUI_MeshInfo::clear() +void SMESHGUI_BaseInfo::loadMesh() { - myWidgets[iName][iSingle] ->setProperty( "text", QString() ); - myWidgets[iObject][iSingle] ->setProperty( "text", QString() ); - myWidgets[iNodes][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i0D][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[iBalls][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i1D][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i1D][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i1D][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2D][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2D][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2D][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DTriangles][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DTriangles][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DTriangles][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DQuadrangles][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DQuadrangles][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DQuadrangles][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i2DPolygons][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3D][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3D][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3D][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DTetrahedrons][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DTetrahedrons][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DTetrahedrons][iQuadratic]->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DHexahedrons][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DHexahedrons][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DHexahedrons][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPyramids][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPyramids][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPyramids][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPrisms][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPrisms][iLinear] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPrisms][iQuadratic] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DHexaPrisms][iTotal] ->setProperty( "text", QString::number( 0 ) ); - myWidgets[i3DPolyhedrons][iTotal] ->setProperty( "text", QString::number( 0 ) ); + SUIT_OverrideCursor wc; + if ( myProxy ) + { + myProxy.load(); + updateInfo(); + } } /*! - \brief Create info field - \return new info field + \brief Reset panel (clear all data). */ -QLabel* SMESHGUI_MeshInfo::createField() +void SMESHGUI_BaseInfo::clear() { - QLabel* lab = new QLabel( this ); - lab->setFrameStyle( StyledPanel | Sunken ); - lab->setAlignment( Qt::AlignCenter ); - lab->setAutoFillBackground( true ); - QPalette pal = lab->palette(); - pal.setColor( QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Base ) ); - lab->setPalette( pal ); - lab->setMinimumWidth( 70 ); - return lab; + // - name + widget( iName, iSingle )->setProperty( "text", QString() ); + // - type + widget( iObject, iSingle )->setProperty( "text", QString() ); + // - nodes + widget( iNodes, iTotal )->setProperty( "value", 0 ); + // - elements + for ( int i = iElementsTotal; i < iElementsEnd; i++ ) + { + for ( int j = iTotal; j < iNbColumns; j++ ) + { + if ( widget( i, j ) ) + widget( i, j )->setProperty( "value", 0 ); + } + } + // hide 'Load' button + widget( iEnd, iSingle )->setVisible( false ); } /*! - \brief Create horizontal rule. - \return new line object + \brief Register widget in a grid. + \param w Widget being added. + \param row Row index in a grid. + \param column Column index in a grid. + \param colspan Number of columns to span in a grid. Defaults to 1. + \return Just added widget. */ -QWidget* SMESHGUI_MeshInfo::createLine() +QWidget* SMESHGUI_BaseInfo::addWidget( QWidget* w, int row, int column, int colspan ) { - QFrame* line = new QFrame( this ); - line->setFrameStyle( HLine | Sunken ); - return line; + if ( !myWidgets.contains( row ) ) + myWidgets[row] = wlist(); + myWidgets[row][column] = w; + dynamic_cast( layout() )->addWidget( w, row, column, 1, colspan ); + return w; } /*! - \brief Change widget font attributes (bold, italic, ...). - \param w widget - \param attr font attributes (XORed flags) - \param val value to be set to attributes + \brief Get registered widget. + \param row Row index in a grid. + \param column Column index in a grid. + \return Widget stored in a given grid cell (0 if there's no widget). */ -void SMESHGUI_MeshInfo::setFontAttributes( QWidget* w, int attr, bool val ) +QWidget* SMESHGUI_BaseInfo::widget( int row, int column ) const { - if ( w && attr ) { - QFont f = w->font(); - if ( attr & Bold ) f.setBold( val ); - if ( attr & Italic ) f.setItalic( val ); - w->setFont( f ); - } + return myWidgets.contains( row ) && myWidgets[row].contains( column ) ? myWidgets[row][column] : 0; } /*! - \brief Show/hide group(s) of fields. - \param start beginning of the block - \param end end of the block - \param on visibility flag + \brief Get text value from registered widget. + \param row Row index in a grid. + \param column Column index in a grid. + \return Value string (empty string if no label in given cell). */ -void SMESHGUI_MeshInfo::setFieldsVisible( int start, int end, bool on ) +QString SMESHGUI_BaseInfo::value( int row, int column ) const { - start = qMax( 0, start ); - end = qMin( end, (int)iElementsEnd ); - for ( int i = start; i < end; i++ ) { - wlist wl = myWidgets[i]; - foreach ( QWidget* w, wl ) w->setVisible( on ); - } + return widgetValue( widget( row, column ) ); } /*! - \class SMESHGUI_ElemInfo - \brief Base class for the mesh element information widget. -*/ - -/*! - \brief Constructor - \param parent parent widget + \brief Show/hide group(s) of widgets. + \param startRow Starting grid row. + \param lastRow Last grid row. + \param on Visibility flag. */ -SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ) -: QWidget( parent ), myActor( 0 ), myIsElement( -1 ) +void SMESHGUI_BaseInfo::setFieldsVisible( int startRow, int lastRow, bool on ) { - myFrame = new QWidget( this ); - myExtra = new ExtraWidget( this ); - QVBoxLayout* vbl = new QVBoxLayout( this ); - vbl->setMargin( 0 ); - vbl->setSpacing( 0 ); - vbl->addWidget( myFrame ); - vbl->addWidget( myExtra ); - connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) ); - connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) ); - clear(); + startRow = qMax( 0, startRow ); + lastRow = qMin( lastRow, (int)iEnd ); + for ( int i = startRow; i <= lastRow; i++ ) + { + wlist widgets = myWidgets[i]; + foreach ( QWidget* w, widgets ) + w->setVisible( on ); + } } /*! - \brief Destructor + \brief Write information from panel to ouput stream. + \param out Text stream output. */ -SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo() +void SMESHGUI_BaseInfo::saveInfo( QTextStream& out ) { + // title + QString title = tr( "BASE_INFO" ); + out << ruler( title.size() ) << endl; + out << title << endl; + out << ruler( title.size() ) << endl; + out << endl; + + // object info + // - name + out << tr( "NAME_LAB" ) << spacing() << value( iName, iSingle ) << endl; + // - type + out << tr( "OBJECT_LAB" ) << spacing() << value( iObject, iSingle ) << endl; + // - --- (separator) + out << endl; + + // node info + out << tr( "NODES_LAB" ) << spacing() << value( iNodes, iTotal ) << endl; + // - --- (separator) + out << endl; + + // element info + QString lin = tr( "LINEAR_LAB" ) + ":" + spacing(); + QString qua = tr( "QUADRATIC_LAB" ) + ":" + spacing(); + QString biq = tr( "BI_QUADRATIC_LAB" ) + ":" + spacing(); + // - summary + out << tr( "ELEMENTS_LAB" ) << spacing() << value( iElementsTotal, iTotal ) << endl; + out << indent(1) << lin << value( iElementsTotal, iLinear ) << endl; + out << indent(1) << qua << value( iElementsTotal, iQuadratic ) << endl; + out << indent(1) << biq << value( iElementsTotal, iBiQuadratic ) << endl; + // - --- (separator) + out << endl; + // - 0D elements info + out << indent(1) << tr( "0D_LAB" ) << spacing() << value( i0D, iTotal ) << endl; + // - --- (separator) + out << endl; + // - balls info + out << indent(1) << tr( "BALL_LAB" ) << spacing() << value( iBalls, iTotal ) << endl; + // - --- (separator) + out << endl; + // - 1D elements info + out << indent(1) << tr( "1D_LAB" ) << spacing() << value( i1D, iTotal ) << endl; + out << indent(2) << lin << value( i1D, iLinear ) << endl; + out << indent(2) << qua << value( i1D, iQuadratic ) << endl; + // - --- (separator) + out << endl; + // - 2D elements info + // - summary + out << indent(1) << tr( "2D_LAB" ) << spacing() << value( i2D, iTotal ) << endl; + out << indent(2) << lin << value( i2D, iLinear ) << endl; + out << indent(2) << qua << value( i2D, iQuadratic ) << endl; + out << indent(2) << biq << value( i2D, iBiQuadratic ) << endl; + // - --- (separator) + out << endl; + // --+ triangles + out << indent(2) << tr( "TRIANGLES_LAB" ) << spacing() << value( i2DTriangles, iTotal ) << endl; + out << indent(3) << lin << value( i2DTriangles, iLinear ) << endl; + out << indent(3) << qua << value( i2DTriangles, iQuadratic ) << endl; + out << indent(3) << biq << value( i2DTriangles, iBiQuadratic ) << endl; + // --+ quadrangles + out << indent(2) << tr( "QUADRANGLES_LAB" ) << spacing() << value( i2DQuadrangles, iTotal ) << endl; + out << indent(3) << lin << value( i2DQuadrangles, iLinear ) << endl; + out << indent(3) << qua << value( i2DQuadrangles, iQuadratic ) << endl; + out << indent(3) << biq << value( i2DQuadrangles, iBiQuadratic ) << endl; + // --+ polygons + out << indent(2) << tr( "POLYGONS_LAB" ) << spacing() << value( i2DPolygons, iTotal ) << endl; + out << indent(3) << lin << value( i2DPolygons, iLinear ) << endl; + out << indent(3) << qua << value( i2DPolygons, iQuadratic ) << endl; + // - --- (separator) + out << endl; + // - 3D elements info + // --+ summary + out << indent(1) << tr( "3D_LAB" ) << spacing() << value( i3D, iTotal ) << endl; + out << indent(2) << lin << value( i3D, iLinear ) << endl; + out << indent(2) << qua << value( i3D, iQuadratic ) << endl; + out << indent(2) << biq << value( i3D, iBiQuadratic ) << endl; + // - --- (separator) + out << endl; + // --+ tetras + out << indent(2) << tr( "TETRAHEDRONS_LAB" ) << spacing() << value( i3DTetrahedrons, iTotal ) << endl; + out << indent(3) << lin << value( i3DTetrahedrons, iLinear ) << endl; + out << indent(3) << qua << value( i3DTetrahedrons, iQuadratic ) << endl; + // --+ hexas + out << indent(2) << tr( "HEXAHEDONRS_LAB" ) << spacing() << value( i3DHexahedrons, iTotal ) << endl; + out << indent(3) << lin << value( i3DHexahedrons, iLinear ) << endl; + out << indent(3) << qua << value( i3DHexahedrons, iQuadratic ) << endl; + out << indent(3) << biq << value( i3DHexahedrons, iBiQuadratic ) << endl; + // --+ pyramids + out << indent(2) << tr( "PYRAMIDS_LAB" ) << spacing() << value( i3DPyramids, iTotal ) << endl; + out << indent(3) << lin << value( i3DPyramids, iLinear ) << endl; + out << indent(3) << qua << value( i3DPyramids, iQuadratic ) << endl; + // --+ prisms + out << indent(2) << tr( "PRISMS_LAB" ) << spacing() << value( i3DPrisms, iTotal ) << endl; + out << indent(3) << lin << value( i3DPrisms, iLinear ) << endl; + out << indent(3) << qua << value( i3DPrisms, iQuadratic ) << endl; + out << indent(3) << biq << value( i3DPrisms, iBiQuadratic ) << endl; + // --+ hexagonal prisms + out << indent(2) << tr( "HEX_PRISMS_LAB" ) << spacing() << value( i3DHexaPrisms, iTotal ) << endl; + // --+ polyhedrons + out << indent(2) << tr( "POLYHEDRONS_LAB" ) << spacing() << value( i3DPolyhedrons, iTotal ) << endl; + // - --- (separator) + out << endl; } -/*! - \brief Set mesh data source (actor) - \param actor mesh object actor -*/ -void SMESHGUI_ElemInfo::setSource( SMESH_Actor* actor ) +//////////////////////////////////////////////////////////////////////////////// +/// \class InfoWriter +/// \brief Base info writer class. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class InfoWriter { - if ( myActor != actor ) { - myActor = actor; - myIsElement = -1; - clear(); - } -} +protected: + int myPrecision; + bool myRecursive; +public: + InfoWriter( bool = false ); + void write( const QString&, bool = false ); + void write( const QString&, const QString&, bool = false ); + void write( const QString&, int, bool = false ); + void write( const QString&, double, bool = false ); + void write( const QString&, const SMESH::XYZ&, bool = false ); + virtual void indent() {} + virtual void unindent() {} + virtual void separator() {} +protected: + virtual void put( const QString&, const QString&, bool = false ) = 0; +}; -/*! - \brief Show mesh element information - \param id mesh node / element ID - \param isElem show mesh element information if \c true or mesh node information if \c false -*/ -void SMESHGUI_ElemInfo::showInfo( long id, bool isElem ) +InfoWriter::InfoWriter( bool r ): myRecursive(r) { - QSet ids; - ids << id; - showInfo( ids, isElem ); + myPrecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); } -/*! - \brief Show mesh element information - \param ids mesh nodes / elements identifiers - \param isElem show mesh element information if \c true or mesh node information if \c false -*/ -void SMESHGUI_ElemInfo::showInfo( QSet ids, bool isElem ) +void InfoWriter::write( const QString& key, bool emphasize ) { - QList newIds = ids.toList(); - qSort( newIds ); - if ( myIDs == newIds && myIsElement == isElem ) return; - - myIDs = newIds; - myIsElement = isElem; - myIndex = 0; - updateControls(); - information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) ); + put( key, QString(), emphasize ); } -/*! - \brief Clear mesh element information widget -*/ -void SMESHGUI_ElemInfo::clear() +void InfoWriter::write( const QString& key, const QString& value, bool emphasize ) { - myIDs.clear(); - myIndex = 0; - clearInternal(); - updateControls(); + put( key, value, emphasize ); } -/*! - \brief Get central area widget - \return central widget -*/ -QWidget* SMESHGUI_ElemInfo::frame() const +void InfoWriter::write( const QString& key, int value, bool emphasize ) { - return myFrame; + put( key, QString::number( value ), emphasize ); } -/*! - \brief Get actor - \return actor being used -*/ -SMESH_Actor* SMESHGUI_ElemInfo::actor() const +void InfoWriter::write( const QString& key, double value, bool emphasize ) { - return myActor; + put( key, QString::number( value, myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ), emphasize ); } -/*! - \brief Get current info mode. - \return \c true if mesh element information is shown or \c false if node information is shown -*/ -bool SMESHGUI_ElemInfo::isElements() const +void InfoWriter::write( const QString& key, const SMESH::XYZ& value, bool emphasize ) { - return myIsElement; + if ( myRecursive ) + { + write( key, emphasize ); + indent(); + write( "X", value.x() ); + write( "Y", value.y() ); + write( "Z", value.z() ); + unindent(); + } + else + { + QStringList vl; + vl << QString::number( value.x(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ); + vl << QString::number( value.y(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ); + vl << QString::number( value.z(), myPrecision > 0 ? 'f' : 'g', qAbs( myPrecision ) ); + put( key, vl.join( ", " ), emphasize ); + } } -/*! - \fn void SMESHGUI_ElemInfo::information( const QList& ids ) - \brief Show information on the specified nodes / elements - - This function is to be redefined in sub-classes. +//////////////////////////////////////////////////////////////////////////////// +/// \class SimpleWriter +/// \brief Base text writer. +/// \internal +//////////////////////////////////////////////////////////////////////////////// - \param ids nodes / elements identifiers information is to be shown on -*/ +class SimpleWriter: public InfoWriter +{ +protected: + int myIndent; +public: + SimpleWriter(); + void indent(); + void unindent(); + void separator(); +protected: + void put( const QString&, const QString&, bool ); + virtual QString spacer() const; + virtual QString decorate( const QString& ) const; + virtual void dumpLine( const QString& ) = 0; +}; -/*! - \brief Internal clean-up (reset widget) -*/ -void SMESHGUI_ElemInfo::clearInternal() +SimpleWriter::SimpleWriter(): InfoWriter(false), myIndent(0) { } -/*! - \brief Get node connectivity - \param node mesh node - \return node connectivity map -*/ -SMESHGUI_ElemInfo::Connectivity SMESHGUI_ElemInfo::nodeConnectivity( const SMDS_MeshNode* node ) +void SimpleWriter::indent() { - Connectivity elmap; - if ( node ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while ( it && it->more() ) { - const SMDS_MeshElement* ne = it->next(); - elmap[ ne->GetType() ] << ne->GetID(); - } - } - return elmap; + myIndent += 1; } -/*! - \brief Format connectivity data to string representation - \param connectivity connetivity map - \param type element type - \return string representation of the connectivity -*/ -QString SMESHGUI_ElemInfo::formatConnectivity( Connectivity connectivity, int type ) +void SimpleWriter::unindent() { - QStringList str; - if ( connectivity.contains( type ) ) { - QList elements = connectivity[ type ]; - qSort( elements ); - foreach( int id, elements ) - str << QString::number( id ); - } - return str.join( " " ); + myIndent = qMax( myIndent-1, 0 ); } -/*! - \brief Calculate gravity center of the mesh element - \param element mesh element -*/ -SMESHGUI_ElemInfo::XYZ SMESHGUI_ElemInfo::gravityCenter( const SMDS_MeshElement* element ) +void SimpleWriter::separator() { - XYZ xyz; - if ( element ) { - SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - xyz.add( node->X(), node->Y(), node->Z() ); - } - xyz.divide( element->NbNodes() ); - } - return xyz; + write( "" ); } -/*! - \brief This slot is called from "Show Previous" button click. - Shows information on the previous group of the items. -*/ -void SMESHGUI_ElemInfo::showPrevious() +QString SimpleWriter::spacer() const { - myIndex = qMax( 0, myIndex-1 ); - updateControls(); - information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) ); + return " "; } -/*! - \brief This slot is called from "Show Next" button click. - Shows information on the next group of the items. -*/ -void SMESHGUI_ElemInfo::showNext() +QString SimpleWriter::decorate( const QString& s ) const { - myIndex = qMin( myIndex+1, myIDs.count() / MAXITEMS ); - updateControls(); - information( myIDs.mid( myIndex*MAXITEMS, MAXITEMS ) ); + return s; } -/*! - \brief Update widgets state -*/ -void SMESHGUI_ElemInfo::updateControls() +void SimpleWriter::put( const QString& key, const QString& value, bool emphasize ) { - myExtra->updateControls( myIDs.count(), myIndex ); + QString line; + line += ::indent( spacer(), myIndent*4 ); + line += decorate( key ); + if ( !value.isEmpty() ) + { + line += ":"; + line += emphasize ? decorate( value ) : value; + } + dumpLine( line ); } -/*! - \class SMESHGUI_SimpleElemInfo - \brief Represents mesh element information in the simple text area. -*/ +//////////////////////////////////////////////////////////////////////////////// +/// \class StreamWriter +/// \brief Writer for QTextStream. +/// \internal +//////////////////////////////////////////////////////////////////////////////// -/*! - \brief Constructor - \param parent parent widget -*/ -SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent ) -: SMESHGUI_ElemInfo( parent ) +class StreamWriter: public SimpleWriter { - myInfo = new QTextBrowser( frame() ); - QVBoxLayout* l = new QVBoxLayout( frame() ); - l->setMargin( 0 ); - l->addWidget( myInfo ); -} + QTextStream& myOut; +public: + StreamWriter( QTextStream& ); +protected: + void dumpLine( const QString& ); +}; -/*! - \brief Show mesh element information - \param ids mesh nodes / elements identifiers -*/ -void SMESHGUI_SimpleElemInfo::information( const QList& ids ) +StreamWriter::StreamWriter( QTextStream& out ): SimpleWriter(), myOut(out) { - clearInternal(); - - if ( actor() ) { - int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); - foreach ( long id, ids ) { - if ( !isElements() ) { - // - // show node info - // - const SMDS_MeshNode* node = actor()->GetObject()->GetMesh()->FindNode( id ); - if ( !node ) return; - - // node ID - myInfo->append( QString( "%1 #%2" ).arg( tr( "NODE" ) ).arg( id ) ); - // separator - myInfo->append( "" ); - // coordinates - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). - arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). - arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). - arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - // separator - myInfo->append( "" ); - // connectivity - Connectivity connectivity = nodeConnectivity( node ); - if ( !connectivity.isEmpty() ) { - myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); - QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Edge ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Ball ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "BALL_ELEMENTS" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Face ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Volume ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); - } - else { - myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); - } - } - else { - // - // show element info - // - const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id ); - if ( !e ) return; - - // element ID && type - QString stype; - switch( e->GetType() ) { - case SMDSAbs_0DElement: - stype = tr( "0D ELEMENT" ); break; - case SMDSAbs_Ball: - stype = tr( "BALL" ); break; - case SMDSAbs_Edge: - stype = tr( "EDGE" ); break; - case SMDSAbs_Face: - stype = tr( "FACE" ); break; - case SMDSAbs_Volume: - stype = tr( "VOLUME" ); break; - default: - break; - } - if ( stype.isEmpty() ) return; - myInfo->append( QString( "%1 #%2" ).arg( stype ).arg( id ) ); - // separator - myInfo->append( "" ); - // geometry type - QString gtype; - switch( e->GetEntityType() ) { - case SMDSEntity_Triangle: - case SMDSEntity_Quad_Triangle: - gtype = tr( "TRIANGLE" ); break; - case SMDSEntity_Quadrangle: - case SMDSEntity_Quad_Quadrangle: - case SMDSEntity_BiQuad_Quadrangle: - gtype = tr( "QUADRANGLE" ); break; - case SMDSEntity_Polygon: - case SMDSEntity_Quad_Polygon: - gtype = tr( "POLYGON" ); break; - case SMDSEntity_Tetra: - case SMDSEntity_Quad_Tetra: - gtype = tr( "TETRAHEDRON" ); break; - case SMDSEntity_Pyramid: - case SMDSEntity_Quad_Pyramid: - gtype = tr( "PYRAMID" ); break; - case SMDSEntity_Hexa: - case SMDSEntity_Quad_Hexa: - case SMDSEntity_TriQuad_Hexa: - gtype = tr( "HEXAHEDRON" ); break; - case SMDSEntity_Penta: - case SMDSEntity_Quad_Penta: - gtype = tr( "PRISM" ); break; - case SMDSEntity_Hexagonal_Prism: - gtype = tr( "HEX_PRISM" ); break; - case SMDSEntity_Polyhedra: - case SMDSEntity_Quad_Polyhedra: - gtype = tr( "POLYHEDRON" ); break; - default: - break; - } - if ( !gtype.isEmpty() ) - myInfo->append( QString( "%1: %2" ).arg( tr( "TYPE" ) ).arg( gtype ) ); - // quadratic flag and gravity center (any element except 0D) - if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) { - // quadratic flag - myInfo->append( QString( "%1? %2" ).arg( tr( "QUADRATIC" ) ).arg( e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ) ); - // separator - myInfo->append( "" ); - // gravity center - XYZ gc = gravityCenter( e ); - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "GRAVITY_CENTER" ) ).arg( gc.x() ).arg( gc.y() ).arg( gc.z() ) ); - } - if ( const SMDS_BallElement* ball = dynamic_cast( e )) { - // ball diameter - myInfo->append( QString( "%1: %2" ).arg( tr( "BALL_DIAMETER" ) ).arg( ball->GetDiameter() )); - } - // separator - myInfo->append( "" ); - // connectivity - SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); - for ( int idx = 1; nodeIt->more(); idx++ ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - // node number and ID - myInfo->append( QString( "%1 %2/%3 - #%4" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ).arg( node->GetID() ) ); - // node coordinates - myInfo->append( QString( "%1: (%2, %3, %4)" ).arg( tr( "COORDINATES" ) ). - arg( node->X(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). - arg( node->Y(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ). - arg( node->Z(), 0, precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - // node connectivity - Connectivity connectivity = nodeConnectivity( node ); - if ( !connectivity.isEmpty() ) { - myInfo->append( QString( "%1:" ).arg( tr( "CONNECTIVITY" ) ) ); - QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "0D_ELEMENTS" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Edge ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "EDGES" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Face ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "FACES" ) ).arg( con ) ); - con = formatConnectivity( connectivity, SMDSAbs_Volume ); - if ( !con.isEmpty() ) - myInfo->append( QString( "- %1: %2" ).arg( tr( "VOLUMES" ) ).arg( con ) ); - } - else { - myInfo->append( QString( "%1" ).arg( tr( "FREE_NODE" ) ).arg( id ) ); - } - } - } - // separator - if ( ids.count() > 1 ) { - myInfo->append( "" ); - myInfo->append( "------" ); - myInfo->append( "" ); - } - } - } } -/*! - \brief Internal clean-up (reset widget) -*/ -void SMESHGUI_SimpleElemInfo::clearInternal() +void StreamWriter::dumpLine( const QString& line ) { - myInfo->clear(); + myOut << line; + myOut << endl; } -/*! - \class SMESHGUI_TreeElemInfo::ItemDelegate - \brief Item delegate for tree mesh info widget - \internal -*/ -class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate +//////////////////////////////////////////////////////////////////////////////// +/// \class TextWriter +/// \brief Writer for QTextBrowser. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class TextWriter: public SimpleWriter { + QTextBrowser* myInfo; public: - ItemDelegate( QObject* ); - QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; + TextWriter( QTextBrowser* ); +protected: + QString spacer() const; + QString decorate( const QString& ) const; + void dumpLine( const QString& ); }; -/*! - \brief Constructor - \internal -*/ -SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ) : QItemDelegate( parent ) +TextWriter::TextWriter( QTextBrowser* w ): SimpleWriter(), myInfo(w) { } -/*! - \brief Create item editor widget - \internal -*/ -QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +QString TextWriter::spacer() const { - QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index ); - if ( qobject_cast( w ) ) qobject_cast( w )->setReadOnly( true ); - return w; + return " "; } -/*! - \class SMESHGUI_TreeElemInfo - \brief Represents mesh element information in the tree-like form. -*/ +QString TextWriter::decorate( const QString& s ) const +{ + return bold( s ); +} -/*! - \brief Constructor - \param parent parent widget -*/ -SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent ) -: SMESHGUI_ElemInfo( parent ) +void TextWriter::dumpLine( const QString& line ) { - myInfo = new QTreeWidget( frame() ); - myInfo->setColumnCount( 2 ); - myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) ); - myInfo->header()->setStretchLastSection( true ); - myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); - myInfo->setItemDelegate( new ItemDelegate( myInfo ) ); - QVBoxLayout* l = new QVBoxLayout( frame() ); - l->setMargin( 0 ); - l->addWidget( myInfo ); + myInfo->append( line ); } -/*! - \brief Show mesh element information - \param ids mesh nodes / elements identifiers -*/ -void SMESHGUI_TreeElemInfo::information( const QList& ids ) +//////////////////////////////////////////////////////////////////////////////// +/// \class TreeWriter +/// \brief Writer for QTreeWidget. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class TreeWriter: public InfoWriter { - clearInternal(); + QTreeWidget* myInfo; + QTreeWidgetItem* myCurrentItem; + TreeItemCreator* myCreator; +public: + TreeWriter( QTreeWidget*, TreeItemCreator* ); + ~TreeWriter(); + void indent(); + void unindent(); +protected: + void put( const QString&, const QString&, bool = false ); +}; - if ( actor() ) { - int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); - foreach ( long id, ids ) { - if ( !isElements() ) { - // - // show node info - // - const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindNode( id ); - if ( !e ) return; - const SMDS_MeshNode* node = static_cast( e ); - - // node ID - QTreeWidgetItem* nodeItem = createItem( 0, Bold | All ); - nodeItem->setText( 0, tr( "NODE" ) ); - nodeItem->setText( 1, QString( "#%1" ).arg( id ) ); - // coordinates - QTreeWidgetItem* coordItem = createItem( nodeItem, Bold ); - coordItem->setText( 0, tr( "COORDINATES" ) ); - QTreeWidgetItem* xItem = createItem( coordItem ); - xItem->setText( 0, "X" ); - xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* yItem = createItem( coordItem ); - yItem->setText( 0, "Y" ); - yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* zItem = createItem( coordItem ); - zItem->setText( 0, "Z" ); - zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - // connectivity - QTreeWidgetItem* conItem = createItem( nodeItem, Bold ); - conItem->setText( 0, tr( "CONNECTIVITY" ) ); - Connectivity connectivity = nodeConnectivity( node ); - if ( !connectivity.isEmpty() ) { - QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "0D_ELEMENTS" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Ball ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "BALL_ELEMENTS" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Edge ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "EDGES" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Face ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "FACES" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Volume ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( conItem ); - i->setText( 0, tr( "VOLUMES" ) ); - i->setText( 1, con ); - } - } - else { - conItem->setText( 1, tr( "FREE_NODE" ) ); - } - // node position - int shapeID = node->getshapeId(); - if ( shapeID > 0 ) - { - SMDS_PositionPtr pos = node->GetPosition(); - SMDS_TypeOfPosition posType = pos->GetTypeOfPosition(); - QString shapeType; - double u,v; - switch ( posType ) { - case SMDS_TOP_EDGE: shapeType = tr( "EDGE" ); - u = static_cast( pos )->GetUParameter(); - break; - case SMDS_TOP_FACE: shapeType = tr( "FACE" ); - u = static_cast( pos )->GetUParameter(); - v = static_cast( pos )->GetVParameter(); - break; - case SMDS_TOP_VERTEX: shapeType = tr( "VERTEX" ); break; - default: shapeType = tr( "SOLID" ); - } - QTreeWidgetItem* posItem = createItem( nodeItem, Bold ); - posItem->setText( 0, tr("NODE_POSITION") ); - posItem->setText( 1, (shapeType + " #%1").arg( shapeID )); - if ( posType == SMDS_TOP_EDGE || posType == SMDS_TOP_FACE ) { - QTreeWidgetItem* uItem = createItem( posItem ); - uItem->setText( 0, tr("U_POSITION") ); - uItem->setText( 1, QString::number( u, precision > 0 ? 'f' : 'g', qAbs( precision ))); - if ( posType == SMDS_TOP_FACE ) { - QTreeWidgetItem* vItem = createItem( posItem ); - vItem->setText( 0, tr("V_POSITION") ); - vItem->setText( 1, QString::number( v, precision > 0 ? 'f' : 'g', qAbs( precision ))); - } - } - } - } - else { - // - // show element info - // - const SMDS_MeshElement* e = actor()->GetObject()->GetMesh()->FindElement( id ); - if ( !e ) return; - - // element ID && type - QString stype; - switch( e->GetType() ) { - case SMDSAbs_0DElement: - stype = tr( "0D ELEMENT" ); break; - case SMDSAbs_Ball: - stype = tr( "BALL" ); break; - case SMDSAbs_Edge: - stype = tr( "EDGE" ); break; - case SMDSAbs_Face: - stype = tr( "FACE" ); break; - case SMDSAbs_Volume: - stype = tr( "VOLUME" ); break; - default: - break; - } - if ( stype.isEmpty() ) return; - QTreeWidgetItem* elemItem = createItem( 0, Bold | All ); - elemItem->setText( 0, stype ); - elemItem->setText( 1, QString( "#%1" ).arg( id ) ); - // geometry type - QString gtype; - switch( e->GetEntityType() ) { - case SMDSEntity_Triangle: - case SMDSEntity_Quad_Triangle: - gtype = tr( "TRIANGLE" ); break; - case SMDSEntity_Quadrangle: - case SMDSEntity_Quad_Quadrangle: - case SMDSEntity_BiQuad_Quadrangle: - gtype = tr( "QUADRANGLE" ); break; - case SMDSEntity_Polygon: - case SMDSEntity_Quad_Polygon: - gtype = tr( "POLYGON" ); break; - case SMDSEntity_Tetra: - case SMDSEntity_Quad_Tetra: - gtype = tr( "TETRAHEDRON" ); break; - case SMDSEntity_Pyramid: - case SMDSEntity_Quad_Pyramid: - gtype = tr( "PYRAMID" ); break; - case SMDSEntity_Hexa: - case SMDSEntity_Quad_Hexa: - case SMDSEntity_TriQuad_Hexa: - gtype = tr( "HEXAHEDRON" ); break; - case SMDSEntity_Penta: - case SMDSEntity_Quad_Penta: - gtype = tr( "PRISM" ); break; - case SMDSEntity_Hexagonal_Prism: - gtype = tr( "HEX_PRISM" ); break; - case SMDSEntity_Polyhedra: - case SMDSEntity_Quad_Polyhedra: - gtype = tr( "POLYHEDRON" ); break; - default: - break; - } - if ( !gtype.isEmpty() ) { - QTreeWidgetItem* typeItem = createItem( elemItem, Bold ); - typeItem->setText( 0, tr( "TYPE" ) ); - typeItem->setText( 1, gtype ); - } - // quadratic flag and gravity center (any element except 0D) - if ( e->GetEntityType() > SMDSEntity_0D && e->GetEntityType() < SMDSEntity_Ball ) { - // quadratic flag - QTreeWidgetItem* quadItem = createItem( elemItem, Bold ); - quadItem->setText( 0, tr( "QUADRATIC" ) ); - quadItem->setText( 1, e->IsQuadratic() ? tr( "YES" ) : tr( "NO" ) ); - // gravity center - XYZ gc = gravityCenter( e ); - QTreeWidgetItem* gcItem = createItem( elemItem, Bold ); - gcItem->setText( 0, tr( "GRAVITY_CENTER" ) ); - QTreeWidgetItem* xItem = createItem( gcItem ); - xItem->setText( 0, "X" ); - xItem->setText( 1, QString::number( gc.x(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* yItem = createItem( gcItem ); - yItem->setText( 0, "Y" ); - yItem->setText( 1, QString::number( gc.y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* zItem = createItem( gcItem ); - zItem->setText( 0, "Z" ); - zItem->setText( 1, QString::number( gc.z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - } - if ( const SMDS_BallElement* ball = dynamic_cast( e )) { - // ball diameter - QTreeWidgetItem* diamItem = createItem( elemItem, Bold ); - diamItem->setText( 0, tr( "BALL_DIAMETER" ) ); - diamItem->setText( 1, QString( "%1" ).arg( ball->GetDiameter() )); - } - // connectivity - QTreeWidgetItem* conItem = createItem( elemItem, Bold ); - conItem->setText( 0, tr( "CONNECTIVITY" ) ); - SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); - for ( int idx = 1; nodeIt->more(); idx++ ) { - const SMDS_MeshNode* node = static_cast( nodeIt->next() ); - // node number and ID - QTreeWidgetItem* nodeItem = createItem( conItem, Bold ); - nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( tr( "NODE" ) ).arg( idx ).arg( e->NbNodes() ) ); - nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() ) ); - nodeItem->setExpanded( false ); - // node coordinates - QTreeWidgetItem* coordItem = createItem( nodeItem ); - coordItem->setText( 0, tr( "COORDINATES" ) ); - QTreeWidgetItem* xItem = createItem( coordItem ); - xItem->setText( 0, "X" ); - xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* yItem = createItem( coordItem ); - yItem->setText( 0, "Y" ); - yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - QTreeWidgetItem* zItem = createItem( coordItem ); - zItem->setText( 0, "Z" ); - zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision ) ) ); - // node connectivity - QTreeWidgetItem* nconItem = createItem( nodeItem ); - nconItem->setText( 0, tr( "CONNECTIVITY" ) ); - Connectivity connectivity = nodeConnectivity( node ); - if ( !connectivity.isEmpty() ) { - QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "0D_ELEMENTS" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Edge ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "EDGES" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Ball ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "BALL_ELEMENTS" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Face ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "FACES" ) ); - i->setText( 1, con ); - } - con = formatConnectivity( connectivity, SMDSAbs_Volume ); - if ( !con.isEmpty() ) { - QTreeWidgetItem* i = createItem( nconItem ); - i->setText( 0, tr( "VOLUMES" ) ); - i->setText( 1, con ); - } - } - } - } +TreeWriter::TreeWriter( QTreeWidget* w, TreeItemCreator* c ): + InfoWriter(true), myInfo(w), myCurrentItem(0), myCreator(c) +{ +} + +TreeWriter::~TreeWriter() +{ + delete myCreator; +} + +void TreeWriter::put( const QString& key, const QString& value, bool emphasize ) +{ + //std::string sss = myCurrentItem ? myCurrentItem->text(0).toStdString() : ""; + int options = Bold; + if ( emphasize ) options |= AllColumns; + QTreeWidgetItem* item = myCreator->createItem( myCurrentItem, options ); + item->setText( 0, key ); + if ( !value.isEmpty() ) + { + QString val = value; + if ( value.startsWith( "1 2 + { + int role = ( value[11] == 'n' ) ? NodeConnectivity : ElemConnectivity; + val = value.mid( value.lastIndexOf( '>', -5 ) + 1 ); // ==> 1 2 + val.chop( 4 ); + item->setData( 1, TypeRole, role ); } + item->setText( 1, val ); } } -/*! - \brief Internal clean-up (reset widget) -*/ -void SMESHGUI_TreeElemInfo::clearInternal() +void TreeWriter::indent() { - myInfo->clear(); - myInfo->repaint(); + QTreeWidgetItem* item = myCurrentItem ? myCurrentItem : myInfo->invisibleRootItem(); + if ( item->childCount() > 0 ) + myCurrentItem = item->child( item->childCount()-1 ); +} + +void TreeWriter::unindent() +{ + if ( myCurrentItem ) + myCurrentItem = myCurrentItem->parent(); } +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_ElemInfo +/// \brief Base class for the mesh element information widget. +/// +/// Displays the detail information about given mesh node(s) or element(s). +/// Default class does not provide working implementation but onle general +/// functionalities; main work is done in sub-classes. +//////////////////////////////////////////////////////////////////////////////// + /*! - \brief Create new tree item. - \param parent parent tree widget item - \param flags item flag - \return new tree widget item + \brief Constructor. + \param parent Parent widget. Defaults to 0. */ -QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int flags ) +SMESHGUI_ElemInfo::SMESHGUI_ElemInfo( QWidget* parent ): SMESHGUI_Info( parent ), myWhat( ShowNone ) { - QTreeWidgetItem* item; - if ( parent ) - item = new QTreeWidgetItem( parent ); - else - item = new QTreeWidgetItem( myInfo ); + myFrame = new QWidget( this ); + myExtra = new ExtraWidget( this ); - item->setFlags( item->flags() | Qt::ItemIsEditable ); + QVBoxLayout* vbl = new QVBoxLayout( this ); + vbl->setMargin( 0 ); + vbl->setSpacing( SPACING ); + vbl->addWidget( myFrame ); + vbl->addWidget( myExtra ); - QFont f = item->font( 0 ); - f.setBold( true ); - for ( int i = 0; i < myInfo->columnCount(); i++ ) { - if ( ( flags & Bold ) && ( i == 0 || flags & All ) ) - item->setFont( i, f ); - } + connect( myExtra->prev, SIGNAL( clicked() ), this, SLOT( showPrevious() ) ); + connect( myExtra->next, SIGNAL( clicked() ), this, SLOT( showNext() ) ); - item->setExpanded( true ); - return item; + clear(); } /*! - \class GrpComputor - \brief Mesh information computer - \internal - - The class is created for different computation operation. Currently it is used - to compute number of underlying nodes for the groups. + \brief Destructor. */ +SMESHGUI_ElemInfo::~SMESHGUI_ElemInfo() +{ +} /*! - \brief Contructor + \brief Show information on given node / element. + \param proxy Object to compute information on (mesh, sub-mesh, group, ID source). + \param id Mesh node / element ID. + \param isElement If \c true, show element info; otherwise show node info. */ -GrpComputor::GrpComputor( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* item, QObject* parent ) - : QObject( parent ), myItem( item ) +void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, uint id, bool isElement ) { - myGroup = SMESH::SMESH_GroupBase::_narrow( grp ); + QSet ids; + ids << id; + showInfo( proxy, ids, isElement ); } /*! - \brief Compute function + \brief Show information on given nodes / elements. + \param proxy Object to compute information on (mesh, sub-mesh, group, ID source). + \param ids Mesh nodes / elements IDs. + \param isElement If \c true, show element info; otherwise show node info. */ -void GrpComputor::compute() +void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy, QSet ids, bool isElement ) { - if ( !CORBA::is_nil( myGroup ) && myItem ) { - QTreeWidgetItem* item = myItem; - myItem = 0; - int nbNodes = myGroup->GetNumberOfNodes(); - item->treeWidget()->removeItemWidget( item, 1 ); - item->setText( 1, QString::number( nbNodes )); + if ( !proxy ) + { + clear(); + return; } + + QList newIds = ids.toList(); + qSort( newIds ); + int what = isElement ? ShowElements : ShowNodes; + + if ( myProxy == proxy && myIDs == newIds && myWhat == what ) + return; + + myProxy = proxy; + myProxy.refresh(); // try to re-initialize actor + + clear(); + + myIDs = newIds; + myWhat = what; + myIndex = 0; + + updateControls(); + information( myIDs.mid( myIndex*blockSize(), blockSize() ) ); } /*! - \class SMESHGUI_AddInfo - \brief The wigdet shows additional information on the mesh object. + \brief Show information on given group. + \param proxy Object to compute information on (group). */ +void SMESHGUI_ElemInfo::showInfo( const SMESH::SelectionProxy& proxy ) +{ + if ( !proxy || proxy.groupElementType() == SMESH::ALL ) // null proxy or not a group + { + clear(); + return; + } + + showInfo( proxy, proxy.ids(), proxy.groupElementType() != SMESH::NODE ); +} /*! - \brief Constructor - \param parent parent widget + \brief Reset panel (clear all data). */ -SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent ) -: QTreeWidget( parent ) +void SMESHGUI_ElemInfo::clear() { - setColumnCount( 2 ); - header()->setStretchLastSection( true ); - header()->setResizeMode( 0, QHeaderView::ResizeToContents ); - header()->hide(); + myIDs.clear(); + myIndex = 0; + clearInternal(); + updateControls(); } /*! - \brief Destructor + \brief Get central area widget. + \return Central widget. */ -SMESHGUI_AddInfo::~SMESHGUI_AddInfo() +QWidget* SMESHGUI_ElemInfo::centralWidget() const { + return myFrame; } /*! - \brief Show additional information on the selected object - \param obj object being processed (mesh, sub-mesh, group, ID source) + \brief Get current mesh proxy object information is shown on. + \return Current proxy. */ -void SMESHGUI_AddInfo::showInfo( SMESH::SMESH_IDSource_ptr obj ) +SMESH::SelectionProxy SMESHGUI_ElemInfo::proxy() const { - setProperty( "group_index", 0 ); - setProperty( "submesh_index", 0 ); - myComputors.clear(); - clear(); - - if ( CORBA::is_nil( obj ) ) return; - - _PTR(SObject) sobj = SMESH::ObjectToSObject( obj ); - if ( !sobj ) return; - - // name - QTreeWidgetItem* nameItem = createItem( 0, Bold | All ); - nameItem->setText( 0, tr( "NAME" ) ); - nameItem->setText( 1, sobj->GetName().c_str() ); - - SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow( obj ); - SMESH::SMESH_subMesh_var aSubMesh = SMESH::SMESH_subMesh::_narrow( obj ); - SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_narrow( obj ); - - if ( !aMesh->_is_nil() ) - meshInfo( aMesh, nameItem ); - else if ( !aSubMesh->_is_nil() ) - subMeshInfo( aSubMesh, nameItem ); - else if ( !aGroup->_is_nil() ) - groupInfo( aGroup.in(), nameItem ); + return myProxy; } /*! - \brief Create new tree item. - \param parent parent tree widget item - \param flags item flag - \return new tree widget item + \brief Get current info mode. + \return Current panel mode. */ -QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int flags ) +int SMESHGUI_ElemInfo::what() const { - QTreeWidgetItem* item; - - if ( parent ) - item = new QTreeWidgetItem( parent ); - else - item = new QTreeWidgetItem( this ); - - //item->setFlags( item->flags() | Qt::ItemIsEditable ); + return myWhat; +} - QFont f = item->font( 0 ); - f.setBold( true ); - for ( int i = 0; i < columnCount(); i++ ) { - if ( ( flags & Bold ) && ( i == 0 || flags & All ) ) - item->setFont( i, f ); +/*! + \brief Get title for given element type. + \param type Mesh element type. + \param multiple Use plural form. Defaults to \c false. + \return Element type's title. +*/ +QString SMESHGUI_ElemInfo::type2str( int type, bool multiple ) +{ + QString title; + switch ( type ) + { + case SMDSAbs_Edge: + title = multiple ? tr( "EDGES" ) : tr( "EDGE" ) ; break; + case SMDSAbs_Face: + title = multiple ? tr( "FACES" ) : tr( "FACE" ); break; + case SMDSAbs_Volume: + title = multiple ? tr( "VOLUMES" ) : tr( "VOLUME" ); break; + case SMDSAbs_0DElement: + title = multiple ? tr( "0D_ELEMENTS" ) : tr( "0D_ELEMENT" ); break; + case SMDSAbs_Ball: + title = multiple ? tr( "BALL_ELEMENTS" ) : tr( "BALL" ); break; + default: + break; } - - item->setExpanded( true ); - return item; + return title; } /*! - \brief Show mesh info - \param mesh mesh object - \param parent parent tree item + \brief Get title for given shape type. + \param type Shape type. + \return Shape type's title. */ -void SMESHGUI_AddInfo::meshInfo( SMESH::SMESH_Mesh_ptr mesh, QTreeWidgetItem* parent ) +QString SMESHGUI_ElemInfo::stype2str( int type ) { - // type - GEOM::GEOM_Object_var shape = mesh->GetShapeToMesh(); - SALOME_MED::MedFileInfo* inf = mesh->GetMEDFileInfo(); - QTreeWidgetItem* typeItem = createItem( parent, Bold ); - typeItem->setText( 0, tr( "TYPE" ) ); - if ( !CORBA::is_nil( shape ) ) { - typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) ); - _PTR(SObject) sobj = SMESH::ObjectToSObject( shape ); - if ( sobj ) { - QTreeWidgetItem* gobjItem = createItem( typeItem ); - gobjItem->setText( 0, tr( "GEOM_OBJECT" ) ); - gobjItem->setText( 1, sobj->GetName().c_str() ); - } - } - else if ( strlen( (char*)inf->fileName ) > 0 ) { - typeItem->setText( 1, tr( "MESH_FROM_FILE" ) ); - QTreeWidgetItem* fileItem = createItem( typeItem ); - fileItem->setText( 0, tr( "FILE_NAME" ) ); - fileItem->setText( 1, (char*)inf->fileName ); - } - else { - typeItem->setText( 1, tr( "STANDALONE_MESH" ) ); + QString title; + switch ( type ) + { + case GEOM::VERTEX: + title = tr( "GEOM_VERTEX" ); break; + case GEOM::EDGE: + title = tr( "GEOM_EDGE" ); break; + case GEOM::FACE: + title = tr( "GEOM_FACE" ); break; + case GEOM::SOLID: + default: + title = tr( "GEOM_SOLID" ); break; + break; } - - // groups - myGroups = mesh->GetGroups(); - showGroups(); - - // sub-meshes - mySubMeshes = mesh->GetSubMeshes(); - showSubMeshes(); + return title; } /*! - \brief Show sub-mesh info - \param subMesh sub-mesh object - \param parent parent tree item + \brief Get title for given element type. + \param type Mesh element type. + \return Element type's title. */ -void SMESHGUI_AddInfo::subMeshInfo( SMESH::SMESH_subMesh_ptr subMesh, QTreeWidgetItem* parent ) +QString SMESHGUI_ElemInfo::etype2str( int type ) { - bool isShort = parent->parent() != 0; - - if ( !isShort ) { - // parent mesh - _PTR(SObject) sobj = SMESH::ObjectToSObject( subMesh->GetFather() ); - if ( sobj ) { - QTreeWidgetItem* nameItem = createItem( parent, Bold ); - nameItem->setText( 0, tr( "PARENT_MESH" ) ); - nameItem->setText( 1, sobj->GetName().c_str() ); - } + QString title; + switch ( type ) + { + case SMESH::Entity_0D: + title = tr( "SMESH_ELEM0D" ); break; + case SMESH::Entity_Edge: + title = tr( "SMESH_EDGE" ); break; + case SMESH::Entity_Quad_Edge: + title = tr( "SMESH_QUADRATIC_EDGE" ); break; + case SMESH::Entity_Triangle: + title = tr( "SMESH_TRIANGLE" ); break; + case SMESH::Entity_Quad_Triangle: + title = tr( "SMESH_QUADRATIC_TRIANGLE" ); break; + case SMESH::Entity_BiQuad_Triangle: + title = tr( "SMESH_BIQUADRATIC_TRIANGLE" ); break; + case SMESH::Entity_Quadrangle: + title = tr( "SMESH_QUADRANGLE" ); break; + case SMESH::Entity_Quad_Quadrangle: + title = tr( "SMESH_QUADRATIC_QUADRANGLE" ); break; + case SMESH::Entity_BiQuad_Quadrangle: + title = tr( "SMESH_BIQUADRATIC_QUADRANGLE" ); break; + case SMESH::Entity_Polygon: + title = tr( "SMESH_POLYGON" ); break; + case SMESH::Entity_Quad_Polygon: + title = tr( "SMESH_QUADRATIC_POLYGON" ); break; + case SMESH::Entity_Tetra: + title = tr( "SMESH_TETRAHEDRON" ); break; + case SMESH::Entity_Quad_Tetra: + title = tr( "SMESH_QUADRATIC_TETRAHEDRON" ); break; + case SMESH::Entity_Pyramid: + title = tr( "SMESH_PYRAMID" ); break; + case SMESH::Entity_Quad_Pyramid: + title = tr( "SMESH_QUADRATIC_PYRAMID" ); break; + case SMESH::Entity_Hexa: + title = tr( "SMESH_HEXAHEDRON" ); break; + case SMESH::Entity_Quad_Hexa: + title = tr( "SMESH_QUADRATIC_HEXAHEDRON" ); break; + case SMESH::Entity_TriQuad_Hexa: + title = tr( "SMESH_TRIQUADRATIC_HEXAHEDRON" ); break; + case SMESH::Entity_Penta: + title = tr( "SMESH_PENTA" ); break; + case SMESH::Entity_Quad_Penta: + title = tr( "SMESH_QUADRATIC_PENTAHEDRON" ); break; + case SMESH::Entity_BiQuad_Penta: + title = tr( "SMESH_BIQUADRATIC_PENTAHEDRON" ); break; + case SMESH::Entity_Hexagonal_Prism: + title = tr( "SMESH_HEX_PRISM" ); break; + case SMESH::Entity_Polyhedra: + title = tr( "SMESH_POLYEDRON" ); break; + case SMESH::Entity_Quad_Polyhedra: + title = tr( "SMESH_QUADRATIC_POLYEDRON" ); break; + case SMESH::Entity_Ball: + title = tr( "SMESH_BALL" ); break; + default: + break; } - - // shape - GEOM::GEOM_Object_var gobj = subMesh->GetSubShape(); - _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); - if ( sobj ) { - QTreeWidgetItem* gobjItem = createItem( parent, Bold ); - gobjItem->setText( 0, tr( "GEOM_OBJECT" ) ); - gobjItem->setText( 1, sobj->GetName().c_str() ); + return title; +} + +/*! + \brief Get title for given quality control. + \param type Mesh control type. + \return Quality control's title. +*/ +QString SMESHGUI_ElemInfo::ctrl2str( int control ) +{ + QString title; + switch ( control ) + { + case SMESH::FT_AspectRatio: + title = tr( "ASPECTRATIO_ELEMENTS" ); break; + case SMESH::FT_AspectRatio3D: + title = tr( "ASPECTRATIO_3D_ELEMENTS" ); break; + case SMESH::FT_Warping: + title = tr( "WARP_ELEMENTS" ); break; + case SMESH::FT_MinimumAngle: + title = tr( "MINIMUMANGLE_ELEMENTS" ); break; + case SMESH::FT_Taper: + title = tr( "TAPER_ELEMENTS" ); break; + case SMESH::FT_Skew: + title = tr( "SKEW_ELEMENTS" ); break; + case SMESH::FT_Area: + title = tr( "AREA_ELEMENTS" ); break; + case SMESH::FT_Volume3D: + title = tr( "VOLUME_3D_ELEMENTS" ); break; + case SMESH::FT_MaxElementLength2D: + title = tr( "MAX_ELEMENT_LENGTH_2D" ); break; + case SMESH::FT_MaxElementLength3D: + title = tr( "MAX_ELEMENT_LENGTH_3D" ); break; + case SMESH::FT_Length: + title = tr( "LENGTH_EDGES" ); break; + case SMESH::FT_Length2D: + case SMESH::FT_Length3D: + title = tr( "MIN_ELEM_EDGE" ); break; + case SMESH::FT_BallDiameter: + title = tr( "BALL_DIAMETER" ); break; + default: + break; } + return title; } /*! - \brief Show group info - \param grp mesh group object - \param parent parent tree item + \brief Write information on given mesh nodes / elements. + \param writer Information writer. + \param ids Nodes / elements IDs. */ -void SMESHGUI_AddInfo::groupInfo( SMESH::SMESH_GroupBase_ptr grp, QTreeWidgetItem* parent ) +void SMESHGUI_ElemInfo::writeInfo( InfoWriter* writer, const QList& ids ) { - bool isShort = parent->parent() != 0; + if ( !proxy() ) + return; - SMESH::SMESH_Group_var aStdGroup = SMESH::SMESH_Group::_narrow( grp ); - SMESH::SMESH_GroupOnGeom_var aGeomGroup = SMESH::SMESH_GroupOnGeom::_narrow( grp ); - SMESH::SMESH_GroupOnFilter_var aFltGroup = SMESH::SMESH_GroupOnFilter::_narrow( grp ); + bool grp_details = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "elem_info_grp_details", false ); + int cprecision = SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ? + SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ) : -1; - if ( !isShort ) { - // parent mesh - _PTR(SObject) sobj = SMESH::ObjectToSObject( grp->GetMesh() ); - if ( sobj ) { - QTreeWidgetItem* nameItem = createItem( parent, Bold ); - nameItem->setText( 0, tr( "PARENT_MESH" ) ); - nameItem->setText( 1, sobj->GetName().c_str() ); - } - } + SMESH::XYZ xyz; + SMESH::Connectivity connectivity; + SMESH::Position position; + bool ok; - // type : group on geometry, standalone group, group on filter - QTreeWidgetItem* typeItem = createItem( parent, Bold ); - typeItem->setText( 0, tr( "TYPE" ) ); - if ( !CORBA::is_nil( aStdGroup ) ) { - typeItem->setText( 1, tr( "STANDALONE_GROUP" ) ); - } - else if ( !CORBA::is_nil( aGeomGroup ) ) { - typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) ); - GEOM::GEOM_Object_var gobj = aGeomGroup->GetShape(); - _PTR(SObject) sobj = SMESH::ObjectToSObject( gobj ); - if ( sobj ) { - QTreeWidgetItem* gobjItem = createItem( typeItem ); - gobjItem->setText( 0, tr( "GEOM_OBJECT" ) ); - gobjItem->setText( 1, sobj->GetName().c_str() ); - } - } - else if ( !CORBA::is_nil( aFltGroup ) ) { - typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) ); - } + foreach ( uint id, ids ) + { + writer->separator(); - if ( !isShort ) { - // entity type - QString etype = tr( "UNKNOWN" ); - switch( grp->GetType() ) { - case SMESH::NODE: - etype = tr( "NODE" ); - break; - case SMESH::EDGE: - etype = tr( "EDGE" ); - break; - case SMESH::FACE: - etype = tr( "FACE" ); - break; - case SMESH::VOLUME: - etype = tr( "VOLUME" ); - break; - case SMESH::ELEM0D: - etype = tr( "0DELEM" ); + if ( what() == ShowNodes ) + { + // show node info + // - check that node exists + if ( !proxy().hasNode( id ) ) + continue; + // - id + writer->write( tr( "NODE" ), (int)id, true ); + writer->indent(); + // - coordinates + ok = proxy().nodeCoordinates( id, xyz ); + if ( ok ) + { + writer->write( tr( "COORDINATES" ), xyz ); + } + // - connectivity + ok = proxy().nodeConnectivity( id, connectivity ); + if ( ok ) + { + if ( !connectivity.isEmpty() ) + { + writer->write( tr( "CONNECTIVITY" ) ); + writer->indent(); + for ( int i = SMDSAbs_Edge; i <= SMDSAbs_Ball; i++ ) + { + QString formatted = formatConnectivity( connectivity, i ); + if ( !formatted.isEmpty() ) + writer->write( type2str( i, true ), formatted ); + } + writer->unindent(); + } + else + { + writer->write( tr( "CONNECTIVITY" ), tr( "FREE_NODE" ) ); + } + } + // - position + ok = proxy().nodePosition( id, position ); + if ( ok && position.isValid() ) + { + writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) ); + writer->indent(); + if ( position.hasU() ) + writer->write( tr("U_POSITION"), position.u() ); + if ( position.hasV() ) + writer->write( tr("V_POSITION"), position.v() ); + writer->unindent(); + } + // - groups node belongs to + QList groups = proxy().nodeGroups( id ); + bool topCreated = false; + foreach( SMESH::SelectionProxy group, groups ) + { + if ( group && !group.name().isEmpty() ) + { + if ( !topCreated ) + { + writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) ); + writer->indent(); + topCreated = true; + } + writer->write( group.name().trimmed() ); // trim name + if ( grp_details ) + { + writer->indent(); + int type = group.type(); + if ( type == SMESH::SelectionProxy::GroupStd ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ); + } + else if ( type == SMESH::SelectionProxy::GroupGeom ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ); + writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() ); + } + else if ( type == SMESH::SelectionProxy::GroupFilter ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ); + } + int size = group.size(); + if ( size != -1 ); + writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size ); + QColor color = group.color(); + if ( color.isValid() ) + writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() ); + writer->unindent(); + } + } + } + if ( topCreated ) + writer->unindent(); + writer->unindent(); + } + else if ( what() == ShowElements ) + { + // show element info + // - check that element exists + if ( !proxy().hasElement( id ) ) + continue; + // - id & type + int type = proxy().elementType( id ); + if ( type == SMESH::ALL ) + continue; + writer->write( type2str( type ), (int)id, true ); + writer->indent(); + // - geometry type + type = proxy().elementEntityType( id ); + writer->write( tr( "TYPE" ), etype2str( type ) ); + // - connectivity + if ( type == SMESH::Entity_Polyhedra || + type == SMESH::Entity_Quad_Polyhedra ) + { + int nbNodes; + ok = proxy().perFaceConnectivity( id, connectivity, nbNodes ); + if ( ok && !connectivity.isEmpty() ) + { + writer->write( tr( "NB_NODES" ), nbNodes ); + writer->write( tr( "CONNECTIVITY" ) ); + writer->indent(); + int nbFaces = connectivity.size(); + for ( int iF = 1; iF <= nbFaces; ++iF ) + { + QString formatted = formatConnectivity( connectivity, -iF ); + writer->write(( type2str( SMDSAbs_Face, 0 ) + " %1 / %2" ).arg( iF ).arg( nbFaces ), + formatted ); + } + writer->unindent(); + } + } + else + { + ok = proxy().elementConnectivity( id, connectivity ); + if ( ok && !connectivity.isEmpty() ) + { + QString formatted = formatConnectivity( connectivity, SMDSAbs_Node ); + if ( !formatted.isEmpty() ) + { + writer->write( tr( "NB_NODES" ), connectivity[ SMDSAbs_Node ].size() ); + writer->write( tr( "CONNECTIVITY" ), formatted ); //todo: TypeRole: ElemConnectivity + } + } + } + // - position + ok = proxy().elementPosition( id, position ); + if ( ok && position.isValid() ) + { + writer->write( tr( "POSITION" ), (stype2str( position.shapeType() ) + " #%1").arg( position.shapeId() ) ); + } + // - gravity center + ok = proxy().elementGravityCenter( id, xyz ); + if ( ok ) + { + writer->write( tr( "GRAVITY_CENTER" ), xyz ); + } + // - normal vector + ok = proxy().elementNormal( id, xyz ); + if ( ok ) + { + writer->write( tr( "NORMAL_VECTOR" ), xyz ); + } + // - controls + bool topCreated = false; + for ( int i = SMESH::FT_AspectRatio; i < SMESH::FT_Undefined; i++ ) + { + QString ctrlTitle = ctrl2str( i ); + if ( ctrlTitle.isEmpty() ) + continue; + if ( !topCreated ) + { + writer->write( tr( "CONTROLS" ) ); + writer->indent(); + topCreated = true; + } + double value; + if ( proxy().elementControl( id, i, cprecision, value ) ) + writer->write( ctrlTitle, value ); + } + if ( topCreated ) + writer->unindent(); + // - groups element belongs to + QList groups = proxy().elementGroups( id ); + topCreated = false; + foreach( SMESH::SelectionProxy group, groups ) + { + if ( group && !group.name().isEmpty() ) + { + if ( !topCreated ) + { + writer->write( SMESHGUI_AddInfo::tr( "GROUPS" ) ); + writer->indent(); + topCreated = true; + } + writer->write( group.name().trimmed() ); // trim name + if ( grp_details ) + { + writer->indent(); + int type = group.type(); + if ( type == SMESH::SelectionProxy::GroupStd ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "STANDALONE_GROUP" ) ); + } + else if ( type == SMESH::SelectionProxy::GroupGeom ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_GEOMETRY" ) ); + writer->write( SMESHGUI_AddInfo::tr( "GEOM_OBJECT" ), group.shapeName() ); + } + else if ( type == SMESH::SelectionProxy::GroupFilter ) + { + writer->write( SMESHGUI_AddInfo::tr( "TYPE" ), SMESHGUI_AddInfo::tr( "GROUP_ON_FILTER" ) ); + } + int size = group.size(); + if ( size != -1 ); + writer->write( SMESHGUI_AddInfo::tr( "SIZE" ), size ); + QColor color = group.color(); + if ( color.isValid() ) + writer->write( SMESHGUI_AddInfo::tr( "COLOR" ), color.name() ); + writer->unindent(); + } + } + } + if ( topCreated ) + writer->unindent(); + writer->unindent(); + } + } +} + +/*! + \fn void SMESHGUI_ElemInfo::information( const QList& ids ) + \brief Show information on given mesh nodes / elements. + + This function has to be redefined in sub-classes. + + \param ids Nodes / elements IDs. +*/ + +/*! + \brief Internal clean-up (reset panel). + + Default implementation does nothing; the method has to be redefined + in sub-classes to perform internal clean-up. +*/ +void SMESHGUI_ElemInfo::clearInternal() +{ +} + +/*! + \brief Show previous chunk of information. +*/ +void SMESHGUI_ElemInfo::showPrevious() +{ + myIndex = qMax( 0, myIndex-1 ); + updateControls(); + information( myIDs.mid( myIndex*blockSize(), blockSize() ) ); +} + +/*! + \brief Show next chunk of information. +*/ +void SMESHGUI_ElemInfo::showNext() +{ + myIndex = qMin( myIndex+1, myIDs.count() / blockSize() ); + updateControls(); + information( myIDs.mid( myIndex*blockSize(), blockSize() ) ); +} + +/*! + \brief Update control widget state. +*/ +void SMESHGUI_ElemInfo::updateControls() +{ + myExtra->updateControls( myIDs.count(), myIndex ); +} + +/*! + \brief Write information from panel to ouput stream. + \param out Text stream output. +*/ +void SMESHGUI_ElemInfo::saveInfo( QTextStream &out ) +{ + // title + QString title = tr( "ELEM_INFO" ); + out << ruler( title.size() ) << endl; + out << title << endl; + out << ruler( title.size() ) << endl; + // out << endl; + + // info + StreamWriter writer( out ); + writeInfo( &writer, myIDs ); + out << endl; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_SimpleElemInfo +/// \brief Show mesh element information in the simple text area. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. +*/ +SMESHGUI_SimpleElemInfo::SMESHGUI_SimpleElemInfo( QWidget* parent ) + : SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTextBrowser( centralWidget() ); + QVBoxLayout* l = new QVBoxLayout( centralWidget() ); + l->setMargin( 0 ); + l->addWidget( myInfo ); + + connect( myInfo, SIGNAL( anchorClicked(QUrl)), this, SLOT( connectivityClicked( QUrl ))); +} + +/*! + \brief Show mesh element information. + \param ids Nodes / elements IDs. +*/ +void SMESHGUI_SimpleElemInfo::information( const QList& ids ) +{ + clearInternal(); + TextWriter writer( myInfo ); + writeInfo( &writer, ids ); +} + +/*! + \brief Internal clean-up (reset widget) +*/ +void SMESHGUI_SimpleElemInfo::clearInternal() +{ + myInfo->clear(); +} + +void SMESHGUI_SimpleElemInfo::connectivityClicked(const QUrl & url) +{ + int type = ( url.scheme()[0] == 'n' ) ? NodeConnectivity : ElemConnectivity; + QString ids = url.path(); // excess chars will be filtered off by SMESHGUI_IdValidator + emit( itemInfo( type, ids )); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_TreeElemInfo::ItemDelegate +/// \brief Item delegate for tree mesh info widget. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class SMESHGUI_TreeElemInfo::ItemDelegate : public QItemDelegate +{ +public: + ItemDelegate( QObject* ); + QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; +}; + +/*! + \brief Constructor. + \internal +*/ +SMESHGUI_TreeElemInfo::ItemDelegate::ItemDelegate( QObject* parent ): QItemDelegate( parent ) +{ +} + +/*! + \brief Redefined from QItemDelegate. + \internal +*/ +QWidget* SMESHGUI_TreeElemInfo::ItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const +{ + QWidget* w = index.column() == 0 ? 0: QItemDelegate::createEditor( parent, option, index ); + if ( qobject_cast( w ) ) + qobject_cast( w )->setReadOnly( true ); + return w; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_TreeElemInfo::ItemCreator +/// \brief Item creator for tree mesh info widget. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class SMESHGUI_TreeElemInfo::ItemCreator : public TreeItemCreator +{ + SMESHGUI_TreeElemInfo* myView; +public: + ItemCreator( SMESHGUI_TreeElemInfo* ); + QTreeWidgetItem* createItem( QTreeWidgetItem*, int ); +}; + +/*! + \brief Constructor. + \param view Parent view. + \internal +*/ +SMESHGUI_TreeElemInfo::ItemCreator::ItemCreator( SMESHGUI_TreeElemInfo* view ): TreeItemCreator(), myView( view ) +{ +} + +/*! + \brief Create new tree item. + \param parent Parent tree item. + \param options Item options. + \return New tree widget item. + \internal +*/ +QTreeWidgetItem* SMESHGUI_TreeElemInfo::ItemCreator::createItem( QTreeWidgetItem* parent, int options ) +{ + return myView->createItem( parent, options ); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_TreeElemInfo +/// \brief Show mesh element information as the tree. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. +*/ +SMESHGUI_TreeElemInfo::SMESHGUI_TreeElemInfo( QWidget* parent ) + : SMESHGUI_ElemInfo( parent ) +{ + myInfo = new QTreeWidget( centralWidget() ); + myInfo->setColumnCount( 2 ); + myInfo->setHeaderLabels( QStringList() << tr( "PROPERTY" ) << tr( "VALUE" ) ); + myInfo->header()->setStretchLastSection( true ); +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + myInfo->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); +#else + myInfo->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); +#endif + myInfo->setItemDelegate( new ItemDelegate( myInfo ) ); + QVBoxLayout* l = new QVBoxLayout( centralWidget() ); + l->setMargin( 0 ); + l->addWidget( myInfo ); + connect( myInfo, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( itemDoubleClicked( QTreeWidgetItem*, int ) ) ); + connect( myInfo, SIGNAL( itemCollapsed( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) ); + connect( myInfo, SIGNAL( itemExpanded( QTreeWidgetItem* )), this, SLOT( saveExpanded( QTreeWidgetItem* )) ); +} + +/*! + \brief Show mesh element information. + \param ids Nodes / elements IDs. +*/ +void SMESHGUI_TreeElemInfo::information( const QList& ids ) +{ + clearInternal(); + TreeWriter writer( myInfo, new ItemCreator( this ) ); + writeInfo( &writer, ids ); +} + +/*! + \brief Show node information + \param node mesh node for showing + \param index index of current node + \param nbNodes number of unique nodes in element + \param parentItem parent item of tree +*/ +void SMESHGUI_TreeElemInfo::nodeInfo( const SMDS_MeshNode* node, int index, + int nbNodes, QTreeWidgetItem* parentItem ) +{ + // int precision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "length_precision", 6 ); + // // node number and ID + // QTreeWidgetItem* nodeItem = createItem( parentItem, Bold ); + // nodeItem->setText( 0, QString( "%1 %2 / %3" ).arg( SMESHGUI_ElemInfo::tr( "NODE" )).arg( index ).arg( nbNodes )); + // nodeItem->setText( 1, QString( "#%1" ).arg( node->GetID() )); + // nodeItem->setData( 1, TypeRole, ElemConnectivity ); + // nodeItem->setData( 1, IdRole, node->GetID() ); + // nodeItem->setExpanded( false ); + // // node coordinates + // QTreeWidgetItem* coordItem = createItem( nodeItem ); + // coordItem->setText( 0, SMESHGUI_ElemInfo::tr( "COORDINATES" )); + // QTreeWidgetItem* xItem = createItem( coordItem ); + // xItem->setText( 0, "X" ); + // xItem->setText( 1, QString::number( node->X(), precision > 0 ? 'f' : 'g', qAbs( precision )) ); + // QTreeWidgetItem* yItem = createItem( coordItem ); + // yItem->setText( 0, "Y" ); + // yItem->setText( 1, QString::number( node->Y(), precision > 0 ? 'f' : 'g', qAbs( precision )) ); + // QTreeWidgetItem* zItem = createItem( coordItem ); + // zItem->setText( 0, "Z" ); + // zItem->setText( 1, QString::number( node->Z(), precision > 0 ? 'f' : 'g', qAbs( precision )) ); + // // node connectivity + // QTreeWidgetItem* nconItem = createItem( nodeItem ); + // nconItem->setText( 0, SMESHGUI_ElemInfo::tr( "CONNECTIVITY" )); + // Connectivity connectivity = nodeConnectivity( node ); + // if ( !connectivity.isEmpty() ) { + // QString con = formatConnectivity( connectivity, SMDSAbs_0DElement ); + // if ( !con.isEmpty() ) { + // QTreeWidgetItem* i = createItem( nconItem ); + // i->setText( 0, SMESHGUI_ElemInfo::tr( "0D_ELEMENTS" )); + // i->setText( 1, con ); + // } + // con = formatConnectivity( connectivity, SMDSAbs_Edge ); + // if ( !con.isEmpty() ) { + // QTreeWidgetItem* i = createItem( nconItem ); + // i->setText( 0, SMESHGUI_ElemInfo::tr( "EDGES" )); + // i->setText( 1, con ); + // i->setData( 1, TypeRole, NodeConnectivity ); + // } + // con = formatConnectivity( connectivity, SMDSAbs_Ball ); + // if ( !con.isEmpty() ) { + // QTreeWidgetItem* i = createItem( nconItem ); + // i->setText( 0, SMESHGUI_ElemInfo::tr( "BALL_ELEMENTS" )); + // i->setText( 1, con ); + // i->setData( 1, TypeRole, NodeConnectivity ); + // } + // con = formatConnectivity( connectivity, SMDSAbs_Face ); + // if ( !con.isEmpty() ) { + // QTreeWidgetItem* i = createItem( nconItem ); + // i->setText( 0, SMESHGUI_ElemInfo::tr( "FACES" )); + // i->setText( 1, con ); + // i->setData( 1, TypeRole, NodeConnectivity ); + // } + // con = formatConnectivity( connectivity, SMDSAbs_Volume ); + // if ( !con.isEmpty() ) { + // QTreeWidgetItem* i = createItem( nconItem ); + // i->setText( 0, SMESHGUI_ElemInfo::tr( "VOLUMES" )); + // i->setText( 1, con ); + // i->setData( 1, TypeRole, NodeConnectivity ); + // } + // } +} +/*! + \brief Internal clean-up (reset widget) +*/ +void SMESHGUI_TreeElemInfo::clearInternal() +{ + myInfo->clear(); + myInfo->repaint(); +} + +/*! + \brief Create new item and add it to the tree. + \param parent Parent tree widget item. Defaults to 0 (top-level item). + \param options Item flags. Defaults to 0 (none). + \return New tree widget item. +*/ +QTreeWidgetItem* SMESHGUI_TreeElemInfo::createItem( QTreeWidgetItem* parent, int options ) +{ + QTreeWidgetItem* item = new QTreeWidgetItem( parent ? parent : myInfo->invisibleRootItem() ); + setTreeItemAttributes( item, options | Expanded | Editable ); + + if ( parent && parent->childCount() == 1 && itemDepth( parent ) == 1 ) + { + QString resName = expandedResource( parent ); + parent->setExpanded( SMESHGUI::resourceMgr()->booleanValue("SMESH", resName, true )); + } + + return item; +} + +void SMESHGUI_TreeElemInfo::contextMenuEvent( QContextMenuEvent* e ) +{ + QList< QTreeWidgetItem* > widgets = myInfo->selectedItems(); + if ( widgets.isEmpty() ) return; + QTreeWidgetItem* aTreeItem = widgets.first(); + int type = aTreeItem->data( 1, TypeRole ).toInt(); + if (( type == ElemConnectivity || type == NodeConnectivity ) && + ( !aTreeItem->text( 1 ).isEmpty() )) + { + QMenu menu; + QAction* a = menu.addAction( tr( "SHOW_ITEM_INFO" )); + if ( menu.exec( e->globalPos() ) == a ) + emit( itemInfo( type, aTreeItem->text( 1 )) ); + } +} + +void SMESHGUI_TreeElemInfo::itemDoubleClicked( QTreeWidgetItem* theItem, int theColumn ) +{ + if ( theItem ) { + int type = theItem->data( 1, TypeRole ).toInt(); + emit( itemInfo( type, theItem->text( 1 )) ); + } +} + +void SMESHGUI_TreeElemInfo::saveExpanded( QTreeWidgetItem* theItem ) +{ + if ( theItem ) + SMESHGUI::resourceMgr()->setValue("SMESH", expandedResource( theItem ), theItem->isExpanded() ); +} + +QString SMESHGUI_TreeElemInfo::expandedResource( QTreeWidgetItem* theItem ) +{ + return QString("Expanded_") + ( what()==ShowElements ? "E_" : "N_" ) + theItem->text(0); +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class InfoComputor +/// \brief Mesh information computor. +/// \internal +/// +/// The class is created for different computation operations. Currently it is +/// used to compute size and number of underlying nodes for given group. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent object. + \param proxy Object to compute information on (group). + \param item Tree widget item, referenced by this computer. + \param operation Value to compute. + \internal +*/ +InfoComputor::InfoComputor( QObject* parent, const SMESH::SelectionProxy& proxy, int operation ) + : QObject( parent ), myProxy( proxy ), myOperation( operation ) +{ +} + +/*! + \brief Compute requested information. + \internal +*/ +void InfoComputor::compute() +{ + if ( myProxy ) + { + SUIT_OverrideCursor wc; + myProxy.load(); + switch ( myOperation ) + { + case GrpSize: + myProxy.size( true ); // force size computation + emit computed(); break; - case SMESH::BALL: - etype = tr( "BALL" ); + case GrpNbNodes: + myProxy.nbNodes( true ); // force size computation + emit computed(); break; default: break; } - QTreeWidgetItem* etypeItem = createItem( parent, Bold ); - etypeItem->setText( 0, tr( "ENTITY_TYPE" ) ); - etypeItem->setText( 1, etype ); } +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_AddInfo +/// \brief Show additional information on selected object. +/// +/// Displays an additional information about selected object: mesh, sub-mesh +/// or group. +/// +/// \todo Rewrite saveInfo() method to print all data, not currently shown only. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. +*/ +SMESHGUI_AddInfo::SMESHGUI_AddInfo( QWidget* parent ): SMESHGUI_Info( parent ) +{ + QVBoxLayout* l = new QVBoxLayout( this ); + l->setMargin( 0 ); + l->setSpacing( SPACING ); + + myTree = new QTreeWidget( this ); + + myTree->setColumnCount( 2 ); + myTree->header()->setStretchLastSection( true ); +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + myTree->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); +#else + myTree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); +#endif + myTree->header()->hide(); + + l->addWidget( myTree ); +} + +/*! + \brief Destructor. +*/ +SMESHGUI_AddInfo::~SMESHGUI_AddInfo() +{ +} + +/*! + \brief Show information on given object. + \param proxy Object to show information on (mesh, sub-mesh, group). +*/ +void SMESHGUI_AddInfo::showInfo( const SMESH::SelectionProxy& proxy ) +{ + // reset panel + setProperty( "group_index", 0 ); + setProperty( "submesh_index", 0 ); + myComputors.clear(); + myTree->clear(); + + // then fill panel with data if object is not null + if ( proxy ) + { + myProxy = proxy; + + // name + QTreeWidgetItem* nameItem = createItem( 0, Bold | AllColumns ); + nameItem->setText( 0, tr( "NAME" ) ); + nameItem->setText( 1, proxy.name() ); + + // object info + if ( proxy.type() == SMESH::SelectionProxy::Mesh ) + meshInfo( proxy, nameItem ); + else if ( proxy.type() == SMESH::SelectionProxy::Submesh ) + subMeshInfo( proxy, nameItem ); + else if ( proxy.type() >= SMESH::SelectionProxy::Group ) + groupInfo( proxy, nameItem ); + } +} + +/*! + \brief Update information in panel. +*/ +void SMESHGUI_AddInfo::updateInfo() +{ + showInfo( myProxy ); +} + +/*! + \brief Reset panel (clear all data). +*/ +void SMESHGUI_AddInfo::clear() +{ + myTree->clear(); +} + +/*! + \brief Create new item and add it to the tree. + \param parent Parent tree widget item. Defaults to 0 (top-level item). + \param options Item flags. Defaults to 0 (none). + \return New tree widget item. +*/ +QTreeWidgetItem* SMESHGUI_AddInfo::createItem( QTreeWidgetItem* parent, int options ) +{ + QTreeWidgetItem* item = parent ? new QTreeWidgetItem( parent ) : + new QTreeWidgetItem( myTree->invisibleRootItem() ); + setTreeItemAttributes( item, options | Expanded ); + return item; +} + +/*! + \brief Show information on mesh. + \param proxy Proxy object (mesh). + \param parent Parent tree item. +*/ +void SMESHGUI_AddInfo::meshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent ) +{ + if ( !proxy ) + return; + + QString shapeName = proxy.shapeName(); + SMESH::MedInfo inf = proxy.medFileInfo(); + + // type + QTreeWidgetItem* typeItem = createItem( parent, Bold ); + typeItem->setText( 0, tr( "TYPE" ) ); + if ( !shapeName.isEmpty() ) + { + typeItem->setText( 1, tr( "MESH_ON_GEOMETRY" ) ); + // shape + QTreeWidgetItem* gobjItem = createItem( parent, Bold ); + gobjItem->setText( 0, tr( "GEOM_OBJECT" ) ); + gobjItem->setText( 1, shapeName ); + } + else if ( inf.isValid() ) + { + typeItem->setText( 1, tr( "MESH_FROM_FILE" ) ); + // med file information + QTreeWidgetItem* fileItem = createItem( parent, Bold ); + fileItem->setText( 0, tr( "FILE_NAME" ) ); + fileItem->setText( 1, inf.fileName() ); + QTreeWidgetItem* sizeItem = createItem( parent, Bold ); + sizeItem->setText( 0, tr( "FILE_SIZE" ) ); + sizeItem->setText( 1, QString::number( inf.size() ) ); + QTreeWidgetItem* versionItem = createItem( parent, Bold ); + versionItem->setText( 0, tr( "FILE_VERSION" ) ); + versionItem->setText( 1, inf.version() != "0" ? inf.version() : tr( "VERSION_UNKNOWN" ) ); + } + else + { + typeItem->setText( 1, tr( "STANDALONE_MESH" ) ); + } + + // groups + myGroups = proxy.groups(); + showGroups(); + + // sub-meshes + mySubMeshes = proxy.submeshes(); + showSubMeshes(); +} + +/*! + \brief Show information on sub-mesh. + \param proxy Proxy object (sub-mesh). + \param parent Parent tree item. +*/ +void SMESHGUI_AddInfo::subMeshInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent ) +{ + if ( !proxy ) + return; + + bool isShort = parent->parent() != 0; + + if ( !isShort ) + { + // parent mesh + SMESH::SelectionProxy meshProxy = proxy.mesh(); + if ( meshProxy ) + { + QTreeWidgetItem* nameItem = createItem( parent, Bold ); + nameItem->setText( 0, tr( "PARENT_MESH" ) ); + nameItem->setText( 1, meshProxy.name() ); + } + } + + // shape + QString shapeName = proxy.shapeName(); + if ( !shapeName.isEmpty() ) + { + QTreeWidgetItem* gobjItem = createItem( parent, Bold ); + gobjItem->setText( 1, shapeName ); + } +} + +/*! + \brief Show information on group. + \param proxy Proxy object (group). + \param parent Parent tree item. +*/ +void SMESHGUI_AddInfo::groupInfo( const SMESH::SelectionProxy& proxy, QTreeWidgetItem* parent ) +{ + if ( !proxy ) + return; + + bool isShort = parent->parent() != 0; + + if ( !isShort ) + { + // parent mesh + SMESH::SelectionProxy meshProxy = proxy.mesh(); + if ( meshProxy ) + { + QTreeWidgetItem* nameItem = createItem( parent, Bold ); + nameItem->setText( 0, tr( "PARENT_MESH" ) ); + nameItem->setText( 1, meshProxy.name() ); + } + } + + // type + SMESH::SelectionProxy::Type type = proxy.type(); + QTreeWidgetItem* typeItem = createItem( parent, Bold ); + typeItem->setText( 0, tr( "TYPE" ) ); + if ( type == SMESH::SelectionProxy::GroupStd ) + { + typeItem->setText( 1, tr( "STANDALONE_GROUP" ) ); + } + else if ( type == SMESH::SelectionProxy::GroupGeom ) + { + typeItem->setText( 1, tr( "GROUP_ON_GEOMETRY" ) ); + // shape + QTreeWidgetItem* gobjItem = createItem( parent, Bold ); + gobjItem->setText( 0, tr( "GEOM_OBJECT" ) ); + gobjItem->setText( 1, proxy.shapeName() ); + } + else if ( type == SMESH::SelectionProxy::GroupFilter ) + { + typeItem->setText( 1, tr( "GROUP_ON_FILTER" ) ); + } + + // element type + int etype = proxy.groupElementType(); + if ( !isShort ) + { + QString typeName = tr( "UNKNOWN" ); + switch( etype ) + { + case SMESH::NODE: + typeName = tr( "NODE" ); + break; + case SMESH::EDGE: + typeName = tr( "EDGE" ); + break; + case SMESH::FACE: + typeName = tr( "FACE" ); + break; + case SMESH::VOLUME: + typeName = tr( "VOLUME" ); + break; + case SMESH::ELEM0D: + typeName = tr( "0DELEM" ); + break; + case SMESH::BALL: + typeName = tr( "BALL" ); + break; + default: + break; + } + QTreeWidgetItem* etypeItem = createItem( parent, Bold ); + etypeItem->setText( 0, tr( "ENTITY_TYPE" ) ); + etypeItem->setText( 1, typeName ); + } + + // size + // note: size is not computed for group on filter for performance reasons, see IPAL52831 + bool meshLoaded = proxy.isMeshLoaded(); + int size = proxy.size(); + + QTreeWidgetItem* sizeItem = createItem( parent, Bold ); + sizeItem->setText( 0, tr( "SIZE" ) ); + if ( size >= 0 ) + { + sizeItem->setText( 1, QString::number( size ) ); + } + else + { + QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this ); + myTree->setItemWidget( sizeItem, 1, btn ); + InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpSize ); + connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) ); + connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) ); + myComputors.append( comp ); + } + + // color + QTreeWidgetItem* colorItem = createItem( parent, Bold ); + colorItem->setText( 0, tr( "COLOR" ) ); + colorItem->setBackground( 1, proxy.color() ); + + // nb of underlying nodes + if ( etype != SMESH::NODE ) + { + QTreeWidgetItem* nodesItem = createItem( parent, Bold ); + nodesItem->setText( 0, tr( "NB_NODES" ) ); + + int nbNodes = proxy.nbNodes(); + if ( nbNodes >= 0 ) + { + nodesItem->setText( 1, QString::number( nbNodes ) ); + } + else + { + QPushButton* btn = new QPushButton( meshLoaded ? tr( "COMPUTE" ) : tr( "LOAD" ), this ); + myTree->setItemWidget( nodesItem, 1, btn ); + InfoComputor* comp = new InfoComputor( this, proxy, InfoComputor::GrpNbNodes ); + connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) ); + connect( comp, SIGNAL( computed() ), this, SLOT( updateInfo() ) ); + myComputors.append( comp ); + } + } +} + +/*! + \brief Update information on child groups. +*/ +void SMESHGUI_AddInfo::showGroups() +{ + // remove all computors + myComputors.clear(); + + // tree root should be the first top level item + QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0; + if ( !parent ) + return; + + int idx = property( "group_index" ).toInt(); + + // find sub-meshes top-level container item + QTreeWidgetItem* itemGroups = 0; + for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) + { + if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GroupsId ) + { + itemGroups = parent->child( i ); + // update controls + ExtraWidget* extra = dynamic_cast( myTree->itemWidget( itemGroups, 1 ) ); + if ( extra ) + extra->updateControls( myGroups.count(), idx ); + // clear: remove all group items + while ( itemGroups->childCount() ) + delete itemGroups->child( 0 ); + } + } + + QMap grpItems; + for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), (int)myGroups.count() ); i++ ) + { + SMESH::SelectionProxy grp = myGroups[i]; + if ( !grp ) + continue; + + int grpType = grp.groupElementType(); + + // create top-level groups container item if it does not exist + if ( !itemGroups ) + { + itemGroups = createItem( parent, Bold | AllColumns ); + itemGroups->setText( 0, tr( "GROUPS" ) ); + itemGroups->setData( 0, Qt::UserRole, GroupsId ); + + // if necessary, create extra widget to show information by chunks + if ( myGroups.count() > blockSize() ) + { + ExtraWidget* extra = new ExtraWidget( this, true ); + connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) ); + connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) ); + myTree->setItemWidget( itemGroups, 1, extra ); + extra->updateControls( myGroups.count(), idx ); + } + } + + // create container item corresponding to particular element type + if ( !grpItems.contains( grpType ) ) + { + grpItems[ grpType ] = createItem( itemGroups, Bold | AllColumns ); + grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) ); + itemGroups->insertChild( grpType-1, grpItems[ grpType ] ); // -1 needed since 0 corresponds to SMESH::ALL + } + + // name + QTreeWidgetItem* nameItem = createItem( grpItems[ grpType ] ); + nameItem->setText( 0, grp.name().trimmed() ); // trim name + + // group info + groupInfo( grp, nameItem ); + } +} + +/*! + \brief Update information on child sub-meshes. +*/ +void SMESHGUI_AddInfo::showSubMeshes() +{ + // tree root should be the first top level item + QTreeWidgetItem* parent = myTree->topLevelItemCount() > 0 ? myTree->topLevelItem( 0 ) : 0; + if ( !parent ) + return; + + int idx = property( "submesh_index" ).toInt(); + + // find sub-meshes top-level container item + QTreeWidgetItem* itemSubMeshes = 0; + for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) + { + if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SubMeshesId ) + { + itemSubMeshes = parent->child( i ); + // update controls + ExtraWidget* extra = dynamic_cast( myTree->itemWidget( itemSubMeshes, 1 ) ); + if ( extra ) + extra->updateControls( mySubMeshes.count(), idx ); + // clear: remove all sub-mesh items + while ( itemSubMeshes->childCount() ) + delete itemSubMeshes->child( 0 ); + } + } + + QMap smItems; + for ( int i = idx*blockSize() ; i < qMin( (idx+1)*blockSize(), mySubMeshes.count() ); i++ ) + { + SMESH::SelectionProxy sm = mySubMeshes[i]; + if ( !sm ) + continue; + + int smType = sm.shapeType(); + if ( smType < 0 ) + continue; + else if ( smType == GEOM::COMPSOLID ) + smType = GEOM::COMPOUND; + + // create top-level sub-meshes container item if it does not exist + if ( !itemSubMeshes ) + { + itemSubMeshes = createItem( parent, Bold | AllColumns ); + itemSubMeshes->setText( 0, tr( "SUBMESHES" ) ); + itemSubMeshes->setData( 0, Qt::UserRole, SubMeshesId ); + + // if necessary, create extra widget to show information by chunks + if ( mySubMeshes.count() > blockSize() ) + { + ExtraWidget* extra = new ExtraWidget( this, true ); + connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) ); + connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) ); + myTree->setItemWidget( itemSubMeshes, 1, extra ); + extra->updateControls( mySubMeshes.count(), idx ); + } + } + + // create container item corresponding to particular shape type + if ( !smItems.contains( smType ) ) + { + smItems[ smType ] = createItem( itemSubMeshes, Bold | AllColumns ); + smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) ); + itemSubMeshes->insertChild( smType, smItems[ smType ] ); + } + + // name + QTreeWidgetItem* nameItem = createItem( smItems[ smType ] ); + nameItem->setText( 0, sm.name().trimmed() ); // trim name + + // submesh info + subMeshInfo( sm, nameItem ); + } +} + +/*! + \brief Show previous chunk of information on child groups. +*/ +void SMESHGUI_AddInfo::showPreviousGroups() +{ + int idx = property( "group_index" ).toInt(); + setProperty( "group_index", idx-1 ); + showGroups(); +} + +/*! + \brief Show next chunk of information on child groups. +*/ +void SMESHGUI_AddInfo::showNextGroups() +{ + int idx = property( "group_index" ).toInt(); + setProperty( "group_index", idx+1 ); + showGroups(); +} + +/*! + \brief Show previous chunk of information on child sub-meshes. +*/ +void SMESHGUI_AddInfo::showPreviousSubMeshes() +{ + int idx = property( "submesh_index" ).toInt(); + setProperty( "submesh_index", idx-1 ); + showSubMeshes(); +} + +/*! + \brief Show next chunk of information on child sub-meshes. +*/ +void SMESHGUI_AddInfo::showNextSubMeshes() +{ + int idx = property( "submesh_index" ).toInt(); + setProperty( "submesh_index", idx+1 ); + showSubMeshes(); +} + +/*! + \brief Write information from panel to ouput stream. + \param out Text stream output. +*/ +void SMESHGUI_AddInfo::saveInfo( QTextStream &out ) +{ + // title + QString title = tr( "ADDITIONAL_INFO" ); + out << ruler( title.size() ) << endl; + out << title << endl; + out << ruler( title.size() ) << endl; + out << endl; + + // info + QTreeWidgetItemIterator it( myTree ); + while ( *it ) + { + if ( !( ( *it )->text(0) ).isEmpty() ) + { + out << indent( itemDepth( *it ) ) << ( *it )->text(0); + if ( ( *it )->text(0) == tr( "COLOR" ) ) + out << ":" << spacing() << ( ( ( *it )->background(1) ).color() ).name(); + else if ( !( ( *it )->text(1) ).isEmpty() ) + out << ":" << spacing() << ( *it )->text(1); + out << endl; + } + ++it; + } + out << endl; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class GroupCombo +/// \brief Customized combo box to manage list of mesh groups. +/// \internal +//////////////////////////////////////////////////////////////////////////////// + +class GroupCombo: public QComboBox +{ + class Item: public QStandardItem + { + public: + SMESH::SelectionProxy myGroup; + Item( const SMESH::SelectionProxy& group ) + { + myGroup = group; + setText( myGroup.name() ); + } + SMESH::SelectionProxy group() + { + return myGroup; + } + }; + + SMESH::SelectionProxy myProxy; + +public: + GroupCombo( QWidget* ); + void setSource( const SMESH::SelectionProxy& ); + SMESH::SelectionProxy currentGroup() const; +}; + +/*! + \brief Contructor. + \param parent Parent widget. + \internal +*/ +GroupCombo::GroupCombo( QWidget* parent ): QComboBox( parent ) +{ + setModel( new QStandardItemModel( this ) ); +} + +/*! + \brief Set mesh source. + \param obj Mesh source. + \internal +*/ +void GroupCombo::setSource( const SMESH::SelectionProxy& proxy ) +{ + if ( myProxy == proxy ) + return; + + myProxy = proxy; + + bool blocked = blockSignals( true ); + QStandardItemModel* m = dynamic_cast( model() ); + m->clear(); + + if ( myProxy ) + { + if ( myProxy.type() == SMESH::SelectionProxy::Mesh ) + { + QList groups = myProxy.groups(); + for ( int i = 0; i < groups.count(); ++i ) + { + if ( groups[i] ) + { + QString name = groups[i].name(); + if ( !name.isEmpty() ) + m->appendRow( new Item( groups[i] ) ); + } + } + setCurrentIndex( -1 ); // for performance reasons + } + else if ( myProxy.type() >= SMESH::SelectionProxy::Group ) + { + m->appendRow( new Item( myProxy ) ); + setCurrentIndex( 0 ); + } + } + + blockSignals( blocked ); +} + +/*! + \brief Get currently selected group. + \return Selected group. + \internal +*/ +SMESH::SelectionProxy GroupCombo::currentGroup() const +{ + SMESH::SelectionProxy group; + QStandardItemModel* m = dynamic_cast( model() ); + if ( currentIndex() >= 0 ) + group = dynamic_cast( m->item( currentIndex() ) )->group(); + return group; +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_MeshInfoDlg +/// \brief Mesh information dialog box +/// +/// \todo Move all business logic for element info to SMESHGUI_ElemInfo class. +/// \todo Add selection button to reactivate selection on move from other dlg. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor + \param parent Parent widget. + \param page Dialog page to show at start-up. Defaults to \c BaseInfo. +*/ +SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) + : QDialog( parent ) +{ + setModal( false ); + setAttribute( Qt::WA_DeleteOnClose, true ); + setWindowTitle( tr( "MESH_INFO" ) ); + setSizeGripEnabled( true ); + + myTabWidget = new QTabWidget( this ); + + // base info + + myBaseInfo = new SMESHGUI_BaseInfo( myTabWidget ); + myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) ); + + // elem info + + QWidget* w = new QWidget( myTabWidget ); + + myMode = new QButtonGroup( this ); + myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode ); + myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode ); + myMode->addButton( new QRadioButton( tr( "GROUP_MODE" ), w ), GroupMode ); + myMode->button( NodeMode )->setChecked( true ); + myID = new QLineEdit( w ); + myID->setValidator( new SMESHGUI_IdValidator( this ) ); + myGroups = new GroupCombo( w ); + QStackedWidget* stack = new QStackedWidget( w ); + stack->addWidget( myID ); + stack->addWidget( myGroups ); + myIDPreviewCheck = new QCheckBox( tr( "SHOW_IDS" ), w ); + myIDPreview = new SMESHGUI_IdPreview( SMESH::GetViewWindow( SMESHGUI::GetSMESHGUI() ) ); + + int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 ); + mode = qMin( 1, qMax( 0, mode ) ); + + if ( mode == 0 ) + myElemInfo = new SMESHGUI_SimpleElemInfo( w ); + else + myElemInfo = new SMESHGUI_TreeElemInfo( w ); + stack->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); + + QGridLayout* elemLayout = new QGridLayout( w ); + elemLayout->setMargin( MARGIN ); + elemLayout->setSpacing( SPACING ); + elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 ); + elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 ); + elemLayout->addWidget( myMode->button( GroupMode ), 0, 2 ); + elemLayout->addWidget( stack, 0, 3 ); + elemLayout->addWidget( myIDPreviewCheck, 1, 0, 1, 4 ); + elemLayout->addWidget( myElemInfo, 2, 0, 1, 4 ); + + myTabWidget->addTab( w, tr( "ELEM_INFO" ) ); + + // additional info + + myAddInfo = new SMESHGUI_AddInfo( myTabWidget ); + myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) ); + + // controls info + + myCtrlInfo = new SMESHGUI_CtrlInfo( myTabWidget ); + myTabWidget->addTab( myCtrlInfo, tr( "CTRL_INFO" ) ); + + // buttons + + QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); + okBtn->setAutoDefault( true ); + okBtn->setDefault( true ); + okBtn->setFocus(); + QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this ); + dumpBtn->setAutoDefault( true ); + QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); + helpBtn->setAutoDefault( true ); + + QHBoxLayout* btnLayout = new QHBoxLayout; + btnLayout->setSpacing( SPACING ); + btnLayout->setMargin( 0 ); + + btnLayout->addWidget( okBtn ); + btnLayout->addWidget( dumpBtn ); + btnLayout->addStretch( 10 ); + btnLayout->addWidget( helpBtn ); + + // arrange widgets + + QVBoxLayout* l = new QVBoxLayout ( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + l->addWidget( myTabWidget ); + l->addLayout( btnLayout ); + + // set initial page + + myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) ); + + // set-up connections + + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); + connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); + connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) ); + connect( myGroups, SIGNAL( currentIndexChanged( int ) ), this, SLOT( modeChanged() ) ); + connect( myID, SIGNAL( textChanged( QString ) ), this, SLOT( idChanged() ) ); + connect( myIDPreviewCheck, SIGNAL( toggled( bool ) ), this, SLOT( idPreviewChange( bool ) ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + connect( myElemInfo, SIGNAL( itemInfo( int, QString ) ), this, SLOT( showItemInfo( int, QString ) ) ); + connect( this, SIGNAL( switchMode( int ) ), stack, SLOT( setCurrentIndex( int ) ) ); + + // initialize + + myIDPreviewCheck->setChecked( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "id_preview_resource", false ) ); + updateSelection(); +} + +/*! + \brief Destructor. +*/ +SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg() +{ + delete myIDPreview; +} + +/*! + \brief Show mesh information on given object. + \param io Interactive object. +*/ +void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io ) +{ + if ( !io.IsNull() ) + showInfo( SMESH::SelectionProxy( io ) ); +} + +/*! + \brief Show mesh information on given object. + \param proxy Selection proxy. +*/ +void SMESHGUI_MeshInfoDlg::showInfo( const SMESH::SelectionProxy& proxy ) +{ + SUIT_OverrideCursor wc; + + if ( !proxy ) + return; + + myProxy = proxy; + + SMESH::SMESH_IDSource_var obj = myProxy.object(); + + // "Base info" tab + myBaseInfo->showInfo( proxy ); + + // "Additional info" tab + myAddInfo->showInfo( proxy ); + + // "Quality info" tab + // Note: for performance reasons we update it only if it is currently active + if ( myTabWidget->currentIndex() == CtrlInfo ) + myCtrlInfo->showInfo( proxy ); + + // "Element info" tab + myGroups->setSource( proxy ); + if ( myMode->checkedId() == GroupMode ) { + SMESH::SelectionProxy group = myGroups->currentGroup(); + if ( group ) + myElemInfo->showInfo( group ); + else + myElemInfo->clear(); + } + else { + SVTK_Selector* selector = SMESH::GetSelector(); + QString ID; + int nb = 0; + if ( myProxy.actor() && selector ) { //todo: actor()? + nb = myMode->checkedId() == NodeMode ? + SMESH::GetNameOfSelectedElements( selector, myProxy.io(), ID ) : + SMESH::GetNameOfSelectedNodes( selector, myProxy.io(), ID ); + } + if ( nb > 0 ) { + myID->setText( ID.trimmed() ); + QSet ids; + QStringList idTxt = ID.split( " ", QString::SkipEmptyParts ); + foreach ( ID, idTxt ) + ids << ID.trimmed().toUInt(); + myElemInfo->showInfo( proxy, ids, myMode->checkedId() == ElemMode ); + } + else { + myID->clear(); + myElemInfo->clear(); + } + } +} + +/*! + \brief Update information. +*/ +void SMESHGUI_MeshInfoDlg::updateInfo() +{ + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) + showInfo( selected.First() ); + else + showInfo( myProxy ); +} + +/*! + \brief Clean-up on dialog closing. +*/ +void SMESHGUI_MeshInfoDlg::reject() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + selMgr->clearFilters(); + SMESH::SetPointRepresentation( false ); + if ( SVTK_ViewWindow* viewWindow = SMESH::GetViewWindow() ) + viewWindow->SetSelectionMode( ActorSelection ); + QDialog::reject(); + myIDPreview->SetPointsLabeled( false ); +} + +/*! + \brief Process keyboard event. + \param e Key press event. +*/ +void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e ) +{ + QDialog::keyPressEvent( e ); + if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { + e->accept(); + help(); + } +} + +/*! + \brief Set-up selection mode for currently selected page. +*/ +void SMESHGUI_MeshInfoDlg::updateSelection() +{ + LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); + + disconnect( selMgr, 0, this, 0 ); + selMgr->clearFilters(); + + int selMode = ActorSelection; + if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == NodeMode ) + selMode = NodeSelection; + else if ( myTabWidget->currentIndex() == ElemInfo && myMode->checkedId() == ElemMode ) + selMode = CellSelection; + SMESH::SetPointRepresentation( selMode == NodeSelection ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->SetSelectionMode( selMode ); + + SMESH::SelectionProxy previous = myProxy; + QString ids = myID->text().trimmed(); + myID->clear(); + + connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); + updateInfo(); + + if ( myProxy && myProxy == previous && !ids.isEmpty() ) { + myID->setText( ids ); + idChanged(); + } +} + +/*! + \brief Show documentation on selected dialog page. +*/ +void SMESHGUI_MeshInfoDlg::help() +{ + QString helpPage = "mesh_infos.html"; + switch ( myTabWidget->currentIndex() ) + { + case BaseInfo: + helpPage += "#advanced-mesh-infos-anchor"; + break; + case ElemInfo: + helpPage += "#mesh-element-info-anchor"; + break; + case AddInfo: + helpPage += "#mesh-addition-info-anchor"; + break; + case CtrlInfo: + helpPage += "#mesh-quality-info-anchor"; + break; + default: + break; + } + SMESH::ShowHelpFile( helpPage ); +} + +/*! + \brief Deactivate dialog box. +*/ +void SMESHGUI_MeshInfoDlg::deactivate() +{ + disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); +} + +/*! + \brief Called when users switches between node / element modes. +*/ +void SMESHGUI_MeshInfoDlg::modeChanged() +{ + emit( switchMode( myMode->checkedId() == GroupMode ? 1 : 0 ) ); + myID->clear(); + updateSelection(); +} + +/*! + \brief Called when users prints mesh element ID in the corresponding field. +*/ +void SMESHGUI_MeshInfoDlg::idChanged() +{ + myIDPreview->SetPointsLabeled( false ); + + if ( myProxy ) { + TColStd_MapOfInteger ID; + QSet ids; + std::vector idVec; + std::list< gp_XYZ > aGrCentersXYZ; + SMESH::XYZ xyz; + const bool isElem = ( myMode->checkedId() == ElemMode ); + QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts ); + foreach ( QString tid, idTxt ) { + long id = tid.toUInt(); + if ( isElem ? myProxy.hasElement( id ) : myProxy.hasNode( id )) + { + ID.Add( id ); + ids << id; + if ( isElem && myProxy.actor() && myProxy.elementGravityCenter( id, xyz )) + { + idVec.push_back( id ); + aGrCentersXYZ.push_back( xyz ); + } + } + } + SVTK_Selector* selector = SMESH::GetSelector(); + if ( myProxy.actor() && selector ) { + Handle(SALOME_InteractiveObject) IO = myProxy.actor()->getIO(); + selector->AddOrRemoveIndex( IO, ID, false ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + { + if ( myMode->checkedId() == NodeMode ) + myIDPreview->SetPointsData( myProxy.actor()->GetObject()->GetMesh(), ID ); + else + myIDPreview->SetElemsData( idVec, aGrCentersXYZ ); + + bool showIDs = ( !ID.IsEmpty() && + myIDPreviewCheck->isChecked() && + myTabWidget->currentIndex() == ElemInfo ); + myIDPreview->SetPointsLabeled( showIDs, myProxy.actor()->GetVisibility() ); + + aViewWindow->highlight( IO, true, true ); + aViewWindow->Repaint(); + } + } + myElemInfo->showInfo( myProxy, ids, isElem ); + } +} + +/*! + * \brief Show IDs clicked + */ +void SMESHGUI_MeshInfoDlg::idPreviewChange( bool isOn ) +{ + myIDPreview->SetPointsLabeled( isOn && !myID->text().simplified().isEmpty() ); + SMESHGUI::resourceMgr()->setValue("SMESH", "id_preview_resource", isOn ); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) + aViewWindow->Repaint(); +} + +void SMESHGUI_MeshInfoDlg::showItemInfo( int type, const QString& ids ) +{ + if ( !ids.isEmpty() && ( type == NodeConnectivity || type == ElemConnectivity )) { + myMode->button( type - NodeConnectivity )->click(); + myID->setText( ids ); + } +} + +/*! + \brief Dump information to file. +*/ +void SMESHGUI_MeshInfoDlg::dump() +{ + DumpFileDlg fd( this ); + fd.setWindowTitle( tr( "SAVE_INFO" ) ); + fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) ); + fd.setChecked( BaseInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_base", true ) ); + fd.setChecked( ElemInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_elem", true ) ); + fd.setChecked( AddInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_add", true ) ); + fd.setChecked( CtrlInfo, SMESHGUI::resourceMgr()->booleanValue( "SMESH", "info_dump_ctrl", true ) ); + if ( fd.exec() == QDialog::Accepted ) + { + QString fileName = fd.selectedFile(); + if ( !fileName.isEmpty() ) { + QFile file( fileName ); + if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + return; + + QTextStream out( &file ); + if ( fd.isChecked( BaseInfo ) ) myBaseInfo->saveInfo( out ); + if ( fd.isChecked( ElemInfo ) ) myElemInfo->saveInfo( out ); + if ( fd.isChecked( AddInfo ) ) myAddInfo->saveInfo( out ); + if ( fd.isChecked( CtrlInfo ) ) myCtrlInfo->saveInfo( out ); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_CtrlInfo +/// \brief Show quality statistics information on selected object. +/// +/// Displays quality controls statistics about selected object: mesh, sub-mesh, +/// group or arbitrary ID source. +//////////////////////////////////////////////////////////////////////////////// + +/*! + \brief Constructor. + \param parent Parent widget. Defaults to 0. +*/ +SMESHGUI_CtrlInfo::SMESHGUI_CtrlInfo( QWidget* parent ): SMESHGUI_Info( parent ) +{ + QGridLayout* l = new QGridLayout( this ); + l->setMargin( MARGIN ); + l->setSpacing( SPACING ); + + QIcon aComputeIcon( SUIT_Session::session()->resourceMgr()->loadPixmap( "SMESH", tr( "ICON_COMPUTE" ) ) ); + SMESH::FilterManager_var aFilterMgr = SMESH::GetFilterManager(); + + // name + QLabel* aNameLab = createLabel( tr( "NAME_LAB" ), this, Bold ); + QLabel* aName = createField( this, "ctrlName" ); + aName->setMinimumWidth( 150 ); + myWidgets << aName; + + // nodes info + QLabel* aNodesLab = createLabel( tr( "NODES_INFO" ), this, Bold ); + QLabel* aNodesFreeLab = new QLabel( tr( "NUMBER_OF_THE_FREE_NODES" ), this ); + QLabel* aNodesFree = createField( this, "ctrlNodesFree" ); + myWidgets << aNodesFree; + myPredicates << aFilterMgr->CreateFreeNodes(); + // + QLabel* aNodesNbConnLab = new QLabel( tr( "MAX_NODE_CONNECTIVITY" ), this ); + QLabel* aNodesNbConn = createField( this, "ctrlNodesCnty" ); + myWidgets << aNodesNbConn; + myNodeConnFunctor = aFilterMgr->CreateNodeConnectivityNumber(); + // + QLabel* aNodesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_NODES" ), this ); + QLabel* aNodesDouble = createField( this, "ctrlNodesDouble" ); + myWidgets << aNodesDouble; + myPredicates << aFilterMgr->CreateEqualNodes(); + QLabel* aToleranceLab = new QLabel( tr( "DOUBLE_NODES_TOLERANCE" ), this ); + myToleranceWidget = new SMESHGUI_SpinBox( this ); + myToleranceWidget->RangeStepAndValidator(0.0000000001, 1000000.0, 0.0000001, "length_precision" ); + myToleranceWidget->setAcceptNames( false ); + myToleranceWidget->SetValue( SMESHGUI::resourceMgr()->doubleValue( "SMESH", "equal_nodes_tolerance", 1e-7 ) ); + + // edges info + QLabel* anEdgesLab = createLabel( tr( "EDGES_INFO" ), this, Bold ); + QLabel* anEdgesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_EDGES" ), this ); + QLabel* anEdgesDouble = createField( this, "ctrlEdgesDouble" ); + myWidgets << anEdgesDouble; + myPredicates << aFilterMgr->CreateEqualEdges(); + + // faces info + QLabel* aFacesLab = createLabel( tr( "FACES_INFO" ), this, Bold ); + QLabel* aFacesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_FACES" ), this ); + QLabel* aFacesDouble = createField( this, "ctrlFacesDouble" ); + myWidgets << aFacesDouble; + myPredicates << aFilterMgr->CreateEqualFaces(); + QLabel* aFacesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this ); + QLabel* aFacesOver = createField( this, "ctrlFacesOver" ); + myWidgets << aFacesOver; + myPredicates << aFilterMgr->CreateOverConstrainedFace(); + QLabel* anAspectRatioLab = new QLabel( tr( "ASPECT_RATIO_HISTOGRAM" ), this ); + myPlot = createPlot( this ); + myAspectRatio = aFilterMgr->CreateAspectRatio(); + + // volumes info + QLabel* aVolumesLab = createLabel( tr( "VOLUMES_INFO" ), this, Bold ); + QLabel* aVolumesDoubleLab = new QLabel( tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ), this ); + QLabel* aVolumesDouble = createField( this, "ctrlVolumesDouble" ); + myWidgets << aVolumesDouble; + myPredicates << aFilterMgr->CreateEqualVolumes(); + QLabel* aVolumesOverLab = new QLabel( tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ), this ); + QLabel* aVolumesOver = createField( this, "ctrlVolumesOver" ); + myWidgets << aVolumesOver; + myPredicates << aFilterMgr->CreateOverConstrainedVolume(); + QLabel* anAspectRatio3DLab = new QLabel( tr( "ASPECT_RATIO_3D_HISTOGRAM" ), this ); + myPlot3D = createPlot( this ); + myAspectRatio3D = aFilterMgr->CreateAspectRatio3D(); + + QToolButton* aFreeNodesBtn = new QToolButton( this ); + aFreeNodesBtn->setIcon(aComputeIcon); + myButtons << aFreeNodesBtn; //0 + + QToolButton* aNodesNbConnBtn = new QToolButton( this ); + aNodesNbConnBtn->setIcon(aComputeIcon); + myButtons << aNodesNbConnBtn; //1 + + QToolButton* aDoubleNodesBtn = new QToolButton( this ); + aDoubleNodesBtn->setIcon(aComputeIcon); + myButtons << aDoubleNodesBtn; //2 + + QToolButton* aDoubleEdgesBtn = new QToolButton( this ); + aDoubleEdgesBtn->setIcon(aComputeIcon); + myButtons << aDoubleEdgesBtn; //3 + + QToolButton* aDoubleFacesBtn = new QToolButton( this ); + aDoubleFacesBtn->setIcon(aComputeIcon); + myButtons << aDoubleFacesBtn; //4 + + QToolButton* aOverContFacesBtn = new QToolButton( this ); + aOverContFacesBtn->setIcon(aComputeIcon); + myButtons << aOverContFacesBtn; //5 + + QToolButton* aComputeFaceBtn = new QToolButton( this ); + aComputeFaceBtn->setIcon(aComputeIcon); + myButtons << aComputeFaceBtn; //6 + + QToolButton* aDoubleVolumesBtn = new QToolButton( this ); + aDoubleVolumesBtn->setIcon(aComputeIcon); + myButtons << aDoubleVolumesBtn; //7 + + QToolButton* aOverContVolumesBtn = new QToolButton( this ); + aOverContVolumesBtn->setIcon(aComputeIcon); + myButtons << aOverContVolumesBtn; //8 + + QToolButton* aComputeVolumeBtn = new QToolButton( this ); + aComputeVolumeBtn->setIcon(aComputeIcon); + myButtons << aComputeVolumeBtn; //9 + + connect( aComputeFaceBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio() ) ); + connect( aComputeVolumeBtn, SIGNAL( clicked() ), this, SLOT( computeAspectRatio3D() ) ); + connect( aFreeNodesBtn, SIGNAL( clicked() ), this, SLOT( computeFreeNodesInfo() ) ); + connect( aNodesNbConnBtn, SIGNAL( clicked() ), this, SLOT( computeNodesNbConnInfo() ) ); + connect( aDoubleNodesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleNodesInfo() ) ); + connect( aDoubleEdgesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleEdgesInfo() ) ); + connect( aDoubleFacesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleFacesInfo() ) ); + connect( aOverContFacesBtn, SIGNAL( clicked() ), this, SLOT( computeOverConstrainedFacesInfo() ) ); + connect( aDoubleVolumesBtn, SIGNAL( clicked() ), this, SLOT( computeDoubleVolumesInfo() ) ); + connect( aOverContVolumesBtn,SIGNAL( clicked() ), this, SLOT( computeOverConstrainedVolumesInfo() ) ); + connect( myToleranceWidget, SIGNAL( valueChanged( double ) ), this, SLOT( setTolerance( double ) ) ); + + l->addWidget( aNameLab, 0, 0 ); //0 + l->addWidget( aName, 0, 1, 1, 2 ); //1 + l->addWidget( aNodesLab, 1, 0, 1, 3 ); //2 + l->addWidget( aNodesFreeLab, 2, 0 ); //3 + l->addWidget( aNodesFree, 2, 1 ); //4 + l->addWidget( aFreeNodesBtn, 2, 2 ); //5 + l->addWidget( aNodesNbConnLab, 3, 0 ); //6 + l->addWidget( aNodesNbConn, 3, 1 ); //7 + l->addWidget( aNodesNbConnBtn, 3, 2 ); //8 + l->addWidget( aNodesDoubleLab, 4, 0 ); //9 + l->addWidget( aNodesDouble, 4, 1 ); //10 + l->addWidget( aDoubleNodesBtn, 4, 2 ); //11 + l->addWidget( aToleranceLab, 5, 0 ); //12 + l->addWidget( myToleranceWidget, 5, 1 ); //13 + l->addWidget( anEdgesLab, 6, 0, 1, 3 ); //14 + l->addWidget( anEdgesDoubleLab, 7, 0 ); //15 + l->addWidget( anEdgesDouble, 7, 1 ); //16 + l->addWidget( aDoubleEdgesBtn, 7, 2 ); //17 + l->addWidget( aFacesLab, 8, 0, 1, 3 ); //18 + l->addWidget( aFacesDoubleLab, 9, 0 ); //19 + l->addWidget( aFacesDouble, 9, 1 ); //20 + l->addWidget( aDoubleFacesBtn, 9, 2 ); //21 + l->addWidget( aFacesOverLab, 10, 0 ); //22 + l->addWidget( aFacesOver, 10, 1 ); //23 + l->addWidget( aOverContFacesBtn, 10, 2 ); //24 + l->addWidget( anAspectRatioLab, 11, 0 ); //25 + l->addWidget( aComputeFaceBtn, 11, 2 ); //26 + l->addWidget( myPlot, 12, 0, 1, 3 );//27 + l->addWidget( aVolumesLab, 13, 0, 1, 3 );//28 + l->addWidget( aVolumesDoubleLab, 14, 0 ); //29 + l->addWidget( aVolumesDouble, 14, 1 ); //30 + l->addWidget( aDoubleVolumesBtn, 14, 2 ); //31 + l->addWidget( aVolumesOverLab, 15, 0 ); //32 + l->addWidget( aVolumesOver, 15, 1 ); //33 + l->addWidget( aOverContVolumesBtn,15, 2 ); //34 + l->addWidget( anAspectRatio3DLab, 16, 0 ); //35 + l->addWidget( aComputeVolumeBtn, 16, 2 ); //36 + l->addWidget( myPlot3D, 17, 0, 1, 3 );//37 + + l->setColumnStretch( 0, 0 ); + l->setColumnStretch( 1, 5 ); + l->setRowStretch ( 12, 5 ); + l->setRowStretch ( 17, 5 ); + l->setRowStretch ( 18, 1 ); + + clearInternal(); +} + +/*! + \brief Destructor. +*/ +SMESHGUI_CtrlInfo::~SMESHGUI_CtrlInfo() +{ +} + +/*! + \brief Create plot widget. + \param parent Parent widget. + \return New plot widget. +*/ +QwtPlot* SMESHGUI_CtrlInfo::createPlot( QWidget* parent ) +{ + QwtPlot* aPlot = new QwtPlot( parent ); + aPlot->setMinimumSize( 100, 100 ); + QFont xFont = aPlot->axisFont( QwtPlot::xBottom ); + xFont.setPointSize( 5 ); + QFont yFont = aPlot->axisFont( QwtPlot::yLeft ); + yFont.setPointSize( 5 ); + aPlot->setAxisFont( QwtPlot::xBottom, xFont ); + aPlot->setAxisFont( QwtPlot::yLeft, yFont ); + aPlot->replot(); + return aPlot; +} + +/*! + \brief Show information on given object. + \param proxy Object to show information on (mesh, sub-mesh, group, ID source). +*/ +void SMESHGUI_CtrlInfo::showInfo( const SMESH::SelectionProxy& proxy ) +{ + clearInternal(); + + if ( !proxy ) + return; + + myProxy = proxy; + SMESH::SMESH_IDSource_var obj = proxy.object(); + + myWidgets[0]->setText( proxy.name() ); + + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); + if ( mesh->_is_nil() ) return; + + const bool meshLoaded = mesh->IsLoaded(); + if ( !meshLoaded ) // mesh not yet loaded from the hdf file + // enable Compute buttons, just in case obj->GetNbElementsByType() fails + for ( int i = 0; i < myButtons.count(); ++i ) + myButtons[i]->setEnabled( true ); + + SMESH::long_array_var nbElemsByType = obj->GetNbElementsByType(); + if ( ! &nbElemsByType.in() ) return; + + const CORBA::Long ctrlLimit = + meshLoaded ? SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_controls_limit", 3000 ) : -1; + + // nodes info + const CORBA::Long nbNodes = nbElemsByType[ SMESH::NODE ]; + // const CORBA::Long nbElems = ( nbElemsByType[ SMESH::EDGE ] + + // nbElemsByType[ SMESH::FACE ] + + // nbElemsByType[ SMESH::VOLUME ] ); + if ( nbNodes > 0 ) { + if ( nbNodes <= ctrlLimit ) { + // free nodes + computeFreeNodesInfo(); + // node connectivity number + computeNodesNbConnInfo(); + // double nodes + computeDoubleNodesInfo(); + } + else { + myButtons[0]->setEnabled( true ); + myButtons[1]->setEnabled( true ); + myButtons[2]->setEnabled( true ); + } + } + else { + for( int i=2; i<=13; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); + } + + // edges info + if ( nbElemsByType[ SMESH::EDGE ] > 0 ) { + // double edges + if( nbElemsByType[ SMESH::EDGE ] <= ctrlLimit ) + computeDoubleEdgesInfo(); + else + myButtons[3]->setEnabled( true ); + } + else { + for( int i=14; i<=17; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); + } + + // faces info + if ( nbElemsByType[ SMESH::FACE ] > 0 ) { + if ( nbElemsByType[ SMESH::FACE ] <= ctrlLimit ) { + // double faces + computeDoubleFacesInfo(); + // over constrained faces + computeOverConstrainedFacesInfo(); + // aspect Ratio histogram + computeAspectRatio(); + } + else { + myButtons[4]->setEnabled( true ); + myButtons[5]->setEnabled( true ); + myButtons[6]->setEnabled( true ); + } +#ifdef DISABLE_PLOT2DVIEWER + for( int i=25; i<=27; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); +#endif + } + else { + for( int i=18; i<=27; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); + } + + // volumes info + if ( nbElemsByType[ SMESH::VOLUME ] > 0 ) { + if ( nbElemsByType[ SMESH::VOLUME ] <= ctrlLimit ) { + // double volumes + computeDoubleVolumesInfo(); + // over constrained volumes + computeOverConstrainedVolumesInfo(); + // aspect Ratio 3D histogram + computeAspectRatio3D(); + } + else { + myButtons[7]->setEnabled( true ); + myButtons[8]->setEnabled( true ); + myButtons[9]->setEnabled( true ); + } +#ifdef DISABLE_PLOT2DVIEWER + for( int i=35; i<=37; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); +#endif + } + else { + for( int i=28; i<=37; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( false ); + } +} + +//================================================================================ +/*! + * \brief Computes and shows nb of elements satisfying a given predicate + * \param [in] ft - a predicate type (SMESH::FunctorType) + * \param [in] iBut - index of one of myButtons to disable + * \param [in] iWdg - index of one of myWidgets to show the computed number + */ +//================================================================================ + +void SMESHGUI_CtrlInfo::computeNb( int ft, int iBut, int iWdg ) +{ + myButtons[ iBut ]->setEnabled( false ); + myWidgets[ iWdg ]->setText( "" ); + + if ( !myProxy ) + return; + + SUIT_OverrideCursor wc; + + SMESH::SMESH_IDSource_var obj = myProxy.object(); + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); + + if ( !mesh->_is_nil() && !mesh->IsLoaded() ) + { + mesh->Load(); + showInfo( myProxy ); // try to show all values + if ( !myWidgets[ iWdg ]->text().isEmpty() ) + return; // predicate already computed + } + // look for a predicate of type + for ( int i = 0; i < myPredicates.count(); ++i ) + if ( myPredicates[i]->GetFunctorType() == ft ) + { + CORBA::Long nb = myPredicates[i]->NbSatisfying( obj ); + myWidgets[ iWdg ]->setText( QString::number( nb ) ); + } +} + +void SMESHGUI_CtrlInfo::computeFreeNodesInfo() +{ + computeNb( SMESH::FT_FreeNodes, 0, 1 ); +} + +void SMESHGUI_CtrlInfo::computeDoubleNodesInfo() +{ + computeNb( SMESH::FT_EqualNodes, 2, 3 ); +} - // size - QTreeWidgetItem* sizeItem = createItem( parent, Bold ); - sizeItem->setText( 0, tr( "SIZE" ) ); - sizeItem->setText( 1, QString::number( grp->Size() ) ); +void SMESHGUI_CtrlInfo::computeDoubleEdgesInfo() +{ + computeNb( SMESH::FT_EqualEdges, 3, 4 ); +} - // color - SALOMEDS::Color color = grp->GetColor(); - QTreeWidgetItem* colorItem = createItem( parent, Bold ); - colorItem->setText( 0, tr( "COLOR" ) ); - colorItem->setBackground( 1, QBrush( QColor( color.R*255., color.G*255., color.B*255.) ) ); +void SMESHGUI_CtrlInfo::computeDoubleFacesInfo() +{ + computeNb( SMESH::FT_EqualFaces, 4, 5 ); +} - // nb of underlying nodes - if ( grp->GetType() != SMESH::NODE) { - QTreeWidgetItem* nodesItem = createItem( parent, Bold ); - nodesItem->setText( 0, tr( "NB_NODES" ) ); - int nbNodesLimit = SMESHGUI::resourceMgr()->integerValue( "SMESH", "info_groups_nodes_limit", 100000 ); - SMESH::SMESH_Mesh_var mesh = grp->GetMesh(); - bool meshLoaded = mesh->IsLoaded(); - bool toShowNodes = ( grp->IsNodeInfoAvailable() || nbNodesLimit <= 0 || grp->Size() <= nbNodesLimit ); - if ( toShowNodes && meshLoaded ) { - // already calculated and up-to-date - nodesItem->setText( 1, QString::number( grp->GetNumberOfNodes() ) ); - } - else { - QPushButton* btn = new QPushButton( tr( meshLoaded ? "COMPUTE" : "LOAD"), this ); - setItemWidget( nodesItem, 1, btn ); - GrpComputor* comp = new GrpComputor( grp, nodesItem, this ); - connect( btn, SIGNAL( clicked() ), comp, SLOT( compute() ) ); - myComputors.append( comp ); - if ( !meshLoaded ) - connect( btn, SIGNAL( clicked() ), this, SLOT( changeLoadToCompute() ) ); - } - } +void SMESHGUI_CtrlInfo::computeOverConstrainedFacesInfo() +{ + computeNb( SMESH::FT_OverConstrainedFace, 5, 6 ); } -void SMESHGUI_AddInfo::showGroups() +void SMESHGUI_CtrlInfo::computeDoubleVolumesInfo() { - myComputors.clear(); + computeNb( SMESH::FT_EqualVolumes, 7, 7 ); +} - QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item - if ( !parent ) return; +void SMESHGUI_CtrlInfo::computeOverConstrainedVolumesInfo() +{ + computeNb( SMESH::FT_OverConstrainedVolume, 8, 8 ); +} - int idx = property( "group_index" ).toInt(); +void SMESHGUI_CtrlInfo::computeNodesNbConnInfo() +{ + myButtons[ 1 ]->setEnabled( false ); + myWidgets[ 2 ]->setText( "" ); - QTreeWidgetItem* itemGroups = 0; - for ( int i = 0; i < parent->childCount() && !itemGroups; i++ ) { - if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == GROUPS_ID ) { - itemGroups = parent->child( i ); - ExtraWidget* extra = dynamic_cast( itemWidget( itemGroups, 1 ) ); - if ( extra ) - extra->updateControls( myGroups->length(), idx ); - while ( itemGroups->childCount() ) delete itemGroups->child( 0 ); // clear child items - } + if ( !myProxy ) + return; + + SUIT_OverrideCursor wc; + + SMESH::SMESH_IDSource_var obj = myProxy.object(); + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); + + if ( !mesh->IsLoaded() ) + { + mesh->Load(); + showInfo( myProxy ); // try to show all values + if ( !myWidgets[ 2 ]->text().isEmpty() ) + return; // already computed } + myNodeConnFunctor->SetMesh( mesh ); + SMESH::Histogram_var histogram = + myNodeConnFunctor->GetLocalHistogram( 1, /*isLogarithmic=*/false, obj ); - QMap grpItems; - for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)myGroups->length() ); i++ ) { - SMESH::SMESH_GroupBase_var grp = myGroups[i]; - if ( CORBA::is_nil( grp ) ) continue; - _PTR(SObject) grpSObj = SMESH::ObjectToSObject( grp ); - if ( !grpSObj ) continue; + myWidgets[ 2 ]->setText( QString::number( histogram[0].max ) ); +} - int grpType = grp->GetType(); +void SMESHGUI_CtrlInfo::computeAspectRatio() +{ +#ifndef DISABLE_PLOT2DVIEWER + myButtons[6]->setEnabled( false ); - if ( !itemGroups ) { - // create top-level groups container item - itemGroups = createItem( parent, Bold | All ); - itemGroups->setText( 0, tr( "GROUPS" ) ); - itemGroups->setData( 0, Qt::UserRole, GROUPS_ID ); + if ( !myProxy ) + return; - // total number of groups > 10, show extra widgets for info browsing - if ( myGroups->length() > MAXITEMS ) { - ExtraWidget* extra = new ExtraWidget( this, true ); - connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousGroups() ) ); - connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextGroups() ) ); - setItemWidget( itemGroups, 1, extra ); - extra->updateControls( myGroups->length(), idx ); - } - } + SUIT_OverrideCursor wc; - if ( grpItems.find( grpType ) == grpItems.end() ) { - grpItems[ grpType ] = createItem( itemGroups, Bold | All ); - grpItems[ grpType ]->setText( 0, tr( QString( "GROUPS_%1" ).arg( grpType ).toLatin1().constData() ) ); - itemGroups->insertChild( grpType-1, grpItems[ grpType ] ); - } - - // group name - QTreeWidgetItem* grpNameItem = createItem( grpItems[ grpType ] ); - grpNameItem->setText( 0, QString( grpSObj->GetName().c_str() ).trimmed() ); // name is trimmed + SMESH::SMESH_IDSource_var obj = myProxy.object(); + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); - // group info - groupInfo( grp.in(), grpNameItem ); + Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio ); + if ( aHistogram && !aHistogram->isEmpty() ) { + QwtPlotItem* anItem = aHistogram->createPlotItem(); + anItem->attach( myPlot ); + myPlot->replot(); } + delete aHistogram; +#endif } -void SMESHGUI_AddInfo::showSubMeshes() +void SMESHGUI_CtrlInfo::computeAspectRatio3D() { - QTreeWidgetItem* parent = topLevelItemCount() > 0 ? topLevelItem( 0 ) : 0; // parent should be first top level item - if ( !parent ) return; +#ifndef DISABLE_PLOT2DVIEWER + myButtons[9]->setEnabled( false ); - int idx = property( "submesh_index" ).toInt(); - - QTreeWidgetItem* itemSubMeshes = 0; - for ( int i = 0; i < parent->childCount() && !itemSubMeshes; i++ ) { - if ( parent->child( i )->data( 0, Qt::UserRole ).toInt() == SUBMESHES_ID ) { - itemSubMeshes = parent->child( i ); - ExtraWidget* extra = dynamic_cast( itemWidget( itemSubMeshes, 1 ) ); - if ( extra ) - extra->updateControls( mySubMeshes->length(), idx ); - while ( itemSubMeshes->childCount() ) delete itemSubMeshes->child( 0 ); // clear child items - } - } + if ( !myProxy ) + return; - QMap smItems; - for ( int i = idx*MAXITEMS ; i < qMin( (idx+1)*MAXITEMS, (int)mySubMeshes->length() ); i++ ) { - SMESH::SMESH_subMesh_var sm = mySubMeshes[i]; - if ( CORBA::is_nil( sm ) ) continue; - _PTR(SObject) smSObj = SMESH::ObjectToSObject( sm ); - if ( !smSObj ) continue; - - GEOM::GEOM_Object_var gobj = sm->GetSubShape(); - if ( CORBA::is_nil(gobj ) ) continue; - - int smType = gobj->GetShapeType(); - if ( smType == GEOM::COMPSOLID ) smType = GEOM::COMPOUND; + SUIT_OverrideCursor wc; - if ( !itemSubMeshes ) { - itemSubMeshes = createItem( parent, Bold | All ); - itemSubMeshes->setText( 0, tr( "SUBMESHES" ) ); - itemSubMeshes->setData( 0, Qt::UserRole, SUBMESHES_ID ); + SMESH::SMESH_IDSource_var obj = myProxy.object(); + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); - // total number of sub-meshes > 10, show extra widgets for info browsing - if ( mySubMeshes->length() > MAXITEMS ) { - ExtraWidget* extra = new ExtraWidget( this, true ); - connect( extra->prev, SIGNAL( clicked() ), this, SLOT( showPreviousSubMeshes() ) ); - connect( extra->next, SIGNAL( clicked() ), this, SLOT( showNextSubMeshes() ) ); - setItemWidget( itemSubMeshes, 1, extra ); - extra->updateControls( mySubMeshes->length(), idx ); - } - } - - if ( smItems.find( smType ) == smItems.end() ) { - smItems[ smType ] = createItem( itemSubMeshes, Bold | All ); - smItems[ smType ]->setText( 0, tr( QString( "SUBMESHES_%1" ).arg( smType ).toLatin1().constData() ) ); - itemSubMeshes->insertChild( smType, smItems[ smType ] ); - } - - // submesh name - QTreeWidgetItem* smNameItem = createItem( smItems[ smType ] ); - smNameItem->setText( 0, QString( smSObj->GetName().c_str() ).trimmed() ); // name is trimmed - - // submesh info - subMeshInfo( sm.in(), smNameItem ); + Plot2d_Histogram* aHistogram = getHistogram( myAspectRatio3D ); + if ( aHistogram && !aHistogram->isEmpty() ) { + QwtPlotItem* anItem = aHistogram->createPlotItem(); + anItem->attach( myPlot3D ); + myPlot3D->replot(); } + delete aHistogram; +#endif } /*! - * \brief Change button label of "nb underlying node" group from "Load" to "Compute" - */ -void SMESHGUI_AddInfo::changeLoadToCompute() + \brief Internal clean-up (reset widget) +*/ +void SMESHGUI_CtrlInfo::clearInternal() { - for ( int i = 0; i < myComputors.count(); ++i ) - { - if ( QTreeWidgetItem* item = myComputors[i]->getItem() ) - { - if ( QPushButton* btn = qobject_cast( itemWidget ( item, 1 ) ) ) - btn->setText( tr("COMPUTE") ); - } - } + for( int i=0; i<=37; i++) + dynamic_cast(layout())->itemAt(i)->widget()->setVisible( true ); + for( int i=0; i<=9; i++) + myButtons[i]->setEnabled( false ); + myPlot->detachItems(); + myPlot3D->detachItems(); + myPlot->replot(); + myPlot3D->replot(); + myWidgets[0]->setText( QString() ); + for ( int i = 1; i < myWidgets.count(); i++ ) + myWidgets[i]->setText( "" ); } -void SMESHGUI_AddInfo::showPreviousGroups() +void SMESHGUI_CtrlInfo::setTolerance( double theTolerance ) { - int idx = property( "group_index" ).toInt(); - setProperty( "group_index", idx-1 ); - showGroups(); + //SMESH::long_array_var anElems = getElementsByType( SMESH::NODE ); + myButtons[1]->setEnabled( true ); + myWidgets[2]->setText(""); } -void SMESHGUI_AddInfo::showNextGroups() +#ifndef DISABLE_PLOT2DVIEWER +Plot2d_Histogram* SMESHGUI_CtrlInfo::getHistogram( SMESH::NumericalFunctor_ptr aNumFun ) { - int idx = property( "group_index" ).toInt(); - setProperty( "group_index", idx+1 ); - showGroups(); -} + SUIT_OverrideCursor wc; -void SMESHGUI_AddInfo::showPreviousSubMeshes() -{ - int idx = property( "submesh_index" ).toInt(); - setProperty( "submesh_index", idx-1 ); - showSubMeshes(); + SMESH::SMESH_IDSource_var obj = myProxy.object(); + SMESH::SMESH_Mesh_var mesh = obj->GetMesh(); + + if ( !mesh->IsLoaded() ) + mesh->Load(); + aNumFun->SetMesh( mesh ); + + CORBA::Long cprecision = 6; + if ( SMESHGUI::resourceMgr()->booleanValue( "SMESH", "use_precision", false ) ) + cprecision = SMESHGUI::resourceMgr()->integerValue( "SMESH", "controls_precision", -1 ); + aNumFun->SetPrecision( cprecision ); + + int nbIntervals = SMESHGUI::resourceMgr()->integerValue( "SMESH", "scalar_bar_num_colors", false ); + + SMESH::Histogram_var histogramVar = aNumFun->GetLocalHistogram( nbIntervals, + /*isLogarithmic=*/false, + obj ); + Plot2d_Histogram* aHistogram = new Plot2d_Histogram(); + aHistogram->setColor( palette().color( QPalette::Highlight ) ); + if ( &histogramVar.in() ) + { + for ( size_t i = 0, nb = histogramVar->length(); i < nb; i++ ) + aHistogram->addPoint( 0.5 * ( histogramVar[i].min + histogramVar[i].max ), histogramVar[i].nbEvents ); + if ( histogramVar->length() >= 2 ) + aHistogram->setWidth( ( histogramVar[0].max - histogramVar[0].min ) * 0.8 ); + } + return aHistogram; } +#endif -void SMESHGUI_AddInfo::showNextSubMeshes() +void SMESHGUI_CtrlInfo::saveInfo( QTextStream &out ) { - int idx = property( "submesh_index" ).toInt(); - setProperty( "submesh_index", idx+1 ); - showSubMeshes(); + // title + QString title = tr( "CTRL_INFO" ); + out << ruler( title.size() ) << endl; + out << title << endl; + out << ruler( title.size() ) << endl; + out << endl; + + // info + out << tr( "NAME_LAB" ) << " " << myWidgets[0]->text() << endl; + out << tr( "NODES_INFO" ) << endl; + out << indent() << tr( "NUMBER_OF_THE_FREE_NODES" ) << ": " << myWidgets[1]->text() << endl; + out << indent() << tr( "NUMBER_OF_THE_DOUBLE_NODES" ) << ": " << myWidgets[2]->text() << endl; + out << tr( "EDGES_INFO" ) << endl; + out << indent() << tr( "NUMBER_OF_THE_DOUBLE_EDGES" ) << ": " << myWidgets[3]->text() << endl; + out << tr( "FACES_INFO" ) << endl; + out << indent() << tr( "NUMBER_OF_THE_DOUBLE_FACES" ) << ": " << myWidgets[4]->text() << endl; + out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[5]->text() << endl; + out << tr( "VOLUMES_INFO" ) << endl; + out << indent() << tr( "NUMBER_OF_THE_DOUBLE_VOLUMES" ) << ": " << myWidgets[6]->text() << endl; + out << indent() << tr( "NUMBER_OF_THE_OVER_CONSTRAINED" ) << ": " << myWidgets[7]->text() << endl; } -/*! - \class SMESHGUI_MeshInfoDlg - \brief Mesh information dialog box -*/ +//////////////////////////////////////////////////////////////////////////////// +/// \class SMESHGUI_CtrlInfoDlg +/// \brief Overall Mesh Quality dialog. +/// \todo Add selection button to reactivate selection on move from other dlg. +//////////////////////////////////////////////////////////////////////////////// /*! \brief Constructor \param parent parent widget - \param page specifies the dialog page to be shown at the start-up */ -SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) -: QDialog( parent ), myActor( 0 ) +SMESHGUI_CtrlInfoDlg::SMESHGUI_CtrlInfoDlg( QWidget* parent ) + : QDialog( parent ) { - setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); - setWindowTitle( tr( "MESH_INFO" ) ); - setSizeGripEnabled( true ); - - myTabWidget = new QTabWidget( this ); - - // base info - - myBaseInfo = new SMESHGUI_MeshInfo( myTabWidget ); - myTabWidget->addTab( myBaseInfo, tr( "BASE_INFO" ) ); - - // elem info - - QWidget* w = new QWidget( myTabWidget ); - - myMode = new QButtonGroup( this ); - myMode->addButton( new QRadioButton( tr( "NODE_MODE" ), w ), NodeMode ); - myMode->addButton( new QRadioButton( tr( "ELEM_MODE" ), w ), ElemMode ); - myMode->button( NodeMode )->setChecked( true ); - myID = new QLineEdit( w ); - myID->setValidator( new SMESHGUI_IdValidator( this ) ); - - int mode = SMESHGUI::resourceMgr()->integerValue( "SMESH", "mesh_elem_info", 1 ); - mode = qMin( 1, qMax( 0, mode ) ); - - if ( mode == 0 ) - myElemInfo = new SMESHGUI_SimpleElemInfo( w ); - else - myElemInfo = new SMESHGUI_TreeElemInfo( w ); + setWindowTitle( tr( "CTRL_INFO" ) ); + setMinimumSize( 400, 600 ); - QGridLayout* elemLayout = new QGridLayout( w ); - elemLayout->setMargin( MARGIN ); - elemLayout->setSpacing( SPACING ); - elemLayout->addWidget( myMode->button( NodeMode ), 0, 0 ); - elemLayout->addWidget( myMode->button( ElemMode ), 0, 1 ); - elemLayout->addWidget( myID, 0, 2 ); - elemLayout->addWidget( myElemInfo, 1, 0, 1, 3 ); + myCtrlInfo = new SMESHGUI_CtrlInfo( this ); - myTabWidget->addTab( w, tr( "ELEM_INFO" ) ); - - // additional info - - myAddInfo = new SMESHGUI_AddInfo( myTabWidget ); - myTabWidget->addTab( myAddInfo, tr( "ADDITIONAL_INFO" ) ); - // buttons - QPushButton* okBtn = new QPushButton( tr( "SMESH_BUT_OK" ), this ); okBtn->setAutoDefault( true ); okBtn->setDefault( true ); okBtn->setFocus(); + QPushButton* dumpBtn = new QPushButton( tr( "BUT_DUMP_MESH" ), this ); + dumpBtn->setAutoDefault( true ); QPushButton* helpBtn = new QPushButton( tr( "SMESH_BUT_HELP" ), this ); helpBtn->setAutoDefault( true ); @@ -1946,24 +4009,21 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) btnLayout->setMargin( 0 ); btnLayout->addWidget( okBtn ); + btnLayout->addWidget( dumpBtn ); btnLayout->addStretch( 10 ); btnLayout->addWidget( helpBtn ); QVBoxLayout* l = new QVBoxLayout ( this ); - l->setMargin( MARGIN ); + l->setMargin( 0 ); l->setSpacing( SPACING ); - l->addWidget( myTabWidget ); + l->addWidget( myCtrlInfo ); l->addLayout( btnLayout ); - myTabWidget->setCurrentIndex( qMax( (int)BaseInfo, qMin( (int)ElemInfo, page ) ) ); - - connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); - connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); - connect( myTabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( updateSelection() ) ); - connect( myMode, SIGNAL( buttonClicked( int ) ), this, SLOT( modeChanged() ) ); - connect( myID, SIGNAL( textEdited( QString ) ), this, SLOT( idChanged() ) ); - connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); - connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); + connect( okBtn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + connect( dumpBtn, SIGNAL( clicked() ), this, SLOT( dump() ) ); + connect( helpBtn, SIGNAL( clicked() ), this, SLOT( help() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalDeactivateActiveDialog() ), this, SLOT( deactivate() ) ); + connect( SMESHGUI::GetSMESHGUI(), SIGNAL( SignalCloseAllDialogs() ), this, SLOT( reject() ) ); updateSelection(); } @@ -1971,205 +4031,104 @@ SMESHGUI_MeshInfoDlg::SMESHGUI_MeshInfoDlg( QWidget* parent, int page ) /*! \brief Destructor */ -SMESHGUI_MeshInfoDlg::~SMESHGUI_MeshInfoDlg() +SMESHGUI_CtrlInfoDlg::~SMESHGUI_CtrlInfoDlg() { } /*! - \brief Show mesh information - \param IO interactive object + \brief Show mesh quality information on given object. + \param io Interactive object. */ -void SMESHGUI_MeshInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& IO ) -{ - SMESH::SMESH_IDSource_var obj = SMESH::IObjectToInterface( IO ); - if ( !CORBA::is_nil( obj ) ) { - myBaseInfo->showInfo( obj ); - myAddInfo->showInfo( obj ); - - myActor = SMESH::FindActorByEntry( IO->getEntry() ); - SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); - QString ID; - int nb = 0; - if ( myActor && selector ) { - nb = myMode->checkedId() == NodeMode ? - SMESH::GetNameOfSelectedElements( selector, IO, ID ) : - SMESH::GetNameOfSelectedNodes( selector, IO, ID ); - } - myElemInfo->setSource( myActor ) ; - if ( nb > 0 ) { - myID->setText( ID.trimmed() ); - QSet ids; - QStringList idTxt = ID.split( " ", QString::SkipEmptyParts ); - foreach ( ID, idTxt ) - ids << ID.trimmed().toLong(); - myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode ); - } - else { - myID->clear(); - myElemInfo->clear(); - } - } +void SMESHGUI_CtrlInfoDlg::showInfo( const Handle(SALOME_InteractiveObject)& io ) +{ + if ( !io.IsNull() ) + showInfo( SMESH::SelectionProxy( io ) ); } /*! - \brief Perform clean-up actions on the dialog box closing. + \brief Show mesh quality information on given object. + \param proxy Selection proxy. */ -void SMESHGUI_MeshInfoDlg::reject() +void SMESHGUI_CtrlInfoDlg::showInfo( const SMESH::SelectionProxy& proxy ) { - LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); - selMgr->clearFilters(); - SMESH::SetPointRepresentation( false ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) - aViewWindow->SetSelectionMode( ActorSelection ); - QDialog::reject(); + SUIT_OverrideCursor wc; + + if ( !proxy ) + return; + + myProxy = proxy; + myCtrlInfo->showInfo( proxy ); } /*! - \brief Process keyboard event - \param e key press event + \brief Show mesh information */ -void SMESHGUI_MeshInfoDlg::keyPressEvent( QKeyEvent* e ) +void SMESHGUI_CtrlInfoDlg::updateInfo() { - QDialog::keyPressEvent( e ); - if ( !e->isAccepted() && e->key() == Qt::Key_F1 ) { - e->accept(); - help(); - } + SALOME_ListIO selected; + SMESHGUI::selectionMgr()->selectedObjects( selected ); + + if ( selected.Extent() == 1 ) + showInfo( selected.First() ); + else + showInfo( myProxy ); } /*! - \brief Reactivate dialog box, when mouse pointer goes into it. + \brief Perform clean-up actions on the dialog box closing. */ -void SMESHGUI_MeshInfoDlg::enterEvent( QEvent* ) +void SMESHGUI_CtrlInfoDlg::reject() { - //activate(); + SMESH::SetPointRepresentation( false ); + QDialog::reject(); } /*! \brief Setup selection mode depending on the current dialog box state. */ -void SMESHGUI_MeshInfoDlg::updateSelection() +void SMESHGUI_CtrlInfoDlg::updateSelection() { LightApp_SelectionMgr* selMgr = SMESHGUI::selectionMgr(); - disconnect( selMgr, 0, this, 0 ); - selMgr->clearFilters(); - - if ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) { - SMESH::SetPointRepresentation( false ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) - aViewWindow->SetSelectionMode( ActorSelection ); - } - else { - if ( myMode->checkedId() == NodeMode ) { - SMESH::SetPointRepresentation( true ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) - aViewWindow->SetSelectionMode( NodeSelection ); - } - else { - SMESH::SetPointRepresentation( false ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) - aViewWindow->SetSelectionMode( CellSelection ); - } - } - - QString oldID = myID->text().trimmed(); - SMESH_Actor* oldActor = myActor; - myID->clear(); - + SMESH::SetPointRepresentation( false ); connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); - updateInfo(); - - if ( oldActor == myActor && myActor && !oldID.isEmpty() ) { - myID->setText( oldID ); - idChanged(); - } -} - -/*! - \brief Show help page -*/ -void SMESHGUI_MeshInfoDlg::help() -{ - SMESH::ShowHelpFile( ( myTabWidget->currentIndex() == BaseInfo || myTabWidget->currentIndex() == AddInfo ) ? - "mesh_infos_page.html#advanced_mesh_infos_anchor" : - "mesh_infos_page.html#mesh_element_info_anchor" ); -} - -/*! - \brief Show mesh information -*/ -void SMESHGUI_MeshInfoDlg::updateInfo() -{ - SUIT_OverrideCursor wc; - - SALOME_ListIO selected; - SMESHGUI::selectionMgr()->selectedObjects( selected ); - - if ( selected.Extent() == 1 ) { - Handle(SALOME_InteractiveObject) IO = selected.First(); - showInfo( IO ); - } -// else { -// myBaseInfo->clear(); -// myElemInfo->clear(); -// myAddInfo->clear(); -// } -} - -/*! - \brief Activate dialog box -*/ -void SMESHGUI_MeshInfoDlg::activate() -{ - SMESHGUI::GetSMESHGUI()->EmitSignalDeactivateDialog(); - SMESHGUI::GetSMESHGUI()->SetActiveDialogBox( this ); - myTabWidget->setEnabled( true ); - updateSelection(); + updateInfo(); } /*! - \brief Deactivate dialog box + \brief Deactivate dialog box. */ -void SMESHGUI_MeshInfoDlg::deactivate() +void SMESHGUI_CtrlInfoDlg::deactivate() { - myTabWidget->setEnabled( false ); disconnect( SMESHGUI::selectionMgr(), SIGNAL( currentSelectionChanged() ), this, SLOT( updateInfo() ) ); } /*! - \brief Called when users switches between node / element modes. + \brief Dump information to file. */ -void SMESHGUI_MeshInfoDlg::modeChanged() +void SMESHGUI_CtrlInfoDlg::dump() { - myID->clear(); - updateSelection(); + DumpFileDlg fd( this, false ); + fd.setWindowTitle( tr( "SAVE_INFO" ) ); + fd.setNameFilters( QStringList() << tr( "TEXT_FILES" ) ); + if ( fd.exec() == QDialog::Accepted ) + { + QString fileName = fd.selectedFile(); + if ( !fileName.isEmpty() ) { + QFile file( fileName ); + if ( !file.open( QIODevice::WriteOnly | QIODevice::Text ) ) + return; + + QTextStream out( &file ); + myCtrlInfo->saveInfo( out ); + } + } } /*! - \brief Caled when users prints mesh element ID in the corresponding field. + \brief Show documentation on dialog. */ -void SMESHGUI_MeshInfoDlg::idChanged() +void SMESHGUI_CtrlInfoDlg::help() { - SVTK_Selector* selector = SMESH::GetViewWindow()->GetSelector(); - if ( myActor && selector ) { - Handle(SALOME_InteractiveObject) IO = myActor->getIO(); - TColStd_MapOfInteger ID; - QSet ids; - QStringList idTxt = myID->text().split( " ", QString::SkipEmptyParts ); - foreach ( QString tid, idTxt ) { - long id = tid.trimmed().toLong(); - const SMDS_MeshElement* e = myMode->checkedId() == ElemMode ? - myActor->GetObject()->GetMesh()->FindElement( id ) : - myActor->GetObject()->GetMesh()->FindNode( id ); - if ( e ) { - ID.Add( id ); - ids << id; - } - } - selector->AddOrRemoveIndex( IO, ID, false ); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow() ) - aViewWindow->highlight( IO, true, true ); - myElemInfo->showInfo( ids, myMode->checkedId() == ElemMode ); - } + SMESH::ShowHelpFile( "mesh_infos.html#mesh-quality-info-anchor" ); }