File indexing completed on 2024-05-19 15:27:52
0001 /* This file is part of KGraphViewer. 0002 Copyright (C) 2005-2007 Gael de Chalendar <kleag@free.fr> 0003 0004 KGraphViewer is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU General Public 0006 License as published by the Free Software Foundation, version 2. 0007 0008 This program is distributed in the hope that it will be useful, 0009 but WITHOUT ANY WARRANTY; without even the implied warranty of 0010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0011 General Public License for more details. 0012 0013 You should have received a copy of the GNU General Public License 0014 along with this program; if not, write to the Free Software 0015 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0016 02110-1301, USA 0017 */ 0018 0019 /* This file was part of the KDE project 0020 Copyright (C) 2005 Jarosław Staniek <staniek@kde.org> 0021 0022 This program is free software; you can redistribute it and/or 0023 modify it under the terms of the GNU Library General Public 0024 License as published by the Free Software Foundation; either 0025 version 2 of the License, or (at your option) any later version. 0026 */ 0027 0028 #include "KgvUnitWidgets.h" 0029 #include "kgraphviewerlib_debug.h" 0030 0031 #include <QDebug> 0032 #include <QEvent> 0033 #include <QGridLayout> 0034 #include <QLocale> 0035 #include <qlayout.h> 0036 #include <qpushbutton.h> 0037 0038 // ---------------------------------------------------------------- 0039 // Support classes 0040 0041 KgvUnitDoubleValidator::KgvUnitDoubleValidator(KgvUnitDoubleBase *base, QObject *parent) 0042 : QDoubleValidator(parent) 0043 , m_base(base) 0044 { 0045 } 0046 0047 QValidator::State KgvUnitDoubleValidator::validate(QString &s, int &pos) const 0048 { 0049 qCDebug(KGRAPHVIEWERLIB_LOG) << "KgvUnitDoubleValidator::validate : " << s << " at " << pos; 0050 QValidator::State result = Acceptable; 0051 0052 QRegExp regexp("([ a-zA-Z]+)$"); // Letters or spaces at end 0053 const int res = regexp.indexIn(s); 0054 0055 if (res == -1) { 0056 // Nothing like an unit? The user is probably editing the unit 0057 qCDebug(KGRAPHVIEWERLIB_LOG) << "Intermediate (no unit)"; 0058 return Intermediate; 0059 } 0060 0061 // ### TODO: are all the QString::trimmed really necessary? 0062 const QString number(s.left(res).trimmed()); 0063 const QString unitName(regexp.cap(1).trimmed().toLower()); 0064 0065 qCDebug(KGRAPHVIEWERLIB_LOG) << "Split:" << number << ":" << unitName << ":"; 0066 0067 bool ok = false; 0068 const double value = m_base->toDouble(number, &ok); 0069 double newVal = 0.0; 0070 if (ok) { 0071 KgvUnit::Unit unit = KgvUnit::unit(unitName, &ok); 0072 if (ok) 0073 newVal = KgvUnit::fromUserValue(value, unit); 0074 else { 0075 // Probably the user is trying to edit the unit 0076 qCDebug(KGRAPHVIEWERLIB_LOG) << "Intermediate (unknown unit)"; 0077 return Intermediate; 0078 } 0079 } else { 0080 qCWarning(KGRAPHVIEWERLIB_LOG) << "Not a number:" << number; 0081 return Invalid; 0082 } 0083 0084 newVal = KgvUnit::ptToUnit(newVal, m_base->m_unit); 0085 0086 s = m_base->getVisibleText(newVal); 0087 0088 return result; 0089 } 0090 0091 QString KgvUnitDoubleBase::getVisibleText(double value) const 0092 { 0093 const QString num(QString("%1%2").arg(QLocale().toString(value, m_precision), KgvUnit::unitName(m_unit))); 0094 qCDebug(KGRAPHVIEWERLIB_LOG) << "getVisibleText: " << QString::number(value, 'f', 12) << " => " << num; 0095 return num; 0096 } 0097 0098 double KgvUnitDoubleBase::toDouble(const QString &str, bool *ok) const 0099 { 0100 QString str2(str); 0101 /* KLocale::readNumber wants the thousand separator exactly at 1000. 0102 But when editing, it might be anywhere. So we need to remove it. */ 0103 const QString sep(QLocale().groupSeparator()); 0104 if (!sep.isEmpty()) 0105 str2.remove(sep); 0106 str2.remove(KgvUnit::unitName(m_unit)); 0107 const double dbl = QLocale().toDouble(str2, ok); 0108 if (ok) 0109 qCDebug(KGRAPHVIEWERLIB_LOG) << "toDouble:" << str << ": => :" << str2 << ": => " << QString::number(dbl, 'f', 12); 0110 else 0111 qCWarning(KGRAPHVIEWERLIB_LOG) << "error:" << str << ": => :" << str2 << ":"; 0112 return dbl; 0113 } 0114 0115 // ---------------------------------------------------------------- 0116 // Widget classes 0117 0118 KgvUnitDoubleSpinBox::KgvUnitDoubleSpinBox(QWidget *parent) 0119 : QDoubleSpinBox(parent) 0120 , KgvUnitDoubleBase(KgvUnit::U_PT, 2) 0121 , m_lowerInPoints(-9999) 0122 , m_upperInPoints(9999) 0123 , m_stepInPoints(1) 0124 { 0125 QDoubleSpinBox::setDecimals(2); 0126 m_validator = new KgvUnitDoubleValidator(this, this); 0127 // QSpinBox::setValidator( m_validator ); 0128 // setAcceptLocalizedNumbers( true ); 0129 setUnit(KgvUnit::U_PT); 0130 0131 connect(this, static_cast<void (KgvUnitDoubleSpinBox::*)(double)>(&KgvUnitDoubleSpinBox::valueChanged), this, &KgvUnitDoubleSpinBox::privateValueChanged); 0132 } 0133 0134 KgvUnitDoubleSpinBox::KgvUnitDoubleSpinBox(QWidget *parent, double lower, double upper, double step, double value, KgvUnit::Unit unit, unsigned int precision) 0135 : QDoubleSpinBox(parent) 0136 , KgvUnitDoubleBase(unit, precision) 0137 , m_lowerInPoints(lower) 0138 , m_upperInPoints(upper) 0139 , m_stepInPoints(step) 0140 { 0141 setMinimum(lower); 0142 setMaximum(upper); 0143 setSingleStep(step); 0144 setValue(value); 0145 setDecimals(precision); 0146 QDoubleSpinBox::setMinimum(lower); 0147 QDoubleSpinBox::setMaximum(upper); 0148 QDoubleSpinBox::setSingleStep(step); 0149 QDoubleSpinBox::setValue(value); 0150 m_unit = KgvUnit::U_PT; 0151 m_validator = new KgvUnitDoubleValidator(this, this); 0152 // QSpinBox::setValidator( m_validator ); 0153 // setAcceptLocalizedNumbers( true ); 0154 setUnit(unit); 0155 changeValue(value); 0156 setLineStep(0.5); 0157 0158 connect(this, static_cast<void (KgvUnitDoubleSpinBox::*)(double)>(&KgvUnitDoubleSpinBox::valueChanged), this, &KgvUnitDoubleSpinBox::privateValueChanged); 0159 } 0160 0161 void KgvUnitDoubleSpinBox::changeValue(double val) 0162 { 0163 QDoubleSpinBox::setValue(KgvUnit::toUserValue(val, m_unit)); 0164 // TODO: emit valueChanged ONLY if the value was out-of-bounds 0165 // This will allow the 'user' dialog to set a dirty bool and ensure 0166 // a proper value is getting saved. 0167 } 0168 0169 void KgvUnitDoubleSpinBox::privateValueChanged() 0170 { 0171 emit valueChangedPt(value()); 0172 } 0173 0174 void KgvUnitDoubleSpinBox::setUnit(KgvUnit::Unit unit) 0175 { 0176 double oldvalue = KgvUnit::fromUserValue(QDoubleSpinBox::value(), m_unit); 0177 QDoubleSpinBox::setMinimum(KgvUnit::toUserValue(m_lowerInPoints, unit)); 0178 QDoubleSpinBox::setMaximum(KgvUnit::toUserValue(m_upperInPoints, unit)); 0179 QDoubleSpinBox::setSingleStep(KgvUnit::toUserValue(m_stepInPoints, unit)); 0180 QDoubleSpinBox::setValue(KgvUnit::ptToUnit(oldvalue, unit)); 0181 m_unit = unit; 0182 setSuffix(KgvUnit::unitName(unit).prepend(' ')); 0183 } 0184 0185 double KgvUnitDoubleSpinBox::value(void) const 0186 { 0187 return KgvUnit::fromUserValue(QDoubleSpinBox::value(), m_unit); 0188 } 0189 0190 void KgvUnitDoubleSpinBox::setMinValue(double min) 0191 { 0192 m_lowerInPoints = min; 0193 QDoubleSpinBox::setMinimum(KgvUnit::toUserValue(m_lowerInPoints, m_unit)); 0194 } 0195 0196 void KgvUnitDoubleSpinBox::setMaxValue(double max) 0197 { 0198 m_upperInPoints = max; 0199 QDoubleSpinBox::setMaximum(KgvUnit::toUserValue(m_upperInPoints, m_unit)); 0200 } 0201 0202 void KgvUnitDoubleSpinBox::setLineStep(double step) 0203 { 0204 m_stepInPoints = KgvUnit::toUserValue(step, KgvUnit::U_PT); 0205 QDoubleSpinBox::setSingleStep(step); 0206 } 0207 0208 void KgvUnitDoubleSpinBox::setLineStepPt(double step) 0209 { 0210 m_stepInPoints = step; 0211 QDoubleSpinBox::setSingleStep(KgvUnit::toUserValue(m_stepInPoints, m_unit)); 0212 } 0213 0214 void KgvUnitDoubleSpinBox::setMinMaxStep(double min, double max, double step) 0215 { 0216 setMinimum(min); 0217 setMaximum(max); 0218 setLineStepPt(step); 0219 } 0220 0221 // ---------------------------------------------------------------- 0222 0223 KgvUnitDoubleLineEdit::KgvUnitDoubleLineEdit(QWidget *parent) 0224 : QLineEdit(parent) 0225 , KgvUnitDoubleBase(KgvUnit::U_PT, 2) 0226 , m_value(0.0) 0227 , m_lower(0.0) 0228 , m_upper(9999.99) 0229 , m_lowerInPoints(0.0) 0230 , m_upperInPoints(9999.99) 0231 { 0232 setAlignment(Qt::AlignRight); 0233 m_validator = new KgvUnitDoubleValidator(this, this); 0234 setValidator(m_validator); 0235 setUnit(KgvUnit::U_PT); 0236 changeValue(KgvUnit::ptToUnit(0.0, KgvUnit::U_PT)); 0237 } 0238 0239 KgvUnitDoubleLineEdit::KgvUnitDoubleLineEdit(QWidget *parent, double lower, double upper, double value, KgvUnit::Unit unit, unsigned int precision) 0240 : QLineEdit(parent) 0241 , KgvUnitDoubleBase(unit, precision) 0242 , m_value(value) 0243 , m_lower(lower) 0244 , m_upper(upper) 0245 , m_lowerInPoints(lower) 0246 , m_upperInPoints(upper) 0247 { 0248 setAlignment(Qt::AlignRight); 0249 m_validator = new KgvUnitDoubleValidator(this, this); 0250 setValidator(m_validator); 0251 setUnit(unit); 0252 changeValue(KgvUnit::ptToUnit(value, unit)); 0253 } 0254 0255 void KgvUnitDoubleLineEdit::changeValue(double value) 0256 { 0257 m_value = value < m_lower ? m_lower : (value > m_upper ? m_upper : value); 0258 setText(getVisibleText(m_value)); 0259 } 0260 0261 void KgvUnitDoubleLineEdit::setUnit(KgvUnit::Unit unit) 0262 { 0263 KgvUnit::Unit old = m_unit; 0264 m_unit = unit; 0265 m_lower = KgvUnit::ptToUnit(m_lowerInPoints, unit); 0266 m_upper = KgvUnit::ptToUnit(m_upperInPoints, unit); 0267 changeValue(KgvUnit::ptToUnit(KgvUnit::fromUserValue(m_value, old), unit)); 0268 } 0269 0270 bool KgvUnitDoubleLineEdit::eventFilter(QObject *o, QEvent *ev) 0271 { 0272 #if 0 0273 if( ev->type() == QEvent::FocusOut || ev->type() == QEvent::Leave || ev->type() == QEvent::Hide ) 0274 { 0275 bool ok; 0276 double value = toDouble( text(), &ok ); 0277 changeValue( value ); 0278 return false; 0279 } 0280 else 0281 #endif 0282 return QLineEdit::eventFilter(o, ev); 0283 } 0284 0285 double KgvUnitDoubleLineEdit::value(void) const 0286 { 0287 return KgvUnit::fromUserValue(m_value, m_unit); 0288 } 0289 0290 // ---------------------------------------------------------------- 0291 0292 KgvUnitDoubleComboBox::KgvUnitDoubleComboBox(QWidget *parent) 0293 : QComboBox(parent) 0294 , KgvUnitDoubleBase(KgvUnit::U_PT, 2) 0295 , m_value(0.0) 0296 , m_lower(0.0) 0297 , m_upper(9999.99) 0298 , m_lowerInPoints(0.0) 0299 , m_upperInPoints(9999.99) 0300 { 0301 lineEdit()->setAlignment(Qt::AlignRight); 0302 m_validator = new KgvUnitDoubleValidator(this, this); 0303 lineEdit()->setValidator(m_validator); 0304 setUnit(KgvUnit::U_PT); 0305 changeValue(KgvUnit::ptToUnit(0.0, KgvUnit::U_PT)); 0306 connect(this, static_cast<void (KgvUnitDoubleComboBox::*)(int)>(&KgvUnitDoubleComboBox::activated), this, &KgvUnitDoubleComboBox::slotActivated); 0307 } 0308 0309 KgvUnitDoubleComboBox::KgvUnitDoubleComboBox(QWidget *parent, double lower, double upper, double value, KgvUnit::Unit unit, unsigned int precision) 0310 : QComboBox(parent) 0311 , KgvUnitDoubleBase(unit, precision) 0312 , m_value(value) 0313 , m_lower(lower) 0314 , m_upper(upper) 0315 , m_lowerInPoints(lower) 0316 , m_upperInPoints(upper) 0317 { 0318 lineEdit()->setAlignment(Qt::AlignRight); 0319 m_validator = new KgvUnitDoubleValidator(this, this); 0320 lineEdit()->setValidator(m_validator); 0321 setUnit(unit); 0322 changeValue(KgvUnit::ptToUnit(value, unit)); 0323 connect(this, static_cast<void (KgvUnitDoubleComboBox::*)(int)>(&KgvUnitDoubleComboBox::activated), this, &KgvUnitDoubleComboBox::slotActivated); 0324 } 0325 0326 void KgvUnitDoubleComboBox::changeValue(double value) 0327 { 0328 QString oldLabel = lineEdit()->text(); 0329 updateValue(value); 0330 if (lineEdit()->text() != oldLabel) 0331 emit valueChanged(m_value); 0332 } 0333 0334 void KgvUnitDoubleComboBox::updateValue(double value) 0335 { 0336 m_value = value < m_lower ? m_lower : (value > m_upper ? m_upper : value); 0337 lineEdit()->setText(getVisibleText(m_value)); 0338 } 0339 0340 void KgvUnitDoubleComboBox::insertItem(double value, int index) 0341 { 0342 QComboBox::insertItem(index, getVisibleText(value)); 0343 } 0344 0345 void KgvUnitDoubleComboBox::slotActivated(int index) 0346 { 0347 double oldvalue = m_value; 0348 bool ok; 0349 double value = toDouble(itemText(index), &ok); 0350 m_value = value < m_lower ? m_lower : (value > m_upper ? m_upper : value); 0351 if (m_value != oldvalue) 0352 emit valueChanged(m_value); 0353 } 0354 0355 void KgvUnitDoubleComboBox::setUnit(KgvUnit::Unit unit) 0356 { 0357 KgvUnit::Unit old = m_unit; 0358 m_unit = unit; 0359 m_lower = KgvUnit::ptToUnit(m_lowerInPoints, unit); 0360 m_upper = KgvUnit::ptToUnit(m_upperInPoints, unit); 0361 changeValue(KgvUnit::ptToUnit(KgvUnit::fromUserValue(m_value, old), unit)); 0362 } 0363 0364 bool KgvUnitDoubleComboBox::eventFilter(QObject *o, QEvent *ev) 0365 { 0366 #if 0 0367 if( ev->type() == QEvent::FocusOut || ev->type() == QEvent::Leave || ev->type() == QEvent::Hide ) 0368 { 0369 bool ok; 0370 double value = toDouble( lineEdit()->text(), &ok ); 0371 changeValue( value ); 0372 return false; 0373 } 0374 else 0375 #endif 0376 return QComboBox::eventFilter(o, ev); 0377 } 0378 0379 double KgvUnitDoubleComboBox::value(void) const 0380 { 0381 return KgvUnit::fromUserValue(m_value, m_unit); 0382 } 0383 0384 // ---------------------------------------------------------------- 0385 0386 KgvUnitDoubleSpinComboBox::KgvUnitDoubleSpinComboBox(QWidget *parent) 0387 : QWidget(parent) 0388 , m_step(1.0) 0389 { 0390 QGridLayout *layout = new QGridLayout(this); 0391 // layout->setMargin( 2 ); 0392 QPushButton *up = new QPushButton("+", this); 0393 // up->setFlat( true ); 0394 up->setMaximumHeight(15); 0395 up->setMaximumWidth(15); 0396 layout->addWidget(up, 0, 0); 0397 connect(up, &QPushButton::clicked, this, &KgvUnitDoubleSpinComboBox::slotUpClicked); 0398 0399 QPushButton *down = new QPushButton("-", this); 0400 down->setMaximumHeight(15); 0401 down->setMaximumWidth(15); 0402 layout->addWidget(down, 1, 0); 0403 connect(down, &QPushButton::clicked, this, &KgvUnitDoubleSpinComboBox::slotDownClicked); 0404 0405 m_combo = new KgvUnitDoubleComboBox(this, KgvUnit::ptToUnit(0.0, KgvUnit::U_PT), KgvUnit::ptToUnit(9999.99, KgvUnit::U_PT), 0.0, KgvUnit::U_PT, 2); 0406 connect(m_combo, &KgvUnitDoubleComboBox::valueChanged, this, &KgvUnitDoubleSpinComboBox::valueChanged); 0407 layout->addWidget(m_combo, 0, 2, 2, 1); 0408 } 0409 0410 KgvUnitDoubleSpinComboBox::KgvUnitDoubleSpinComboBox(QWidget *parent, double lower, double upper, double step, double value, KgvUnit::Unit unit, unsigned int precision) 0411 : QWidget(parent) 0412 , m_step(step) //, m_lowerInPoints( lower ), m_upperInPoints( upper ) 0413 { 0414 QGridLayout *layout = new QGridLayout(this); 0415 // layout->setMargin( 2 ); 0416 QPushButton *up = new QPushButton("+", this); 0417 // up->setFlat( true ); 0418 up->setMaximumHeight(15); 0419 up->setMaximumWidth(15); 0420 layout->addWidget(up, 0, 0); 0421 connect(up, &QPushButton::clicked, this, &KgvUnitDoubleSpinComboBox::slotUpClicked); 0422 0423 QPushButton *down = new QPushButton("-", this); 0424 down->setMaximumHeight(15); 0425 down->setMaximumWidth(15); 0426 layout->addWidget(down, 1, 0); 0427 connect(down, &QPushButton::clicked, this, &KgvUnitDoubleSpinComboBox::slotDownClicked); 0428 0429 m_combo = new KgvUnitDoubleComboBox(this, KgvUnit::ptToUnit(lower, unit), KgvUnit::ptToUnit(upper, unit), value, unit, precision); 0430 connect(m_combo, &KgvUnitDoubleComboBox::valueChanged, this, &KgvUnitDoubleSpinComboBox::valueChanged); 0431 layout->addWidget(m_combo, 0, 2, 2, 1); 0432 } 0433 0434 void KgvUnitDoubleSpinComboBox::slotUpClicked() 0435 { 0436 m_combo->changeValue(m_combo->value() + m_step); 0437 } 0438 0439 void KgvUnitDoubleSpinComboBox::slotDownClicked() 0440 { 0441 m_combo->changeValue(m_combo->value() - m_step); 0442 } 0443 0444 void KgvUnitDoubleSpinComboBox::insertItem(double value, int index) 0445 { 0446 m_combo->insertItem(value, index); 0447 } 0448 0449 void KgvUnitDoubleSpinComboBox::updateValue(double value) 0450 { 0451 m_combo->updateValue(value); 0452 } 0453 0454 double KgvUnitDoubleSpinComboBox::value() const 0455 { 0456 return m_combo->value(); 0457 } 0458 0459 #include "moc_KgvUnitWidgets.cpp"