]> SALOME platform Git repositories - modules/gui.git/blob - src/Qtx/QtxDblSpinBox.cxx
Salome HOME
b10c28bd60a50f80c43cf296da104ecf37aac0e4
[modules/gui.git] / src / Qtx / QtxDblSpinBox.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 // File:      QtxDblSpinBox.cxx
20 // Author:    Sergey TELKOV
21
22 #include "QtxDblSpinBox.h"
23
24 #include <qlineedit.h>
25 #include <qvalidator.h>
26 #include <qapplication.h>
27
28 #include <float.h>
29
30 /*
31         Class: QtxDblSpinBox::Validator [internal]
32         Descr: Validator for QtxDblSpinBox (getted from Trolltech Qt - SpinBoxValidator)
33 */
34
35 class QtxDblSpinBox::Validator : public QDoubleValidator
36 {
37 public:
38     Validator( QtxDblSpinBox* sb, const char* name )
39         : QDoubleValidator( sb, name ), spinBox( sb ) {}
40
41     virtual State validate( QString& str, int& pos ) const;
42
43 private:
44     QtxDblSpinBox* spinBox;
45 };
46
47 QValidator::State QtxDblSpinBox::Validator::validate( QString& str, int& pos ) const
48 {
49   QString pref = spinBox->prefix();
50   QString suff = spinBox->suffix();
51   uint overhead = pref.length() + suff.length();
52   State state = Invalid;
53
54   if ( overhead == 0 )
55           state = QDoubleValidator::validate( str, pos );
56   else
57         {
58                 if ( str.length() >= overhead && str.startsWith( pref ) &&
59          str.right( suff.length() ) == suff )
60                 {
61                         QString core = str.mid( pref.length(), str.length() - overhead );
62                         int corePos = pos - pref.length();
63                         state = QDoubleValidator::validate( core, corePos );
64                         pos = corePos + pref.length();
65                         str.replace( pref.length(), str.length() - overhead, core );
66                 }
67                 else
68                 {
69                         state = QDoubleValidator::validate( str, pos );
70                         if ( state == Invalid )
71                         {
72                                 QString special = spinBox->specialValueText().stripWhiteSpace();
73                                 QString candidate = str.stripWhiteSpace();
74                                 if ( special.startsWith( candidate ) )
75                                 {
76                                         if ( candidate.length() == special.length() )
77                                                 state = Acceptable;
78                                         else
79                                                 state = Intermediate;
80                                 }
81                         }
82                 }
83   }
84   return state;
85 }
86
87 /*
88         Class: QtxDblSpinBox
89         Descr: Spin box for real numbers.
90 */
91
92 QtxDblSpinBox::QtxDblSpinBox( QWidget* parent, const char* name )
93 : QSpinBox( parent, name ),
94 myCleared( false ),
95 myBlocked( false ),
96 myPrecision( 0 )
97 {
98   myMin = -DBL_MAX;
99   myMax = DBL_MAX;
100   myStep = QRangeControl::lineStep();
101         myValue = 0;
102   setValidator( new Validator( this, "double_spinbox_validator" ) );
103   rangeChange();
104   updateDisplay();
105
106   connect( editor(), SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) );
107 }
108
109 QtxDblSpinBox::QtxDblSpinBox( double min, double max, double step, QWidget* parent, const char* name )
110 : QSpinBox( parent, name ),
111 myMin( min ),
112 myMax( max ),
113 myStep( step ),
114 myCleared( false ),
115 myBlocked( false ),
116 myPrecision( 0 )
117 {
118         myValue = myMin;
119   setValidator( new Validator( this, "double_spinbox_validator" ) );
120   rangeChange();
121   updateDisplay();
122
123   connect( editor(), SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) );
124 }
125
126 QtxDblSpinBox::~QtxDblSpinBox()
127 {
128 }
129
130 double QtxDblSpinBox::minValue() const
131 {
132   return myMin;
133 }
134
135 double QtxDblSpinBox::maxValue() const
136 {
137   return myMax;
138 }
139
140 void QtxDblSpinBox::setMinValue( int min )
141 {
142         setMinValue( (double)min );
143 }
144
145 void QtxDblSpinBox::setMinValue( double min )
146 {
147   if ( myMin != min )
148   {
149     myMin = min;
150     rangeChange();
151   }
152 }
153
154 void QtxDblSpinBox::setMaxValue( int max )
155 {
156         setMaxValue( (double)max );
157 }
158
159 void QtxDblSpinBox::setMaxValue( double max )
160 {
161   if ( myMax != max )
162   {
163     myMax = max;
164     rangeChange();
165   }
166 }
167
168 void QtxDblSpinBox::setRange( int min, int max )
169 {
170         setRange( (double)min, (double)max );
171 }
172
173 void QtxDblSpinBox::setRange( double min, double max )
174 {
175   if ( myMin != min || myMax != max )
176   {
177     myMin = min;
178     myMax = max;
179     rangeChange();
180   }
181 }
182
183 double QtxDblSpinBox::lineStep() const
184 {
185   return myStep;
186 }
187
188 void QtxDblSpinBox::setLineStep( int step )
189 {
190   setLineStep( (double)step );
191 }
192
193 void QtxDblSpinBox::setLineStep( double step )
194 {
195   myStep = step;
196 }
197
198 double QtxDblSpinBox::value() const
199 {
200   QSpinBox::value();
201
202   return myValue;
203 }
204
205 void QtxDblSpinBox::setValue( int val )
206 {
207         setValue( (double)val );
208 }
209
210 void QtxDblSpinBox::setValue( double val )
211 {
212         myCleared = false;
213   double prevVal = myValue;
214   myValue = bound( val );
215   if ( prevVal != myValue )
216     valueChange();
217 }
218
219 void QtxDblSpinBox::stepUp()
220 {
221         interpretText();
222         if ( wrapping() && myValue + myStep > myMax )
223                 setValue( myMin );
224         else
225                 setValue( myValue + myStep );
226 }
227
228 void QtxDblSpinBox::stepDown()
229 {
230         interpretText();
231         if ( wrapping() && myValue - myStep < myMin )
232                 setValue( myMax );
233         else
234                 setValue( myValue - myStep );
235 }
236
237 int QtxDblSpinBox::precision() const
238 {
239         return myPrecision;
240 }
241
242 void QtxDblSpinBox::setPrecision( const int prec )
243 {
244         int newPrec = QMAX( prec, 0 );
245         int oldPrec = QMAX( myPrecision, 0 );
246         myPrecision = prec;
247         if ( newPrec != oldPrec )
248                 updateDisplay();
249 }
250
251 bool QtxDblSpinBox::isCleared() const
252 {
253         return myCleared;
254 }
255
256 void QtxDblSpinBox::setCleared( const bool on )
257 {
258         if ( myCleared == on )
259                 return;
260
261         myCleared = on;
262         updateDisplay();
263 }
264
265 void QtxDblSpinBox::selectAll()
266 {
267 #if QT_VER >= 3
268         QSpinBox::selectAll();
269 #else
270   editor()->selectAll();
271 #endif
272 }
273
274 bool QtxDblSpinBox::eventFilter( QObject* o, QEvent* e )
275 {
276   if ( !myCleared || o != editor() || !editor()->text().stripWhiteSpace().isEmpty() )
277   {
278     bool state = QSpinBox::eventFilter( o, e );
279     if ( e->type() == QEvent::FocusOut && o == editor() )
280       updateDisplay();
281     return state;
282   }
283
284   if ( e->type() == QEvent::FocusOut || e->type() == QEvent::Leave || e->type() == QEvent::Hide )
285     return false;
286
287   if ( e->type() == QEvent::KeyPress &&
288           ( ((QKeyEvent*)e)->key() == Key_Tab || ((QKeyEvent*)e)->key() == Key_BackTab ) )
289   {
290     QApplication::sendEvent( this, e );
291     return true;
292   }
293
294   return QSpinBox::eventFilter( o, e );
295 }
296
297 void QtxDblSpinBox::updateDisplay()
298 {
299   if ( myBlocked )
300     return;
301
302   bool upd = editor()->isUpdatesEnabled();
303   editor()->setUpdatesEnabled( false );
304
305   bool isBlock = myBlocked;
306   myBlocked = true;
307     
308   QString txt = currentValueText();
309     
310   if ( myValue >= myMax )
311     QSpinBox::setValue( QSpinBox::maxValue() );
312   else if ( myValue <= myMin )
313     QSpinBox::setValue( QSpinBox::minValue() );
314   else
315     QSpinBox::setValue( ( QSpinBox::minValue() + QSpinBox::maxValue() ) / 2 );
316   
317   QSpinBox::updateDisplay();
318
319   editor()->setUpdatesEnabled( upd );
320
321   editor()->setText( myCleared ? QString::null : txt );
322   if ( !myCleared && editor()->hasFocus() )
323   {
324     if ( editor()->text() == specialValueText() )
325       editor()->selectAll();
326     else
327       editor()->setSelection( prefix().length(), editor()->text().length() - prefix().length() - suffix().length() );
328   }
329   else
330     editor()->setCursorPosition( 0 );
331
332   myBlocked = isBlock;
333 }
334
335 void QtxDblSpinBox::interpretText()
336 {
337   myCleared = false;
338
339   bool ok = true;
340   bool done = false;
341   double newVal = 0;
342   if ( !specialValueText().isEmpty() )
343   {
344           QString s = QString( text() ).stripWhiteSpace();
345           QString t = QString( specialValueText() ).stripWhiteSpace();
346           if ( s == t )
347     {
348       newVal = minValue();
349             done = true;
350     }
351   }
352   if ( !done )
353           newVal = mapTextToDoubleValue( &ok );
354   if ( ok )
355           setValue( newVal );
356   updateDisplay();
357 }
358
359 void QtxDblSpinBox::valueChange()
360 {
361   updateDisplay();
362   emit valueChanged( myValue );
363   emit valueChanged( currentValueText() );
364 }
365
366 void QtxDblSpinBox::rangeChange()
367 {
368   double min = QMIN( myMin, myMax );
369   double max = QMAX( myMin, myMax );
370   myMin = min;
371   myMax = max;
372   QDoubleValidator* v = ::qt_cast<QDoubleValidator*>( validator() );
373   if ( v )
374     v->setRange( myMin, myMax );
375
376         if ( myMin == myMax )
377                 QSpinBox::setRange( 0, 0 );
378         else
379                 QSpinBox::setRange( 0, 2 );
380
381   setValue( myValue );
382   updateDisplay();
383 }
384
385 QString QtxDblSpinBox::currentValueText()
386 {
387   QString s;
388   if ( (myValue == minValue()) && !specialValueText().isEmpty() )
389           s = specialValueText();
390   else
391         {
392           s = prefix();
393                 s.append( mapValueToText( myValue ) );
394                 s.append( suffix() );
395         }
396   return s;
397 }
398
399 QString QtxDblSpinBox::mapValueToText( double v )
400 {
401         QString s;
402   s.setNum( v, myPrecision >= 0 ? 'f' : 'g', myPrecision == 0 ? 6 : QABS( myPrecision ) );
403   return removeTrailingZeroes( s );
404 }
405
406 QString QtxDblSpinBox::mapValueToText( int )
407 {
408   QString s;
409   s.setNum( myValue, myPrecision >= 0 ? 'f' : 'g', myPrecision == 0 ? 6 : QABS( myPrecision ) );
410   return removeTrailingZeroes( s );
411 }
412
413 double QtxDblSpinBox::mapTextToDoubleValue( bool* ok )
414 {
415   QString s = text();
416   double newVal = s.toDouble( ok );
417   if ( !(*ok) && !( !prefix() && !suffix() ) )
418   {
419           s = cleanText();
420           newVal = s.toDouble( ok );
421   }
422   return newVal;
423 }
424
425 double QtxDblSpinBox::bound( double val )
426 {
427   double newVal = val;
428   if ( newVal > myMax )
429     newVal = myMax;
430   if ( newVal < myMin )
431     newVal = myMin;
432   return newVal;
433 }
434
435 void QtxDblSpinBox::leaveEvent( QEvent* e )
436 {
437         if ( !myCleared )
438                 QSpinBox::leaveEvent( e );
439 }
440
441 void QtxDblSpinBox::wheelEvent( QWheelEvent* e )
442 {
443   if ( !isEnabled() )
444     return;
445
446   QSpinBox::wheelEvent( e );
447   updateDisplay();
448 }
449
450 void QtxDblSpinBox::onTextChanged( const QString& str )
451 {
452   if ( !myBlocked )
453     myCleared = false;
454 }
455
456 QString QtxDblSpinBox::removeTrailingZeroes( const QString& src ) const
457 {
458   QString delim( "." );
459
460   int idx = src.findRev( delim );
461   if ( idx == -1 )
462     return src;
463
464   QString iPart = src.left( idx );
465   QString fPart = src.mid( idx + 1 );
466
467   while ( !fPart.isEmpty() && fPart.at( fPart.length() - 1 ) == '0' )
468     fPart.remove( fPart.length() - 1, 1 );
469
470   QString res = iPart;
471   if ( !fPart.isEmpty() )
472     res += delim + fPart;
473
474   return res;
475 }