src/gui/widgets/qspinbox.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    63 
    63 
    64 class QSpinBoxPrivate : public QAbstractSpinBoxPrivate
    64 class QSpinBoxPrivate : public QAbstractSpinBoxPrivate
    65 {
    65 {
    66     Q_DECLARE_PUBLIC(QSpinBox)
    66     Q_DECLARE_PUBLIC(QSpinBox)
    67 public:
    67 public:
    68     QSpinBoxPrivate(QWidget *parent = 0);
    68     QSpinBoxPrivate();
    69     void emitSignals(EmitPolicy ep, const QVariant &);
    69     void emitSignals(EmitPolicy ep, const QVariant &);
    70 
    70 
    71     virtual QVariant valueFromText(const QString &n) const;
    71     virtual QVariant valueFromText(const QString &n) const;
    72     virtual QString textFromValue(const QVariant &n) const;
    72     virtual QString textFromValue(const QVariant &n) const;
    73     QVariant validateAndInterpret(QString &input, int &pos,
    73     QVariant validateAndInterpret(QString &input, int &pos,
    74                                   QValidator::State &state) const;
    74                                   QValidator::State &state) const;
    75     QChar thousand;
       
    76 
    75 
    77     inline void init() {
    76     inline void init() {
    78         Q_Q(QSpinBox);
    77         Q_Q(QSpinBox);
    79         q->setInputMethodHints(Qt::ImhDigitsOnly);
    78         q->setInputMethodHints(Qt::ImhDigitsOnly);
    80         setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
    79         setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
    83 
    82 
    84 class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate
    83 class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate
    85 {
    84 {
    86     Q_DECLARE_PUBLIC(QDoubleSpinBox)
    85     Q_DECLARE_PUBLIC(QDoubleSpinBox)
    87 public:
    86 public:
    88     QDoubleSpinBoxPrivate(QWidget *parent = 0);
    87     QDoubleSpinBoxPrivate();
    89     void emitSignals(EmitPolicy ep, const QVariant &);
    88     void emitSignals(EmitPolicy ep, const QVariant &);
    90 
    89 
    91     virtual QVariant valueFromText(const QString &n) const;
    90     virtual QVariant valueFromText(const QString &n) const;
    92     virtual QString textFromValue(const QVariant &n) const;
    91     virtual QString textFromValue(const QVariant &n) const;
    93     QVariant validateAndInterpret(QString &input, int &pos,
    92     QVariant validateAndInterpret(QString &input, int &pos,
    94                                   QValidator::State &state) const;
    93                                   QValidator::State &state) const;
    95     double round(double input) const;
    94     double round(double input) const;
    96     // variables
    95     // variables
    97     int decimals;
    96     int decimals;
    98     QChar delimiter, thousand;
       
    99 
    97 
   100     inline void init() {
    98     inline void init() {
   101         Q_Q(QDoubleSpinBox);
    99         Q_Q(QDoubleSpinBox);
   102         q->setInputMethodHints(Qt::ImhFormattedNumbersOnly);
   100         q->setInputMethodHints(Qt::ImhFormattedNumbersOnly);
   103     }
   101     }
   199 
   197 
   200     \sa setMinimum(), setMaximum(), setSingleStep()
   198     \sa setMinimum(), setMaximum(), setSingleStep()
   201 */
   199 */
   202 
   200 
   203 QSpinBox::QSpinBox(QWidget *parent)
   201 QSpinBox::QSpinBox(QWidget *parent)
   204     : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
   202     : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
   205 {
   203 {
   206     Q_D(QSpinBox);
   204     Q_D(QSpinBox);
   207     d->init();
   205     d->init();
   208 }
   206 }
   209 
   207 
   211 /*!
   209 /*!
   212     Use one of the constructors that doesn't take the \a name
   210     Use one of the constructors that doesn't take the \a name
   213     argument and then use setObjectName() instead.
   211     argument and then use setObjectName() instead.
   214 */
   212 */
   215 QSpinBox::QSpinBox(QWidget *parent, const char *name)
   213 QSpinBox::QSpinBox(QWidget *parent, const char *name)
   216     : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
   214     : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
   217 {
   215 {
   218     Q_D(QSpinBox);
   216     Q_D(QSpinBox);
   219     setObjectName(QString::fromAscii(name));
   217     setObjectName(QString::fromAscii(name));
   220     d->init();
   218     d->init();
   221 }
   219 }
   223 /*!
   221 /*!
   224     Use one of the constructors that doesn't take the \a name
   222     Use one of the constructors that doesn't take the \a name
   225     argument and then use setObjectName() instead.
   223     argument and then use setObjectName() instead.
   226 */
   224 */
   227 QSpinBox::QSpinBox(int minimum, int maximum, int step, QWidget *parent, const char *name)
   225 QSpinBox::QSpinBox(int minimum, int maximum, int step, QWidget *parent, const char *name)
   228     : QAbstractSpinBox(*new QSpinBoxPrivate(parent), parent)
   226     : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
   229 {
   227 {
   230     Q_D(QSpinBox);
   228     Q_D(QSpinBox);
   231     d->minimum = QVariant(qMin<int>(minimum, maximum));
   229     d->minimum = QVariant(qMin<int>(minimum, maximum));
   232     d->maximum = QVariant(qMax<int>(minimum, maximum));
   230     d->maximum = QVariant(qMax<int>(minimum, maximum));
   233     d->singleStep = QVariant(step);
   231     d->singleStep = QVariant(step);
   462     \sa valueFromText(), validate()
   460     \sa valueFromText(), validate()
   463 */
   461 */
   464 
   462 
   465 QString QSpinBox::textFromValue(int value) const
   463 QString QSpinBox::textFromValue(int value) const
   466 {
   464 {
   467     Q_D(const QSpinBox);
       
   468     QString str = locale().toString(value);
   465     QString str = locale().toString(value);
   469     if (qAbs(value) >= 1000 || value == INT_MIN) {
   466     if (qAbs(value) >= 1000 || value == INT_MIN) {
   470         str.remove(d->thousand);
   467         str.remove(locale().groupSeparator());
   471     }
   468     }
   472 
   469 
   473     return str;
   470     return str;
   474 }
   471 }
   475 
   472 
   514 /*!
   511 /*!
   515   \reimp
   512   \reimp
   516 */
   513 */
   517 void QSpinBox::fixup(QString &input) const
   514 void QSpinBox::fixup(QString &input) const
   518 {
   515 {
   519     Q_D(const QSpinBox);
   516     input.remove(locale().groupSeparator());
   520 
       
   521     input.remove(d->thousand);
       
   522 }
   517 }
   523 
   518 
   524 
   519 
   525 // --- QDoubleSpinBox ---
   520 // --- QDoubleSpinBox ---
   526 
   521 
   598     initially set to 0.00. The spin box has the given \a parent.
   593     initially set to 0.00. The spin box has the given \a parent.
   599 
   594 
   600     \sa setMinimum(), setMaximum(), setSingleStep()
   595     \sa setMinimum(), setMaximum(), setSingleStep()
   601 */
   596 */
   602 QDoubleSpinBox::QDoubleSpinBox(QWidget *parent)
   597 QDoubleSpinBox::QDoubleSpinBox(QWidget *parent)
   603     : QAbstractSpinBox(*new QDoubleSpinBoxPrivate(parent), parent)
   598     : QAbstractSpinBox(*new QDoubleSpinBoxPrivate, parent)
   604 {
   599 {
   605     Q_D(QDoubleSpinBox);
   600     Q_D(QDoubleSpinBox);
   606     d->init();
   601     d->init();
   607 }
   602 }
   608 
   603 
   873 QString QDoubleSpinBox::textFromValue(double value) const
   868 QString QDoubleSpinBox::textFromValue(double value) const
   874 {
   869 {
   875     Q_D(const QDoubleSpinBox);
   870     Q_D(const QDoubleSpinBox);
   876     QString str = locale().toString(value, 'f', d->decimals);
   871     QString str = locale().toString(value, 'f', d->decimals);
   877     if (qAbs(value) >= 1000.0) {
   872     if (qAbs(value) >= 1000.0) {
   878         str.remove(d->thousand);
   873         str.remove(locale().groupSeparator());
   879     }
   874     }
   880     return str;
   875     return str;
   881 }
   876 }
   882 
   877 
   883 /*!
   878 /*!
   918 /*!
   913 /*!
   919   \reimp
   914   \reimp
   920 */
   915 */
   921 void QDoubleSpinBox::fixup(QString &input) const
   916 void QDoubleSpinBox::fixup(QString &input) const
   922 {
   917 {
   923     Q_D(const QDoubleSpinBox);
   918     input.remove(locale().groupSeparator());
   924 
       
   925     input.remove(d->thousand);
       
   926 }
   919 }
   927 
   920 
   928 // --- QSpinBoxPrivate ---
   921 // --- QSpinBoxPrivate ---
   929 
   922 
   930 /*!
   923 /*!
   931     \internal
   924     \internal
   932     Constructs a QSpinBoxPrivate object
   925     Constructs a QSpinBoxPrivate object
   933 */
   926 */
   934 
   927 
   935 QSpinBoxPrivate::QSpinBoxPrivate(QWidget *parent)
   928 QSpinBoxPrivate::QSpinBoxPrivate()
   936 {
   929 {
   937     minimum = QVariant((int)0);
   930     minimum = QVariant((int)0);
   938     maximum = QVariant((int)99);
   931     maximum = QVariant((int)99);
   939     value = minimum;
   932     value = minimum;
   940     singleStep = QVariant((int)1);
   933     singleStep = QVariant((int)1);
   941     type = QVariant::Int;
   934     type = QVariant::Int;
   942     const QString str = (parent ? parent->locale() : QLocale()).toString(4567);
       
   943     if (str.size() == 5) {
       
   944         thousand = QChar(str.at(1));
       
   945     }
       
   946 
       
   947 }
   935 }
   948 
   936 
   949 /*!
   937 /*!
   950     \internal
   938     \internal
   951     \reimp
   939     \reimp
  1017         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
  1005         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
  1018     } else if (copy.startsWith(QLatin1Char('-')) && min >= 0) {
  1006     } else if (copy.startsWith(QLatin1Char('-')) && min >= 0) {
  1019         state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100
  1007         state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100
  1020     } else {
  1008     } else {
  1021         bool ok = false;
  1009         bool ok = false;
  1022         bool removedThousand = false;
       
  1023         num = locale.toInt(copy, &ok, 10);
  1010         num = locale.toInt(copy, &ok, 10);
  1024         if (!ok && copy.contains(thousand) && (max >= 1000 || min <= -1000)) {
  1011         if (!ok && copy.contains(locale.groupSeparator()) && (max >= 1000 || min <= -1000)) {
  1025             const int s = copy.size();
  1012             QString copy2 = copy;
  1026             copy.remove(thousand);
  1013             copy2.remove(locale.groupSeparator());
  1027             pos = qMax(0, pos - (s - copy.size()));
  1014             num = locale.toInt(copy2, &ok, 10);
  1028             removedThousand = true;
       
  1029             num = locale.toInt(copy, &ok, 10);
       
  1030         }
  1015         }
  1031         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
  1016         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
  1032         if (!ok) {
  1017         if (!ok) {
  1033             state = QValidator::Invalid;
  1018             state = QValidator::Invalid;
  1034         } else if (num >= min && num <= max) {
  1019         } else if (num >= min && num <= max) {
  1035             state = removedThousand ? QValidator::Intermediate : QValidator::Acceptable;
  1020             state = QValidator::Acceptable;
  1036         } else if (max == min) {
  1021         } else if (max == min) {
  1037             state = QValidator::Invalid;
  1022             state = QValidator::Invalid;
  1038         } else {
  1023         } else {
  1039             if ((num >= 0 && num > max) || (num < 0 && num < min)) {
  1024             if ((num >= 0 && num > max) || (num < 0 && num < min)) {
  1040                 state = QValidator::Invalid;
  1025                 state = QValidator::Invalid;
  1062 /*!
  1047 /*!
  1063     \internal
  1048     \internal
  1064     Constructs a QSpinBoxPrivate object
  1049     Constructs a QSpinBoxPrivate object
  1065 */
  1050 */
  1066 
  1051 
  1067 QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate(QWidget *parent)
  1052 QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate()
  1068 {
  1053 {
  1069     minimum = QVariant(0.0);
  1054     minimum = QVariant(0.0);
  1070     maximum = QVariant(99.99);
  1055     maximum = QVariant(99.99);
  1071     value = minimum;
  1056     value = minimum;
  1072     singleStep = QVariant(1.0);
  1057     singleStep = QVariant(1.0);
  1073     decimals = 2;
  1058     decimals = 2;
  1074     type = QVariant::Double;
  1059     type = QVariant::Double;
  1075     const QString str = (parent ? parent->locale() : QLocale()).toString(4567.1);
       
  1076     if (str.size() == 6) {
       
  1077         delimiter = str.at(4);
       
  1078         thousand = QChar((ushort)0);
       
  1079     } else if (str.size() == 7) {
       
  1080         thousand = str.at(1);
       
  1081         delimiter = str.at(5);
       
  1082     }
       
  1083     Q_ASSERT(!delimiter.isNull());
       
  1084 }
  1060 }
  1085 
  1061 
  1086 /*!
  1062 /*!
  1087     \internal
  1063     \internal
  1088     \reimp
  1064     \reimp
  1153     switch (len) {
  1129     switch (len) {
  1154     case 0:
  1130     case 0:
  1155         state = max != min ? QValidator::Intermediate : QValidator::Invalid;
  1131         state = max != min ? QValidator::Intermediate : QValidator::Invalid;
  1156         goto end;
  1132         goto end;
  1157     case 1:
  1133     case 1:
  1158         if (copy.at(0) == delimiter
  1134         if (copy.at(0) == locale.decimalPoint()
  1159             || (plus && copy.at(0) == QLatin1Char('+'))
  1135             || (plus && copy.at(0) == QLatin1Char('+'))
  1160             || (minus && copy.at(0) == QLatin1Char('-'))) {
  1136             || (minus && copy.at(0) == QLatin1Char('-'))) {
  1161             state = QValidator::Intermediate;
  1137             state = QValidator::Intermediate;
  1162             goto end;
  1138             goto end;
  1163         }
  1139         }
  1164         break;
  1140         break;
  1165     case 2:
  1141     case 2:
  1166         if (copy.at(1) == delimiter
  1142         if (copy.at(1) == locale.decimalPoint()
  1167             && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) {
  1143             && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) {
  1168             state = QValidator::Intermediate;
  1144             state = QValidator::Intermediate;
  1169             goto end;
  1145             goto end;
  1170         }
  1146         }
  1171         break;
  1147         break;
  1172     default: break;
  1148     default: break;
  1173     }
  1149     }
  1174 
  1150 
  1175     if (copy.at(0) == thousand) {
  1151     if (copy.at(0) == locale.groupSeparator()) {
  1176         QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1152         QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1177         state = QValidator::Invalid;
  1153         state = QValidator::Invalid;
  1178         goto end;
  1154         goto end;
  1179     } else if (len > 1) {
  1155     } else if (len > 1) {
  1180         const int dec = copy.indexOf(delimiter);
  1156         const int dec = copy.indexOf(locale.decimalPoint());
  1181         if (dec != -1) {
  1157         if (dec != -1) {
  1182             if (dec + 1 < copy.size() && copy.at(dec + 1) == delimiter && pos == dec + 1) {
  1158             if (dec + 1 < copy.size() && copy.at(dec + 1) == locale.decimalPoint() && pos == dec + 1) {
  1183                 copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter
  1159                 copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter
  1184             } // should be treated as typing right arrow
  1160             } // should be treated as typing right arrow
  1185 
  1161 
  1186             if (copy.size() - dec > decimals + 1) {
  1162             if (copy.size() - dec > decimals + 1) {
  1187                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1163                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1188                 state = QValidator::Invalid;
  1164                 state = QValidator::Invalid;
  1189                 goto end;
  1165                 goto end;
  1190             }
  1166             }
  1191             for (int i=dec + 1; i<copy.size(); ++i) {
  1167             for (int i=dec + 1; i<copy.size(); ++i) {
  1192                 if (copy.at(i).isSpace() || copy.at(i) == thousand) {
  1168                 if (copy.at(i).isSpace() || copy.at(i) == locale.groupSeparator()) {
  1193                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1169                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1194                     state = QValidator::Invalid;
  1170                     state = QValidator::Invalid;
  1195                     goto end;
  1171                     goto end;
  1196                 }
  1172                 }
  1197             }
  1173             }
  1198         } else {
  1174         } else {
  1199             const QChar &last = copy.at(len - 1);
  1175             const QChar &last = copy.at(len - 1);
  1200             const QChar &secondLast = copy.at(len - 2);
  1176             const QChar &secondLast = copy.at(len - 2);
  1201             if ((last == thousand || last.isSpace())
  1177             if ((last == locale.groupSeparator() || last.isSpace())
  1202                 && (secondLast == thousand || secondLast.isSpace())) {
  1178                 && (secondLast == locale.groupSeparator() || secondLast.isSpace())) {
  1203                 state = QValidator::Invalid;
  1179                 state = QValidator::Invalid;
  1204                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1180                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1205                 goto end;
  1181                 goto end;
  1206             } else if (last.isSpace() && (!thousand.isSpace() || secondLast.isSpace())) {
  1182             } else if (last.isSpace() && (!locale.groupSeparator().isSpace() || secondLast.isSpace())) {
  1207                 state = QValidator::Invalid;
  1183                 state = QValidator::Invalid;
  1208                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1184                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1209                 goto end;
  1185                 goto end;
  1210             }
  1186             }
  1211         }
  1187         }
  1213 
  1189 
  1214     {
  1190     {
  1215         bool ok = false;
  1191         bool ok = false;
  1216         num = locale.toDouble(copy, &ok);
  1192         num = locale.toDouble(copy, &ok);
  1217         QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok;
  1193         QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok;
  1218         bool notAcceptable = false;
       
  1219 
  1194 
  1220         if (!ok) {
  1195         if (!ok) {
  1221             if (thousand.isPrint()) {
  1196             if (locale.groupSeparator().isPrint()) {
  1222                 if (max < 1000 && min > -1000 && copy.contains(thousand)) {
  1197                 if (max < 1000 && min > -1000 && copy.contains(locale.groupSeparator())) {
  1223                     state = QValidator::Invalid;
  1198                     state = QValidator::Invalid;
  1224                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1199                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1225                     goto end;
  1200                     goto end;
  1226                 }
  1201                 }
  1227 
  1202 
  1228                 const int len = copy.size();
  1203                 const int len = copy.size();
  1229                 for (int i=0; i<len- 1; ++i) {
  1204                 for (int i=0; i<len- 1; ++i) {
  1230                     if (copy.at(i) == thousand && copy.at(i + 1) == thousand) {
  1205                     if (copy.at(i) == locale.groupSeparator() && copy.at(i + 1) == locale.groupSeparator()) {
  1231                         QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1206                         QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1232                         state = QValidator::Invalid;
  1207                         state = QValidator::Invalid;
  1233                         goto end;
  1208                         goto end;
  1234                     }
  1209                     }
  1235                 }
  1210                 }
  1236 
  1211 
  1237                 const int s = copy.size();
  1212                 QString copy2 = copy;
  1238                 copy.remove(thousand);
  1213                 copy2.remove(locale.groupSeparator());
  1239                 pos = qMax(0, pos - (s - copy.size()));
  1214                 num = locale.toDouble(copy2, &ok);
  1240 
  1215                 QSBDEBUG() << locale.groupSeparator() << num << copy2 << ok;
  1241 
       
  1242                 num = locale.toDouble(copy, &ok);
       
  1243                 QSBDEBUG() << thousand << num << copy << ok;
       
  1244 
  1216 
  1245                 if (!ok) {
  1217                 if (!ok) {
  1246                     state = QValidator::Invalid;
  1218                     state = QValidator::Invalid;
  1247                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1219                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1248                     goto end;
  1220                     goto end;
  1249                 }
  1221                 }
  1250                 notAcceptable = true;
       
  1251             }
  1222             }
  1252         }
  1223         }
  1253 
  1224 
  1254         if (!ok) {
  1225         if (!ok) {
  1255             state = QValidator::Invalid;
  1226             state = QValidator::Invalid;
  1256             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1227             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1257         } else if (num >= min && num <= max) {
  1228         } else if (num >= min && num <= max) {
  1258             state = notAcceptable ? QValidator::Intermediate : QValidator::Acceptable;
  1229             state = QValidator::Acceptable;
  1259             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to "
  1230             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Acceptable";
  1260                        << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable");
       
  1261         } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
  1231         } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
  1262             state = QValidator::Invalid;
  1232             state = QValidator::Invalid;
  1263             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1233             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
  1264         } else {
  1234         } else {
  1265             if ((num >= 0 && num > max) || (num < 0 && num < min)) {
  1235             if ((num >= 0 && num > max) || (num < 0 && num < min)) {