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