Salome HOME
FixedPoints hypothesis: fix problem with values close to 0.0 and 1.0
[modules/smesh.git] / src / StdMeshersGUI / StdMeshersGUI_FixedPointsParamWdg.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File   : StdMeshersGUI_FixedPointsParamWdg.cxx
23 // Author : Open CASCADE S.A.S.
24 // SMESH includes
25 //
26 #include "StdMeshersGUI_FixedPointsParamWdg.h"
27
28 #include <QtxIntSpinBox.h>
29 #include <QtxDoubleSpinBox.h>
30
31 // Qt includes
32 #include <QPushButton>
33 #include <QIntValidator>
34 #include <QGridLayout>
35 #include <QListWidget>
36 #include <QListWidgetItem>
37 #include <QItemDelegate>
38 #include <QTreeWidget>
39 #include <QTreeWidgetItem>
40 #include <QCheckBox>
41 #include <QLineEdit>
42 #include <QItemDelegate>
43 #include <QKeyEvent>
44
45 #define SPACING 6
46 #define MARGIN 0
47 #define SAME_TEXT "-/-"
48
49 #define TOLERANCE 1e-7
50 #define EQUAL_DBL(a,b) (fabs(a-b)<TOLERANCE)
51 #define LT_DBL(a,b) ((a<b)&&!EQUAL_DBL(a,b))
52 #define GT_DBL(a,b) ((a>b)&&!EQUAL_DBL(a,b))
53
54 /*
55  * class : Tree Widget Item Delegate
56  * purpose  : Custom item delegate
57  */
58
59 class StdMeshersGUI_FixedPointsParamWdg::LineDelegate : public QItemDelegate
60 {
61 public:
62   LineDelegate( QTreeWidget* );
63   ~LineDelegate() {}
64
65   QWidget*     createEditor( QWidget*, const QStyleOptionViewItem&, const QModelIndex& ) const;
66   void         setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const;
67
68 private:
69   QTreeWidget* myTreeWidget;
70 };
71
72 StdMeshersGUI_FixedPointsParamWdg::LineDelegate::LineDelegate( QTreeWidget* parent )
73   : QItemDelegate( parent ),
74     myTreeWidget( parent )
75 {
76 }
77
78 QWidget* StdMeshersGUI_FixedPointsParamWdg::LineDelegate::createEditor( QWidget* parent,
79                                                                         const QStyleOptionViewItem& option,
80                                                                         const QModelIndex& index ) const
81 {
82   QWidget* w = 0;
83   if ( (index.column() == 1 ) ) {
84     QtxIntSpinBox* sb = new QtxIntSpinBox( parent );
85     sb->setFrame( false );
86     sb->setRange( 1, 999);
87     w = sb;
88   }
89
90   return w;
91 }
92
93 void StdMeshersGUI_FixedPointsParamWdg::LineDelegate::setModelData( QWidget* editor, 
94                                                                     QAbstractItemModel* model, 
95                                                                     const QModelIndex& index ) const
96 {
97   model->setData( index, qobject_cast<QtxIntSpinBox*>( editor )->value(), Qt::EditRole );
98   model->setData( index, qobject_cast<QtxIntSpinBox*>( editor )->value(), Qt::UserRole );
99 }
100
101 //================================================================================
102 /*!
103  *  Constructor
104  */
105 //================================================================================
106
107 StdMeshersGUI_FixedPointsParamWdg
108 ::StdMeshersGUI_FixedPointsParamWdg( QWidget * parent ): 
109   QWidget( parent )
110 {
111   QGridLayout* edgesLayout = new QGridLayout( this );
112   edgesLayout->setMargin( MARGIN );
113   edgesLayout->setSpacing( SPACING );
114   
115   myListWidget   = new QListWidget( this );
116   myTreeWidget   = new QTreeWidget( this );
117   mySpinBox      = new QtxDoubleSpinBox( this );
118   myAddButton    = new QPushButton( tr( "SMESH_BUT_ADD" ),    this );
119   myRemoveButton = new QPushButton( tr( "SMESH_BUT_REMOVE" ), this );      
120   mySameValues   = new QCheckBox( tr("SMESH_SAME_NB_SEGMENTS"), this);
121
122   myListWidget->setSelectionMode( QListWidget::ExtendedSelection );
123
124   myTreeWidget->setColumnCount(2);
125   myTreeWidget->setHeaderLabels( QStringList() << tr( "SMESH_RANGE" ) << tr( "SMESH_NB_SEGMENTS" ) );
126   myTreeWidget->setColumnWidth( 1, 40 );
127   myTreeWidget->setColumnWidth( 2, 30 );
128   myTreeWidget->setItemDelegate( new LineDelegate( myTreeWidget ) );
129
130   edgesLayout->addWidget(myListWidget,   0, 0, 4, 1);
131   edgesLayout->addWidget(mySpinBox,      0, 1);
132   edgesLayout->addWidget(myAddButton,    1, 1);
133   edgesLayout->addWidget(myRemoveButton, 2, 1);
134   edgesLayout->addWidget(myTreeWidget,   0, 2, 4, 1);
135   edgesLayout->addWidget(mySameValues,   4, 0, 1, 3);
136   edgesLayout->setRowStretch( 3, 5 );
137   edgesLayout->setColumnStretch(0, 1);
138   edgesLayout->setColumnStretch(1, 0);
139   edgesLayout->setColumnStretch(2, 2);
140
141   myListWidget->setMinimumWidth( 80 );
142   myTreeWidget->setMinimumWidth( 200 );
143
144   mySpinBox->setRange( 0, 1 );
145   mySpinBox->setSingleStep( 0.1 );
146   mySpinBox->setDecimals( 4 );
147   mySpinBox->setPrecision( 4 );
148   myListWidget->setMinimumWidth( 70 );
149
150   connect( myAddButton,    SIGNAL( clicked() ),              SLOT( onAdd() ) );
151   connect( myRemoveButton, SIGNAL( clicked() ),              SLOT( onRemove() ) );
152   connect( mySameValues,   SIGNAL( stateChanged( int ) ),    SLOT( onCheckBoxChanged() ) );
153   connect( mySpinBox,      SIGNAL( valueChanged( double ) ), SLOT( updateState() ) );
154   connect( myListWidget,   SIGNAL( itemSelectionChanged() ), SLOT( updateState() ) );
155   myListWidget->installEventFilter( this );
156
157   clear();
158 }
159
160 //================================================================================
161 /*!
162  *  Destructor
163  */
164 //================================================================================
165
166 StdMeshersGUI_FixedPointsParamWdg::~StdMeshersGUI_FixedPointsParamWdg()
167 {
168 }
169
170 //================================================================================
171 /*!
172  *  Event filter
173  */
174 //================================================================================
175 bool StdMeshersGUI_FixedPointsParamWdg::eventFilter( QObject* o, QEvent* e )
176 {
177   if ( o == myListWidget && e->type() == QEvent::KeyPress ) {
178     QKeyEvent* ke = (QKeyEvent*)e;
179     if ( ke->key() == Qt::Key_Delete )
180       removePoints();
181   }
182   return QWidget::eventFilter( o, e );
183 }
184
185 //================================================================================
186 /*!
187  *  Clear widget
188  */
189 //================================================================================
190 void StdMeshersGUI_FixedPointsParamWdg::clear()
191 {
192   myTreeWidget->clear();
193   myListWidget->clear();
194   myTreeWidget->addTopLevelItem( newTreeItem( 0, 1 ) );
195   mySpinBox->setValue( 0. );
196   onCheckBoxChanged();
197   updateState();
198 }
199
200 //=================================================================================
201 // function : onAdd()
202 // purpose  : Called when Add Button Clicked
203 //=================================================================================
204 void StdMeshersGUI_FixedPointsParamWdg::onAdd()
205 {
206   addPoint( mySpinBox->value() );
207 }
208          
209 //=================================================================================
210 // function : onRemove()
211 // purpose  : Called when Remove Button Clicked
212 //=================================================================================
213 void StdMeshersGUI_FixedPointsParamWdg::onRemove()
214 {
215   removePoints();
216 }
217
218 //=================================================================================
219 // function : newTreeItem()
220 // purpose  : Called to create TreeItem
221 //=================================================================================
222
223 QTreeWidgetItem* StdMeshersGUI_FixedPointsParamWdg::newTreeItem( double v1, double v2 )
224 {
225   QTreeWidgetItem* anItem = new QTreeWidgetItem();
226   anItem->setText( 0, treeItemText( v1, v2 ) );
227   anItem->setText( 1, QString::number( 1 ) );
228   anItem->setData( 1, Qt::UserRole, 1 );
229   return anItem;
230 }
231
232 //=================================================================================
233 // function : newListItem()
234 // purpose  : Called to create ListItem
235 //=================================================================================
236
237 QListWidgetItem* StdMeshersGUI_FixedPointsParamWdg::newListItem( double v )
238 {
239   QListWidgetItem* anItem = new QListWidgetItem( QString::number( v ) );
240   anItem->setData( Qt::UserRole, v );
241   return anItem;
242 }
243
244 //=================================================================================
245 // function : itemText()
246 // purpose  : Called to convert Values to Text
247 //=================================================================================
248
249 QString StdMeshersGUI_FixedPointsParamWdg::treeItemText( double v1, double v2 )
250 {
251   return QString( "%1 - %2" ).arg( v1 ).arg( v2 );
252 }
253
254 //=================================================================================
255 // function : addPoint()
256 // purpose  : Called to Add new Point
257 //=================================================================================
258 void StdMeshersGUI_FixedPointsParamWdg::addPoint( double v)
259 {
260   if ( GT_DBL(v, 0.0) && LT_DBL(v, 1.0)) {
261     bool toInsert = true;
262     int idx = myTreeWidget->topLevelItemCount()-1;
263     for ( int i = 0 ; i < myListWidget->count(); i++ ) {
264       double lv = point( i );
265       if ( EQUAL_DBL(lv, v) ) { toInsert = false; break; }
266       else if ( GT_DBL(lv, v) ) {
267         idx = i; break;
268       }
269     }
270     if ( toInsert ) {
271       double v1 = idx == 0 ? 0 : point( idx-1 );
272       double v2 = idx == myTreeWidget->topLevelItemCount()-1 ? 1 : point( idx );
273       myTreeWidget->insertTopLevelItem( idx, newTreeItem( v1, v ) );
274       myTreeWidget->topLevelItem( idx+1 )->setText( 0, treeItemText( v, v2 ) );
275       myListWidget->insertItem( idx, newListItem( v ) );
276       onCheckBoxChanged();
277     }
278   }
279   updateState();
280 }
281
282 //=================================================================================
283 // function : removePoints()
284 // purpose  : Called to remove selected points
285 //=================================================================================
286 void StdMeshersGUI_FixedPointsParamWdg::removePoints()
287 {
288   QList<QListWidgetItem*> selItems = myListWidget->selectedItems();
289   QListWidgetItem* item;
290   foreach ( item, selItems ) {
291     int idx = myListWidget->row( item );
292     delete myTreeWidget->topLevelItem( idx );
293     delete item;
294     myTreeWidget->topLevelItem( idx )->setText( 0, treeItemText( idx == 0 ? 0 : point( idx-1 ),
295                                                                  idx > myListWidget->count()-1 ? 1 : point( idx ) ) );
296   }
297   onCheckBoxChanged();
298   updateState();
299 }
300
301 double StdMeshersGUI_FixedPointsParamWdg::point( int idx ) const
302 {
303   return idx >= 0 && idx < myListWidget->count() ? myListWidget->item( idx )->data( Qt::UserRole ).toDouble() : 0.;
304 }
305
306 void StdMeshersGUI_FixedPointsParamWdg::setNbSegments( int idx, int val )
307 {
308   if ( idx >= 0 && idx < myTreeWidget->topLevelItemCount() ) {
309     myTreeWidget->topLevelItem( idx )->setData( 1, Qt::UserRole, val );
310     myTreeWidget->topLevelItem( idx )->setText( 1, idx > 0 && mySameValues->isChecked() ? QString( SAME_TEXT ) : QString::number( val ) );
311   }
312 }
313
314 int StdMeshersGUI_FixedPointsParamWdg::nbSegments( int idx ) const
315 {
316   return idx >= 0 && idx < myTreeWidget->topLevelItemCount() ? myTreeWidget->topLevelItem( idx )->data( 1, Qt::UserRole ).toInt() : 1;
317 }
318
319 //=================================================================================
320 // function : onCheckBoxChanged()
321 // purpose  : Called when Check Box Clicked
322 //=================================================================================
323 void StdMeshersGUI_FixedPointsParamWdg::onCheckBoxChanged()
324 {
325   for ( int i = 0; i < myTreeWidget->topLevelItemCount(); i++ ) {
326     QTreeWidgetItem* anItem = myTreeWidget->topLevelItem(i);
327     setNbSegments( i, nbSegments( i ) );
328     anItem->setFlags( mySameValues->isChecked() && i > 0 ? anItem->flags() & ~Qt::ItemIsEditable : anItem->flags() | Qt::ItemIsEditable );
329   }
330 }
331
332 //=================================================================================
333 // function : updateState()
334 // purpose  : Update widgets state
335 //=================================================================================
336 void StdMeshersGUI_FixedPointsParamWdg::updateState()
337 {
338   double v = mySpinBox->value();
339   myAddButton->setEnabled( GT_DBL(v, 0.0) && LT_DBL(v, 1.0) );
340   myRemoveButton->setEnabled( myListWidget->selectedItems().count() > 0 );
341 }
342
343 //=================================================================================
344 // function : GetListOfPoints
345 // purpose  : Called to get the list of Edges IDs
346 //=================================================================================
347 SMESH::double_array_var StdMeshersGUI_FixedPointsParamWdg::GetListOfPoints()
348 {
349   SMESH::double_array_var anArray = new SMESH::double_array;
350   int size = myListWidget->count();
351   anArray->length( size );
352   for (int i = 0; i < size; i++) {
353     anArray[i] = point(i);
354   }
355   return anArray;
356 }
357
358 //=================================================================================
359 // function : SetListOfPoints
360 // purpose  : Called to set the list of Points
361 //=================================================================================
362 void StdMeshersGUI_FixedPointsParamWdg::SetListOfPoints( SMESH::double_array_var thePoints)
363 {
364   clear();
365   for ( int i = 0; i < thePoints->length(); i++ ) {
366     addPoint( thePoints[ i ] );
367   }
368 }
369
370 //=================================================================================
371 // function : GetListOfSegments
372 // purpose  : Called to get the list Number of Segments
373 //=================================================================================
374 SMESH::long_array_var StdMeshersGUI_FixedPointsParamWdg::GetListOfSegments()
375 {
376   SMESH::long_array_var anArray = new SMESH::long_array;
377   int size = mySameValues->isChecked() ? 1 : myTreeWidget->topLevelItemCount();
378   anArray->length( size );
379   for (int i = 0; i < size; i++) {
380     anArray[i] = nbSegments( i );
381   }
382   return anArray;
383 }
384
385 //=================================================================================
386 // function : SetListOfPoints
387 // purpose  : Called to set the list of Points
388 //=================================================================================
389 void StdMeshersGUI_FixedPointsParamWdg::SetListOfSegments( SMESH::long_array_var theSegments)
390 {
391   if ( myListWidget->count() > 0 && theSegments->length() == 1)
392     mySameValues->setChecked(true);
393   for ( int i = 0; i < theSegments->length(); i++ ) {
394     setNbSegments( i, theSegments[i] );
395   }
396 }