Salome HOME
Fixing a bug : Salome GUI style needs addLibraryPath() method to be called
[modules/gui.git] / src / Qtx / QtxDblSpinBox.cxx
1 // File:      QtxDblSpinBox.cxx
2 // Author:    Sergey TELKOV
3
4 #include "QtxDblSpinBox.h"
5
6 #include <qlineedit.h>
7 #include <qvalidator.h>
8 #include <qapplication.h>
9
10 /*
11         Class: QtxDblSpinBox::Validator [internal]
12         Descr: Validator for QtxDblSpinBox (getted from Trolltech Qt - SpinBoxValidator)
13 */
14
15 class QtxDblSpinBox::Validator : public QDoubleValidator
16 {
17 public:
18     Validator( QtxDblSpinBox* sb, const char* name )
19         : QDoubleValidator( sb, name ), spinBox( sb ) {}
20
21     virtual State validate( QString& str, int& pos ) const;
22
23 private:
24     QtxDblSpinBox* spinBox;
25 };
26
27 QValidator::State QtxDblSpinBox::Validator::validate( QString& str, int& pos ) const
28 {
29   QString pref = spinBox->prefix();
30   QString suff = spinBox->suffix();
31   uint overhead = pref.length() + suff.length();
32   State state = Invalid;
33
34   if ( overhead == 0 )
35           state = QDoubleValidator::validate( str, pos );
36   else
37         {
38                 if ( str.length() >= overhead && str.startsWith( pref ) &&
39          str.right( suff.length() ) == suff )
40                 {
41                         QString core = str.mid( pref.length(), str.length() - overhead );
42                         int corePos = pos - pref.length();
43                         state = QDoubleValidator::validate( core, corePos );
44                         pos = corePos + pref.length();
45                         str.replace( pref.length(), str.length() - overhead, core );
46                 }
47                 else
48                 {
49                         state = QDoubleValidator::validate( str, pos );
50                         if ( state == Invalid )
51                         {
52                                 QString special = spinBox->specialValueText().stripWhiteSpace();
53                                 QString candidate = str.stripWhiteSpace();
54                                 if ( special.startsWith( candidate ) )
55                                 {
56                                         if ( candidate.length() == special.length() )
57                                                 state = Acceptable;
58                                         else
59                                                 state = Intermediate;
60                                 }
61                         }
62                 }
63   }
64   return state;
65 }
66
67 /*
68         Class: QtxDblSpinBox
69         Descr: Spin box for real numbers.
70 */
71
72 QtxDblSpinBox::QtxDblSpinBox( QWidget* parent, const char* name )
73 : QSpinBox( parent, name ),
74 myCleared( false ),
75 myBlocked( false ),
76 myPrecision( 0 )
77 {
78   myMin = QRangeControl::minValue();
79   myMax = QRangeControl::maxValue();
80   myStep = QRangeControl::lineStep();
81         myValue = myMin;
82   setValidator( new Validator( this, "double_spinbox_validator" ) );
83   rangeChange();
84   updateDisplay();
85
86   //connect( editor(), SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) );
87 }
88
89 QtxDblSpinBox::QtxDblSpinBox( double min, double max, double step, QWidget* parent, const char* name )
90 : QSpinBox( parent, name ),
91 myMin( min ),
92 myMax( max ),
93 myStep( step ),
94 myCleared( false ),
95 myBlocked( false ),
96 myPrecision( 0 )
97 {
98         myValue = myMin;
99   setValidator( new Validator( this, "double_spinbox_validator" ) );
100   rangeChange();
101   updateDisplay();
102
103   //connect( editor(), SIGNAL( textChanged( const QString& ) ), this, SLOT( onTextChanged( const QString& ) ) );
104 }
105
106 QtxDblSpinBox::~QtxDblSpinBox()
107 {
108 }
109
110 double QtxDblSpinBox::minValue() const
111 {
112   return myMin;
113 }
114
115 double QtxDblSpinBox::maxValue() const
116 {
117   return myMax;
118 }
119
120 void QtxDblSpinBox::setMinValue( int min )
121 {
122         setMinValue( (double)min );
123 }
124
125 void QtxDblSpinBox::setMinValue( double min )
126 {
127   if ( myMin != min )
128   {
129     myMin = min;
130     rangeChange();
131   }
132 }
133
134 void QtxDblSpinBox::setMaxValue( int max )
135 {
136         setMaxValue( (double)max );
137 }
138
139 void QtxDblSpinBox::setMaxValue( double max )
140 {
141   if ( myMax != max )
142   {
143     myMax = max;
144     rangeChange();
145   }
146 }
147
148 void QtxDblSpinBox::setRange( int min, int max )
149 {
150         setRange( (double)min, (double)max );
151 }
152
153 void QtxDblSpinBox::setRange( double min, double max )
154 {
155   if ( myMin != min || myMax != max )
156   {
157     myMin = min;
158     myMax = max;
159     rangeChange();
160   }
161 }
162
163 double QtxDblSpinBox::lineStep() const
164 {
165   return myStep;
166 }
167
168 void QtxDblSpinBox::setLineStep( int step )
169 {
170   setLineStep( (double)step );
171 }
172
173 void QtxDblSpinBox::setLineStep( double step )
174 {
175   myStep = step;
176 }
177
178 double QtxDblSpinBox::value() const
179 {
180   QtxDblSpinBox* _this = ( QtxDblSpinBox* )this;
181   _this->clearFocus();
182   return myValue;
183 }
184
185 void QtxDblSpinBox::setValue( int val )
186 {
187         setValue( (double)val );
188 }
189
190 void QtxDblSpinBox::setValue( double val )
191 {
192         myCleared = false;
193   double prevVal = myValue;
194   myValue = bound( val );
195   if ( prevVal != myValue )
196     valueChange();
197 }
198
199 void QtxDblSpinBox::stepUp()
200 {
201         interpretText();
202         if ( wrapping() && myValue + myStep > myMax )
203                 setValue( myMin );
204         else
205                 setValue( myValue + myStep );
206 }
207
208 void QtxDblSpinBox::stepDown()
209 {
210         interpretText();
211         if ( wrapping() && myValue - myStep < myMin )
212                 setValue( myMax );
213         else
214                 setValue( myValue - myStep );
215 }
216
217 int QtxDblSpinBox::precision() const
218 {
219         return myPrecision;
220 }
221
222 void QtxDblSpinBox::setPrecision( const int prec )
223 {
224         int newPrec = QMAX( prec, 0 );
225         int oldPrec = QMAX( myPrecision, 0 );
226         myPrecision = prec;
227         if ( newPrec != oldPrec )
228                 updateDisplay();
229 }
230
231 bool QtxDblSpinBox::isCleared() const
232 {
233         return myCleared;
234 }
235
236 void QtxDblSpinBox::setCleared( const bool on )
237 {
238         if ( myCleared == on )
239                 return;
240
241         myCleared = on;
242         updateDisplay();
243 }
244
245 void QtxDblSpinBox::selectAll()
246 {
247 #if QT_VER >= 3
248         QSpinBox::selectAll();
249 #else
250   editor()->selectAll();
251 #endif
252 }
253
254 bool QtxDblSpinBox::eventFilter( QObject* o, QEvent* e )
255 {
256   if ( !myCleared || o != editor() || !editor()->text().stripWhiteSpace().isEmpty() )
257     return QSpinBox::eventFilter( o, e );
258
259   if ( e->type() == QEvent::FocusOut || e->type() == QEvent::Leave || e->type() == QEvent::Hide )
260     return false;
261
262   if ( e->type() == QEvent::KeyPress &&
263           ( ((QKeyEvent*)e)->key() == Key_Tab || ((QKeyEvent*)e)->key() == Key_BackTab ) )
264   {
265     QApplication::sendEvent( this, e );
266     return true;
267   }
268
269   return QSpinBox::eventFilter( o, e );
270 }
271
272 void QtxDblSpinBox::updateDisplay()
273 {
274   if ( myBlocked )
275     return;
276     
277   bool isBlock = myBlocked;
278   myBlocked = true;
279     
280   QString txt = currentValueText();
281     
282   if ( myValue >= myMax )
283     QSpinBox::setValue( QSpinBox::maxValue() );
284   else if ( myValue <= myMin )
285     QSpinBox::setValue( QSpinBox::minValue() );
286   else
287     QSpinBox::setValue( ( QSpinBox::minValue() + QSpinBox::maxValue() ) / 2 );
288     
289   QSpinBox::updateDisplay();
290     
291   editor()->setText( myCleared ? QString::null : txt );
292     
293   myBlocked = isBlock;
294 }
295
296 void QtxDblSpinBox::interpretText()
297 {
298   myCleared = false;
299
300   bool ok = true;
301   bool done = false;
302   double newVal = 0;
303   if ( !specialValueText().isEmpty() )
304   {
305           QString s = QString( text() ).stripWhiteSpace();
306           QString t = QString( specialValueText() ).stripWhiteSpace();
307           if ( s == t )
308     {
309       newVal = minValue();
310             done = true;
311     }
312   }
313   if ( !done )
314           newVal = mapTextToDoubleValue( &ok );
315   if ( ok )
316           setValue( newVal );
317   updateDisplay();
318 }
319
320 void QtxDblSpinBox::valueChange()
321 {
322   updateDisplay();
323   emit valueChanged( value() );
324   emit valueChanged( currentValueText() );
325 }
326
327 void QtxDblSpinBox::rangeChange()
328 {
329   double min = QMIN( myMin, myMax );
330   double max = QMAX( myMin, myMax );
331   myMin = min;
332   myMax = max;
333   if ( validator()->inherits( "QDoubleValidator" ) )
334     ((QDoubleValidator*)validator())->setRange( myMin, myMax );
335
336         if ( myMin == myMax )
337                 QSpinBox::setRange( 0, 0 );
338         else
339                 QSpinBox::setRange( 0, 2 );
340
341   setValue( myValue );
342   updateDisplay();
343 }
344
345 QString QtxDblSpinBox::currentValueText()
346 {
347   QString s;
348   if ( (myValue == minValue()) && !specialValueText().isEmpty() )
349           s = specialValueText();
350   else
351         {
352           s = prefix();
353                 s.append( mapValueToText( myValue ) );
354                 s.append( suffix() );
355         }
356   return s;
357 }
358
359 QString QtxDblSpinBox::mapValueToText( double v )
360 {
361         QString s;
362   s.setNum( v, myPrecision < 0 ? 'f' : 'g', myPrecision == 0 ? 6 : QABS( myPrecision ) );
363   return s;
364 }
365
366 QString QtxDblSpinBox::mapValueToText( int )
367 {
368   QString s;
369   s.setNum( myValue, myPrecision < 0 ? 'f' : 'g', myPrecision == 0 ? 6 : QABS( myPrecision ) );
370   return s;
371 }
372
373 double QtxDblSpinBox::mapTextToDoubleValue( bool* ok )
374 {
375   QString s = text();
376   double newVal = s.toDouble( ok );
377   if ( !(*ok) && !( !prefix() && !suffix() ) )
378   {
379           s = cleanText();
380           newVal = s.toDouble( ok );
381   }
382   return newVal;
383 }
384
385 double QtxDblSpinBox::bound( double val )
386 {
387   double newVal = val;
388   if ( newVal > myMax )
389     newVal = myMax;
390   if ( newVal < myMin )
391     newVal = myMin;
392   return newVal;
393 }
394
395 void QtxDblSpinBox::leaveEvent( QEvent* e )
396 {
397         if ( !myCleared )
398                 QSpinBox::leaveEvent( e );
399 }
400
401 void QtxDblSpinBox::wheelEvent( QWheelEvent* e )
402 {
403   if ( !isEnabled() )
404     return;
405
406   QSpinBox::wheelEvent( e );
407   updateDisplay();
408 }
409
410 void QtxDblSpinBox::onTextChanged( const QString& str )
411 {
412   bool isBlock = myBlocked;
413   myBlocked = true;
414   interpretText();
415   myBlocked = isBlock;
416 }