// Copyright (C) 2007-2012 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 // // 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. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // File : StdMeshersGUI_DistrTable.cxx // Author : Open CASCADE S.A.S. // SMESH includes // #include "StdMeshersGUI_DistrTable.h" #include // Qt incldues #include #include #include #include #include #include #define SPACING 6 /*! \brief Sort list of points by ascending order. \internal */ static void sortData( QList& d ) { typedef QPair Pair; QList pairs; for ( int i = 0; i < d.count() / 2; i++ ) pairs.append( Pair( d[i*2], d[i*2+1] ) ); qSort( pairs ); d.clear(); Pair p; double prevX = 0.0, prevY = 0.0; d.append( prevX ); d.append( pairs.count() > 0 ? pairs[0].second : prevY ); foreach( p, pairs ) { if ( p.first > prevX ) { d.append( p.first ); d.append( p.second ); prevY = p.second; } prevX = p.first; } if ( prevX < 1.0 ) { d.append( 1.0 ); d.append( prevY ); } } /*! \class StdMeshersGUI_DistrTableFrame::SpinBoxDelegate \brief Custom item delegate (uses double spin box to edit table item) \internal */ class StdMeshersGUI_DistrTableFrame::SpinBoxDelegate : public QItemDelegate { public: SpinBoxDelegate( StdMeshersGUI_DistrTableFrame::Table* ); ~SpinBoxDelegate(); QWidget* createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; void setEditorData( QWidget*, const QModelIndex&) const; void setModelData( QWidget*, QAbstractItemModel*, const QModelIndex& ) const; void updateEditorGeometry( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const; private: StdMeshersGUI_DistrTableFrame::Table* myTable; }; /*! \class StdMeshersGUI_DistrTableFrame::Table \brief Table function widget \internal */ class StdMeshersGUI_DistrTableFrame::Table : public QTableWidget { private: struct EditorData { int r, c; SMESHGUI_SpinBox* sb; EditorData() { reset(); } void reset() { r = -1; c = -1; sb = 0; } }; public: Table( QWidget*, int = 2 ); ~Table(); QList data(); void setData( const QList& ); double value( int, int ) const; void setValue( int, int, double ); double argMinimum( int ) const; double argMaximum( int ) const; double argStep( int ) const; double funcMinimum( int ) const; double funcMaximum( int ) const; double funcStep( int ) const; void setFuncMinValue( double ); QSize sizeHint() const; void addRow(); void deleteRow(); void setEditor( int, int, SMESHGUI_SpinBox* ); protected: void closeEditor( QWidget*, QAbstractItemDelegate::EndEditHint ); private: void setUpRows( bool = false ); QSize cachedSizeHint() const; void setCachedSizeHint( const QSize& ) const; QList selectedRows(); private: double myFuncMin; QSize myCachedSizeHint; EditorData myEditorData; }; // --- // StdMeshersGUI_DistrTableFrame::SpinBoxDelegate implementation // --- StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: SpinBoxDelegate( StdMeshersGUI_DistrTableFrame::Table* parent ) : QItemDelegate( parent ), myTable( parent ) { } StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: ~SpinBoxDelegate() { } QWidget* StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: createEditor( QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& index ) const { SMESHGUI_SpinBox* sb = new SMESHGUI_SpinBox( parent ); sb->setAcceptNames(false); // No Notebook variables allowed double aMin = index.column() == StdMeshersGUI_DistrTableFrame::ArgColumn ? myTable->argMinimum( index.row() ) : myTable->funcMinimum( index.row() ); double aMax = index.column() == StdMeshersGUI_DistrTableFrame::ArgColumn ? myTable->argMaximum( index.row() ) : myTable->funcMaximum( index.row() ); double aStep = index.column() == StdMeshersGUI_DistrTableFrame::ArgColumn ? myTable->argStep( index.row() ) : myTable->funcStep( index.row() ); sb->RangeStepAndValidator( aMin, aMax, aStep, "parametric_precision" ); sb->setFrame(false); myTable->setEditor( index.row(), index.column(), sb ); return sb; } void StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: setEditorData( QWidget* editor, const QModelIndex& index ) const { QString value = index.model()->data(index, Qt::DisplayRole).toString(); SMESHGUI_SpinBox* sb = static_cast(editor); bool bOk = false; double v = value.toDouble( &bOk ); if ( !bOk ) v = sb->minimum(); sb->setValue( v ); } void StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const { SMESHGUI_SpinBox* sb = static_cast(editor); model->setData( index, QString::number( sb->value() ), Qt::DisplayRole ); } void StdMeshersGUI_DistrTableFrame::SpinBoxDelegate:: updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/ ) const { editor->setGeometry( option.rect ); } // --- // StdMeshersGUI_DistrTableFrame::Table implementation // --- StdMeshersGUI_DistrTableFrame::Table:: Table( QWidget* parent, int rows ) : QTableWidget( parent ), myFuncMin( 0.0 ) { setItemDelegate( new StdMeshersGUI_DistrTableFrame::SpinBoxDelegate( this ) ); setColumnCount( 2 ); QStringList labs; labs << "t" << "f(t)"; setHorizontalHeaderLabels( labs ); this->horizontalHeader()->setStretchLastSection(true); this->horizontalHeader()->setDefaultSectionSize(60); while( rows-- ) addRow(); setUpRows( true ); } void StdMeshersGUI_DistrTableFrame::Table:: setEditor( int r, int c, SMESHGUI_SpinBox* sb ) { myEditorData.r = r; myEditorData.c = c; myEditorData.sb = sb; } StdMeshersGUI_DistrTableFrame::Table:: ~Table() { } QList StdMeshersGUI_DistrTableFrame::Table:: data() { closePersistentEditor( currentItem() ); QList d; for ( int r = 0; r < rowCount(); r++ ) { d.append( value( r, ArgColumn ) ); d.append( value( r, FuncColumn ) ); } return d; } void StdMeshersGUI_DistrTableFrame::Table:: setData( const QList& d ) { closePersistentEditor( currentItem() ); setRowCount( d.count() / 2 ); for ( int r = 0; r < rowCount(); r++ ) { setValue( r, ArgColumn, d[r*2] ); setValue( r, FuncColumn, d[r*2+1] ); } } double StdMeshersGUI_DistrTableFrame::Table:: value( int r, int c ) const { if ( r < 0 || r > rowCount() || c < 0 || c > columnCount() || !item( r, c ) ) return 0.0; return item( r, c )->text().toDouble(); } void StdMeshersGUI_DistrTableFrame::Table:: setValue( int r, int c, double v ) { if ( r < 0 || r > rowCount() || c < 0 || c > columnCount() ) return; if ( c == FuncColumn && v < funcMinimum( r ) ) v = funcMinimum( r ); // correct func value according to the valid min value if ( c == FuncColumn && v > funcMaximum( r ) ) v = funcMaximum( r ); // correct func value according to the valid max value else if ( r == ArgColumn && v < argMinimum( r ) ) v = argMinimum( r ); // correct arg value according to the valid min value else if ( r == ArgColumn && v > argMaximum( r ) ) v = argMaximum( r ); // correct arg value according to the valid max value if ( !item( r, c ) ) setItem( r, c, new QTableWidgetItem ); item( r, c )->setText( QString::number( v ) ); } double StdMeshersGUI_DistrTableFrame::Table:: argMinimum( int r ) const { // for the first row the minimum value is always 0.0 // for the other rows the minumum value is the above row's value double val = 0.0; if ( r > 0 && r < rowCount() ) val = value( r-1, ArgColumn ); return val; } double StdMeshersGUI_DistrTableFrame::Table:: argMaximum( int r ) const { // for the last row the maximum value is always 1.0 // for the other rows the maxumum value is the below row's value double val = 1.0; if ( r >= 0 && r < rowCount()-1 ) { val = value( r+1, ArgColumn ); } return val; } double StdMeshersGUI_DistrTableFrame::Table:: argStep( int /*r*/ ) const { // correct this to provide more smart behaviour if needed return 0.1; } double StdMeshersGUI_DistrTableFrame::Table:: funcMinimum( int /*r*/ ) const { // correct this to provide more smart behaviour if needed return myFuncMin; } double StdMeshersGUI_DistrTableFrame::Table:: funcMaximum( int /*r*/ ) const { // correct this to provide more smart behaviour if needed return 1e20; } double StdMeshersGUI_DistrTableFrame::Table:: funcStep( int /*r*/ ) const { // correct this to provide more smart behaviour if needed return 1.0; } void StdMeshersGUI_DistrTableFrame::Table:: setFuncMinValue( double val ) { myFuncMin = val; QTableWidgetItem* i = currentItem(); if ( i && i->row() == myEditorData.r && i->column() == myEditorData.c && i->column() == FuncColumn && myEditorData.sb ) { myEditorData.sb->setMinimum( myFuncMin ); } else { closePersistentEditor( currentItem() ); } for ( int r = 0; r < rowCount(); r++ ) { double v = item( r, FuncColumn )->text().toDouble(); if ( v < myFuncMin ) item( r, FuncColumn )->setText( QString::number( myFuncMin ) ); } } QSize StdMeshersGUI_DistrTableFrame::Table:: sizeHint() const { if( cachedSizeHint().isValid() ) return cachedSizeHint(); return QTableWidget::sizeHint(); // QSize sh = QTableWidget::sizeHint(); // if( sh.width() < 400 ) // sh.setWidth( 400 ); // if( sh.height() < 200 ) // sh.setHeight( 200 ); // // setCachedSizeHint( sh ); // return sh; } void StdMeshersGUI_DistrTableFrame::Table:: addRow() { int r = currentRow() >= 0 ? currentRow() : ( rowCount() > 0 ? rowCount() - 1 : 0 ); insertRow( r ); double argMin = argMinimum( r ); double funcMin = funcMinimum( r ); setItem( r, ArgColumn, new QTableWidgetItem( QString::number( argMin ) ) ); setItem( r, FuncColumn, new QTableWidgetItem( QString::number( funcMin ) ) ); } void StdMeshersGUI_DistrTableFrame::Table:: deleteRow() { QList selRows = selectedRows(); for ( int r = selRows.count()-1; r >= 0; r-- ) removeRow( r ); } void StdMeshersGUI_DistrTableFrame::Table:: closeEditor( QWidget* editor, QAbstractItemDelegate::EndEditHint hint ) { myEditorData.reset(); QTableWidget::closeEditor( editor, hint ); } void StdMeshersGUI_DistrTableFrame::Table:: setUpRows( bool autoset ) { if ( rowCount() < 1 ) return; if ( autoset ) { double s = argMaximum( rowCount()-1 ) / rowCount(); for ( int r = 0; r < rowCount()-1; r++ ) setValue( r, ArgColumn, r * s ); setValue( rowCount()-1, ArgColumn, argMaximum( rowCount()-1 ) ); } else { // TODO } } QSize StdMeshersGUI_DistrTableFrame::Table:: cachedSizeHint() const { return myCachedSizeHint; } void StdMeshersGUI_DistrTableFrame::Table:: setCachedSizeHint( const QSize& s ) const { Table* that = const_cast( this ); that->myCachedSizeHint = s; } QList StdMeshersGUI_DistrTableFrame::Table:: selectedRows() { QList l; QList selItems = selectedItems(); QTableWidgetItem* i; foreach( i, selItems ) if ( !l.contains( i->row() ) ) l.append( i->row() ); qSort( l ); return l; } /*! \class StdMeshersGUI_DistrTableFrame \brief Distribution table widget */ StdMeshersGUI_DistrTableFrame:: StdMeshersGUI_DistrTableFrame( QWidget* parent ) : QWidget( parent ) { QGridLayout* main = new QGridLayout( this ); main->setMargin( 0 ); main->setSpacing( 0 ); // --- myTable = new Table( this ); connect( myTable, SIGNAL( valueChanged( int, int ) ), this, SIGNAL( valueChanged( int, int ) ) ); myButtons[ InsertRowBtn ] = new QPushButton( tr( "SMESH_INSERT_ROW" ), this ); myButtons[ RemoveRowBtn ] = new QPushButton( tr( "SMESH_REMOVE_ROW" ), this ); // --- main->addWidget( myTable , 0, 0, 1, 3); main->addWidget( myButtons[ InsertRowBtn ] , 1, 0); main->addWidget( myButtons[ RemoveRowBtn ] , 1, 1); main->setColumnStretch(2, 1); main->setSpacing( SPACING ); // --- connect( myButtons[ InsertRowBtn ], SIGNAL( clicked() ), this, SLOT( onInsert() ) ); connect( myButtons[ RemoveRowBtn ], SIGNAL( clicked() ), this, SLOT( onRemove() ) ); connect( myTable, SIGNAL( currentCellChanged( int, int, int, int ) ), this, SIGNAL( currentChanged( int, int ) ) ); connect( myTable, SIGNAL( cellChanged( int, int ) ), this, SIGNAL( valueChanged( int, int ) ) ); } StdMeshersGUI_DistrTableFrame:: ~StdMeshersGUI_DistrTableFrame() { } void StdMeshersGUI_DistrTableFrame:: showButton( const TableButton b, const bool on ) { if ( button( b ) ) button( b )->setVisible( on ); } bool StdMeshersGUI_DistrTableFrame:: isButtonShown( const TableButton b ) const { return button( b ) ? button( b )->isVisible() : false; } void StdMeshersGUI_DistrTableFrame:: data( DataArray& array ) const { QList d = myTable->data(); sortData( d ); array.length( d.count() ); for ( int i = 0; i < d.count(); i++ ) array[i] = d[i]; } void StdMeshersGUI_DistrTableFrame:: setData( const DataArray& array ) { QList d; for ( int i = 0; i < array.length(); i++ ) d.append( array[i] ); sortData( d ); myTable->setData( d ); } void StdMeshersGUI_DistrTableFrame:: setFuncMinValue( double v ) { myTable->setFuncMinValue( v ); } QPushButton* StdMeshersGUI_DistrTableFrame:: button( const TableButton b ) const { return myButtons.contains( b ) ? myButtons[ b ] : 0; } void StdMeshersGUI_DistrTableFrame:: onInsert() { myTable->addRow(); } void StdMeshersGUI_DistrTableFrame:: onRemove() { myTable->deleteRow(); }