File indexing completed on 2024-12-08 08:10:25
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2006 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "doublespinbox.h" 0012 #include "cnitem.h" 0013 0014 #include <KLocalizedString> 0015 0016 #include <QDebug> 0017 #include <QLineEdit> 0018 #include <QLocale> 0019 #include <QLoggingCategory> 0020 #include <QRegExp> 0021 #include <QTimer> 0022 0023 #include <algorithm> 0024 #include <cmath> 0025 0026 using namespace std; 0027 0028 Q_LOGGING_CATEGORY(KTL_DOUBLESPINBOX_LOG, "org.kde.ktechlab.doublespinbox", QtWarningMsg) 0029 0030 inline int roundDouble(double val) 0031 { 0032 return (val > 0) ? int(val + 0.5) : int(val - 0.5); 0033 } 0034 0035 DoubleSpinBox::DoubleSpinBox(double lower, double upper, double minAbs, double value, const QString &unit, QWidget *parent) 0036 : QDoubleSpinBox(parent) 0037 { 0038 qCDebug(KTL_DOUBLESPINBOX_LOG) << " lower=" << lower << " upper=" << upper << " minAbs=" << minAbs << " value=" << value << " unit=" << unit << " parent=" << parent; 0039 0040 setDecimals(20); // should be enough 0041 0042 // m_lastEmittedValue = value; 0043 m_unit = unit; 0044 // m_minValue = lower; 0045 setMinimum(lower); 0046 // m_maxValue = upper; 0047 setMaximum(upper); 0048 m_minAbsValue = minAbs; 0049 // m_queuedSuffix = QString(); 0050 0051 init(); 0052 setValue(value); 0053 } 0054 0055 DoubleSpinBox::DoubleSpinBox(QWidget *parent) 0056 : QDoubleSpinBox(parent) 0057 { 0058 setDecimals(20); // should be enough 0059 0060 m_lastEmittedValue = 0; 0061 // m_minValue = 0; 0062 setMinimum(0); 0063 // m_maxValue = 1e9; 0064 setMaximum(1e9); 0065 m_minAbsValue = 1e-9; 0066 // m_queuedSuffix = QString(); 0067 0068 init(); 0069 setValue(0); 0070 } 0071 0072 void DoubleSpinBox::init() 0073 { 0074 lineEdit()->setAlignment(Qt::AlignRight); 0075 0076 // connect( this, SIGNAL(valueChanged(double)), this, SLOT(checkIfChanged()) ); 0077 // QSpinBox::setMinValue( -(1<<30) ); 0078 // QSpinBox::setMaxValue( +(1<<30) ); 0079 0080 // setValidator( 0 ); // apparently in Qt4 there is no validator 0081 } 0082 0083 DoubleSpinBox::~DoubleSpinBox() 0084 { 0085 } 0086 0087 QValidator::State DoubleSpinBox::validate(QString &text, int &pos) const 0088 { 0089 qCDebug(KTL_DOUBLESPINBOX_LOG) << "text = |" << text << "| pos= " << pos; 0090 return QValidator::Acceptable; // QValidator::Intermediate; // don't bother 0091 } 0092 0093 // double DoubleSpinBox::value() 0094 // { 0095 // const double mult = getMult(); 0096 // const double displatedNumber = getDisplayedNumber( 0 ); 0097 // const double toRet = displatedNumber * mult ; 0098 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "value() mult = " << mult; 0099 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "value() displatedNumber = " << displatedNumber; 0100 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "value() toRet = " << toRet; 0101 // return toRet; 0102 // } 0103 0104 // void DoubleSpinBox::setValue( double value ) 0105 // { 0106 // if ( this->value() == value ) 0107 // return; 0108 // 0109 // if ( value > maxValue() ) 0110 // value = maxValue(); 0111 // 0112 // else if ( value < minValue() ) 0113 // value = minValue(); 0114 // 0115 // if ( std::abs(value) < m_minAbsValue*0.9999 ) 0116 // value = 0.0; 0117 // 0118 // updateSuffix( value ); 0119 // 0120 // const int toBeStoredValue = roundDouble( (value / Item::getMultiplier( value )) /* * 100 */ ); 0121 // 0122 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "value = " << value; 0123 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "value() = " << QSpinBox::value(); 0124 // qCDebug(KTL_DOUBLESPINBOX_LOG) << "to be stored = " << toBeStoredValue; 0125 // 0126 // QSpinBox::setValue( toBeStoredValue ); 0127 // } 0128 0129 // void DoubleSpinBox::setUnit( const QString & unit ) 0130 // { 0131 // updateSuffix( value() ); 0132 // m_unit = unit; 0133 // } 0134 0135 void DoubleSpinBox::updateSuffix(double value) 0136 { 0137 QString nextSuffix = " " + CNItem::getNumberMag(value) + m_unit; 0138 setSuffix(nextSuffix); 0139 // m_queuedSuffix = " " + CNItem::getNumberMag( value ) + m_unit; 0140 // 0141 // Set suffix to be empty if it is nothing but white space 0142 // if ( m_queuedSuffix.trimmed().isEmpty() ) 0143 // m_queuedSuffix = ""; 0144 // 0145 // QTimer::singleShot( 0, this, SLOT(setQueuedSuffix()) ); 0146 } 0147 0148 // void DoubleSpinBox::setQueuedSuffix() 0149 // { 0150 // bool changed = false; 0151 // if ( !m_queuedSuffix.isNull() && suffix().simplifyWhiteSpace() != m_queuedSuffix.simplifyWhiteSpace() ) 0152 // { 0153 // setSuffix( m_queuedSuffix ); 0154 // changed = true; 0155 // } 0156 // m_queuedSuffix = QString(); 0157 // 0158 // if ( changed ) 0159 // emit valueChanged( value() ); 0160 // } 0161 0162 DoubleSpinBox::StepEnabled DoubleSpinBox::stepEnabled() const 0163 { 0164 return QDoubleSpinBox::StepDownEnabled | QDoubleSpinBox::StepUpEnabled; 0165 } 0166 0167 void DoubleSpinBox::stepBy(int steps) 0168 { 0169 double workVal = value(); 0170 while (steps != 0) { 0171 if (steps > 0) { 0172 workVal = getNextUpStepValue(workVal); 0173 steps--; 0174 } else { 0175 workVal = getNextDownStepValue(workVal); 0176 steps++; 0177 } 0178 } 0179 setValue(workVal); 0180 } 0181 0182 double DoubleSpinBox::getNextUpStepValue(double in) 0183 { 0184 qCDebug(KTL_DOUBLESPINBOX_LOG) << " in = " << in; 0185 0186 double value = roundToOneSF(in); 0187 0188 if (value == 0) { 0189 value = m_minAbsValue; 0190 } else if (value > 0) { 0191 value += std::pow(10., std::floor(std::log10(value))); 0192 } else { 0193 double sub = std::pow(10., std::floor(std::log10(std::abs(value)) - 1)); 0194 value += std::pow(10., std::floor(std::log10(std::abs(value) - sub))); 0195 } 0196 0197 value *= 1.00001; 0198 0199 if (std::abs(value) < m_minAbsValue) { 0200 value = 0.; 0201 } 0202 0203 qCDebug(KTL_DOUBLESPINBOX_LOG) << " out = " << value; 0204 return value; 0205 } 0206 0207 double DoubleSpinBox::getNextDownStepValue(double in) 0208 { 0209 qCDebug(KTL_DOUBLESPINBOX_LOG) << " in = " << in; 0210 0211 double value = roundToOneSF(in); 0212 0213 if (value == 0) { 0214 value = -m_minAbsValue; 0215 } else if (value > 0) { 0216 double sub = std::pow(10., std::floor(std::log10(value) - 1)); 0217 value -= std::pow(10., std::floor(std::log10(value - sub))); 0218 } else { 0219 double add = std::pow(10., std::floor(std::log10(std::abs(value)) - 1)); 0220 value -= std::pow(10., std::floor(std::log10(std::abs(value) + add))); 0221 } 0222 0223 value *= 1.00001; 0224 0225 if (std::abs(value) < m_minAbsValue) { 0226 value = 0.; 0227 } 0228 0229 qCDebug(KTL_DOUBLESPINBOX_LOG) << " out = " << value; 0230 0231 return value; 0232 } 0233 0234 // double DoubleSpinBox::getMult() 0235 // { 0236 // QString text = this->text().trimmed(); 0237 // if ( !m_queuedSuffix.isNull() ) 0238 // { 0239 // QString nsSuffix = suffix().trimmed(); 0240 // 0241 // if ( nsSuffix.isEmpty() ) 0242 // text.append( m_queuedSuffix ); 0243 // else 0244 // text.replace( nsSuffix, m_queuedSuffix ); 0245 // } 0246 // 0247 // if ( text.length() == 0 ) 0248 // return 1.0; 0249 // 0250 // if ( text.endsWith( m_unit, false ) ) 0251 // text = text.remove( text.length() - m_unit.length(), m_unit.length() ); 0252 // 0253 // text.trimmed(); 0254 // 0255 // QChar siExp = text[ text.length()-1 ]; 0256 // 0257 // if ( siExp.isLetter() || siExp.isSymbol() ) 0258 // return CNItem::getMultiplier((QString)siExp); 0259 // 0260 // else 0261 // return 1; 0262 // } 0263 0264 // double DoubleSpinBox::getDisplayedNumber( bool * ok ) 0265 // { 0266 // KLocale * locale = KGlobal::locale(); 0267 // 0268 // //Fetch the characters that we don't want to discard 0269 // const QString exclude = locale->decimalSymbol() 0270 // + locale->thousandsSeparator() 0271 // + locale->positiveSign() 0272 // + locale->negativeSign(); 0273 // 0274 // QString number = cleanText().remove( QRegExp("[^"+exclude+"\\d]") ); 0275 // 0276 // return locale->readNumber( number, ok ); 0277 // } 0278 0279 // int DoubleSpinBox::mapTextToValue( bool * ok ) 0280 // { 0281 // (void)ok; 0282 // 0283 // double value = this->value(); 0284 // 0285 // if ( value > maxValue() ) 0286 // value = maxValue(); 0287 // 0288 // else if ( value < minValue() ) 0289 // value = minValue(); 0290 // 0291 // if ( std::abs(value) < m_minAbsValue*0.9999 ) 0292 // value = 0.0; 0293 // 0294 // updateSuffix( value ); 0295 // 0296 // value /= Item::getMultiplier( value ); 0297 // 0298 // Precision of 2 extra digits 0299 // return int( value /* * 100 */ ); 0300 // } 0301 // 0302 0303 double DoubleSpinBox::valueFromText(const QString &text) const 0304 { 0305 qCDebug(KTL_DOUBLESPINBOX_LOG) << "text = " << text; 0306 0307 QLocale locale; 0308 0309 // Fetch the characters that we don't want to discard 0310 const QString exclude = QString(locale.decimalPoint()) + locale.groupSeparator() + locale.positiveSign() + locale.negativeSign(); 0311 0312 QString textToStrip(text); 0313 QString numberToRead = textToStrip.remove(QRegExp("[^" + exclude + "\\d]")); 0314 0315 bool ok; 0316 double value = locale.toDouble(numberToRead, &ok); 0317 if (!ok) { 0318 qCDebug(KTL_DOUBLESPINBOX_LOG) << "numberToRead = |" << numberToRead << "| NOT OK"; 0319 value = 0; 0320 } 0321 qCDebug(KTL_DOUBLESPINBOX_LOG) << "numberToRead = " << numberToRead << ", value = " << value; 0322 0323 if (value > maximum()) { 0324 value = maximum(); 0325 } else if (value < minimum()) { 0326 value = minimum(); 0327 } 0328 0329 if (std::abs(value) < m_minAbsValue * 0.9999) { 0330 value = 0.0; 0331 } 0332 0333 double multiplier = 1.0; 0334 // updateSuffix( value ); 0335 QString textForSuffix(text); 0336 0337 if (textForSuffix.length() != 0) { 0338 if (textForSuffix.endsWith(m_unit, Qt::CaseInsensitive)) { 0339 textForSuffix = textForSuffix.remove(textForSuffix.length() - m_unit.length(), m_unit.length()); 0340 } 0341 0342 textForSuffix = textForSuffix.trimmed(); 0343 0344 QChar siExp; 0345 if (textForSuffix.length() > 0) { 0346 siExp = textForSuffix[textForSuffix.length() - 1]; 0347 } else { 0348 siExp = '1'; 0349 } 0350 0351 qCDebug(KTL_DOUBLESPINBOX_LOG) << "SI exp = " << siExp; 0352 0353 if (siExp.isLetter() || siExp.isSymbol()) { 0354 multiplier = CNItem::getMultiplier(QString(siExp)); 0355 } else { 0356 multiplier = 1; 0357 } 0358 } 0359 qCDebug(KTL_DOUBLESPINBOX_LOG) << "multiplier = " << multiplier; 0360 0361 // value /= Item::getMultiplier( value ); 0362 value *= multiplier; 0363 0364 qCDebug(KTL_DOUBLESPINBOX_LOG) << "value = " << value; 0365 0366 return value; 0367 } 0368 0369 // 0370 // QString DoubleSpinBox::mapValueToText( int v ) 0371 // { 0372 // double val = double(v) /* /100.0 */; 0373 // 0374 // int leftDigits = (int)floor( log10( abs(val) ) ) + 1; 0375 // if ( leftDigits < 0 ) 0376 // leftDigits = 0; 0377 // else if ( leftDigits > 3 ) 0378 // leftDigits = 3; 0379 // 0380 // KLocale * locale = KGlobal::locale(); 0381 // return locale->formatNumber( val, 3-leftDigits ); 0382 // } 0383 0384 QString DoubleSpinBox::textFromValue(double value) const 0385 { 0386 qCDebug(KTL_DOUBLESPINBOX_LOG) << " value = " << value; 0387 0388 // int leftDigits = (int)floor( log10( abs( value ) ) ) + 1; 0389 // if ( leftDigits < 0 ) { 0390 // leftDigits = 0; 0391 // } else if ( leftDigits > 3 ) { 0392 // leftDigits = 3; 0393 // } 0394 double multiplier = Item::getMultiplier(value); 0395 0396 double toDisplayNr = value / multiplier; 0397 0398 qCDebug(KTL_DOUBLESPINBOX_LOG) << "toDisplayNr = " << toDisplayNr; 0399 0400 QString numberStr = QLocale().toString(toDisplayNr, 'f', 0 /* 3-leftDigits */); 0401 0402 QString magStr = Item::getNumberMag(value); 0403 0404 QString toRet = numberStr + " " + magStr + m_unit; 0405 0406 qCDebug(KTL_DOUBLESPINBOX_LOG) << " text = " << toRet; 0407 return toRet; 0408 } 0409 0410 // void DoubleSpinBox::checkIfChanged() 0411 // { 0412 // double newValue = value(); 0413 // 0414 // if ( m_lastEmittedValue == newValue ) 0415 // return; 0416 // 0417 // m_lastEmittedValue = newValue; 0418 // emit valueChanged( m_lastEmittedValue ); 0419 // } 0420 0421 double DoubleSpinBox::roundToOneSF(double value) 0422 { 0423 if (value == 0.0) 0424 return 0.0; 0425 0426 value *= 1.000001; 0427 double tens = pow(10.0, floor(log10(abs(value)))); 0428 0429 return int(value / tens) * tens; 0430 } 0431 0432 // void DoubleSpinBox::stepUp() 0433 // { 0434 // double value = roundToOneSF( this->value() ); 0435 // 0436 // if ( value == 0 ) 0437 // value = m_minAbsValue; 0438 // 0439 // else if ( value > 0 ) 0440 // value += std::pow( 10., std::floor( std::log10(value) ) ); 0441 // 0442 // else 0443 // { 0444 // double sub = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); 0445 // value += std::pow( 10., std::floor( std::log10(std::abs(value)-sub) ) ); 0446 // } 0447 // 0448 // value *= 1.00001; 0449 // 0450 // if ( std::abs(value) < m_minAbsValue ) 0451 // value = 0.; 0452 // 0453 // setValue( value ); 0454 // } 0455 0456 // void DoubleSpinBox::stepDown() 0457 // { 0458 // double value = roundToOneSF( this->value() ); 0459 // 0460 // if ( value == 0 ) 0461 // value = -m_minAbsValue; 0462 // 0463 // else if ( value > 0 ) 0464 // { 0465 // double sub = std::pow(10., std::floor( std::log10(value)-1) ); 0466 // value -= std::pow( 10., std::floor( std::log10(value-sub) ) ); 0467 // } 0468 // else 0469 // { 0470 // double add = std::pow(10., std::floor( std::log10(std::abs(value))-1) ); 0471 // value -= std::pow( 10., std::floor( std::log10(std::abs(value)+add) ) ); 0472 // } 0473 // 0474 // value *= 1.00001; 0475 // 0476 // if ( std::abs(value) < m_minAbsValue ) 0477 // value = 0.; 0478 // 0479 // setValue( value ); 0480 // } 0481 0482 #include "moc_doublespinbox.cpp"