File indexing completed on 2024-05-12 16:02:12
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2002 Rob Buis (buis@kde.org) 0003 SPDX-FileCopyrightText: 2004 Nicolas GOUTTE <goutte@kde.org> 0004 SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "KoUnitDoubleSpinBox.h" 0010 0011 #include <KoUnit.h> 0012 0013 #include <WidgetsDebug.h> 0014 0015 #include <klocalizedstring.h> 0016 #include <qnumeric.h> 0017 0018 // #define DEBUG_VALIDATOR 0019 // #define DEBUG_VALUEFROMTEXT 0020 0021 class Q_DECL_HIDDEN KoUnitDoubleSpinBox::Private 0022 { 0023 public: 0024 Private(double low, double up, double step) 0025 : lowerInPoints(low), 0026 upperInPoints(up), 0027 stepInPoints(step), 0028 unit(KoUnit(KoUnit::Point)) 0029 { 0030 } 0031 0032 double lowerInPoints; ///< lowest value in points 0033 double upperInPoints; ///< highest value in points 0034 double stepInPoints; ///< step in points 0035 KoUnit unit; 0036 }; 0037 0038 KoUnitDoubleSpinBox::KoUnitDoubleSpinBox( QWidget *parent) 0039 : QDoubleSpinBox( parent ), 0040 d( new Private(-9999, 9999, 1)) 0041 { 0042 QDoubleSpinBox::setDecimals( 2 ); 0043 //setAcceptLocalizedNumbers( true ); 0044 setUnit( KoUnit(KoUnit::Point) ); 0045 setAlignment( Qt::AlignRight ); 0046 0047 connect(this, SIGNAL(valueChanged(double)), SLOT(privateValueChanged())); 0048 } 0049 0050 KoUnitDoubleSpinBox::~KoUnitDoubleSpinBox() 0051 { 0052 delete d; 0053 } 0054 0055 QValidator::State KoUnitDoubleSpinBox::validate(QString &input, int &pos) const 0056 { 0057 #ifdef DEBUG_VALIDATOR 0058 debugWidgets <<"KoUnitDoubleSpinBox::validate :" << input <<" at" << pos; 0059 #else 0060 Q_UNUSED(pos); 0061 #endif 0062 0063 QRegExp regexp ("([ a-zA-Z]+)$"); // Letters or spaces at end 0064 const int res = input.indexOf( regexp ); 0065 0066 if ( res == -1 ) 0067 { 0068 // Nothing like an unit? The user is probably editing the unit 0069 #ifdef DEBUG_VALIDATOR 0070 debugWidgets <<"Intermediate (no unit)"; 0071 #endif 0072 return QValidator::Intermediate; 0073 } 0074 0075 // ### TODO: are all the QString::trimmed really necessary? 0076 const QString number ( input.left( res ).trimmed() ); 0077 const QString unitName ( regexp.cap( 1 ).trimmed().toLower() ); 0078 0079 #ifdef DEBUG_VALIDATOR 0080 debugWidgets <<"Split:" << number <<":" << unitName <<":"; 0081 #endif 0082 0083 const double value = valueFromText( number ); 0084 double newVal = 0.0; 0085 if (!qIsNaN(value)) { 0086 bool ok; 0087 const KoUnit unit = KoUnit::fromSymbol(unitName, &ok); 0088 if ( ok ) 0089 newVal = unit.fromUserValue( value ); 0090 else 0091 { 0092 // Probably the user is trying to edit the unit 0093 #ifdef DEBUG_VALIDATOR 0094 debugWidgets <<"Intermediate (unknown unit)"; 0095 #endif 0096 return QValidator::Intermediate; 0097 } 0098 } 0099 else 0100 { 0101 warnWidgets << "Not a number: " << number; 0102 return QValidator::Invalid; 0103 } 0104 newVal = d->unit.toUserValuePrecise(newVal); 0105 //input = textFromValue( newVal ); // don't overwrite for now; the effect is not exactly what I expect... 0106 0107 return QValidator::Acceptable; 0108 } 0109 0110 void KoUnitDoubleSpinBox::changeValue( double val ) 0111 { 0112 QDoubleSpinBox::setValue( d->unit.toUserValue( val ) ); 0113 // TODO: emit valueChanged ONLY if the value was out-of-bounds 0114 // This will allow the 'user' dialog to set a dirty bool and ensure 0115 // a proper value is getting saved. 0116 } 0117 0118 void KoUnitDoubleSpinBox::privateValueChanged() { 0119 emit valueChangedPt( value () ); 0120 } 0121 0122 void KoUnitDoubleSpinBox::setUnit( const KoUnit &unit ) 0123 { 0124 if (unit == d->unit) return; 0125 0126 double oldvalue = d->unit.fromUserValue( QDoubleSpinBox::value() ); 0127 QDoubleSpinBox::setMinimum( unit.toUserValue( d->lowerInPoints ) ); 0128 QDoubleSpinBox::setMaximum( unit.toUserValue( d->upperInPoints ) ); 0129 0130 qreal step = unit.toUserValue( d->stepInPoints ); 0131 0132 if (unit.type() == KoUnit::Pixel) { 0133 // limit the pixel step by 1.0 0134 step = qMax(qreal(1.0), step); 0135 } 0136 0137 QDoubleSpinBox::setSingleStep( step ); 0138 d->unit = unit; 0139 QDoubleSpinBox::setValue(unit.toUserValuePrecise(oldvalue)); 0140 setSuffix(unit.symbol().prepend(QLatin1Char(' '))); 0141 } 0142 0143 double KoUnitDoubleSpinBox::value( ) const 0144 { 0145 return d->unit.fromUserValue( QDoubleSpinBox::value() ); 0146 } 0147 0148 void KoUnitDoubleSpinBox::setMinimum( double min ) 0149 { 0150 d->lowerInPoints = min; 0151 QDoubleSpinBox::setMinimum( d->unit.toUserValue( min ) ); 0152 } 0153 0154 void KoUnitDoubleSpinBox::setMaximum( double max ) 0155 { 0156 d->upperInPoints = max; 0157 QDoubleSpinBox::setMaximum( d->unit.toUserValue( max ) ); 0158 } 0159 0160 void KoUnitDoubleSpinBox::setLineStep( double step ) 0161 { 0162 d->stepInPoints = KoUnit(KoUnit::Point).toUserValue(step); 0163 QDoubleSpinBox::setSingleStep( step ); 0164 } 0165 0166 void KoUnitDoubleSpinBox::setLineStepPt( double step ) 0167 { 0168 d->stepInPoints = step; 0169 QDoubleSpinBox::setSingleStep( d->unit.toUserValue( step ) ); 0170 } 0171 0172 void KoUnitDoubleSpinBox::setMinMaxStep( double min, double max, double step ) 0173 { 0174 setMinimum( min ); 0175 setMaximum( max ); 0176 setLineStepPt( step ); 0177 } 0178 0179 QString KoUnitDoubleSpinBox::textFromValue( double value ) const 0180 { 0181 //debugWidgets <<"textFromValue:" << QString::number( value, 'f', 12 ) <<" =>" << num; 0182 //const QString num(QString("%1%2").arg(QLocale().toString(value, d->precision ), m_unit.symbol())); 0183 //const QString num ( QString( "%1").arg( QLocale().toString( value, d->precision )) ); 0184 return QLocale().toString( value, 'f', decimals() ); 0185 } 0186 0187 double KoUnitDoubleSpinBox::valueFromText( const QString& str ) const 0188 { 0189 QString str2( str ); 0190 str2.remove(d->unit.symbol()); 0191 return QLocale().toDouble(str2); 0192 // QString str2( str ); 0193 // /* KLocale::readNumber wants the thousand separator exactly at 1000. 0194 // But when editing, it might be anywhere. So we need to remove it. */ 0195 // const QString sep( KGlobal::locale()->thousandsSeparator() ); 0196 // if ( !sep.isEmpty() ) 0197 // str2.remove( sep ); 0198 // str2.remove(d->unit.symbol()); 0199 // bool ok; 0200 // const double dbl = KGlobal::locale()->readNumber( str2, &ok ); 0201 //#ifdef DEBUG_VALUEFROMTEXT 0202 // if ( ok ) 0203 // debugWidgets <<"valueFromText:" << str <<": => :" << str2 <<": =>" << QString::number( dbl, 'f', 12 ); 0204 // else 0205 // warnWidgets << "valueFromText error:" << str << ": => :" << str2 << ":"; 0206 //#endif 0207 // return dbl; 0208 }