File indexing completed on 2024-04-28 05:50:09

0001 /*
0002  * SPDX-License-Identifier: GPL-3.0-or-later
0003  * SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
0004  */
0005 
0006 #include "countervalidator.h"
0007 
0008 #include "util.h"
0009 
0010 namespace validators
0011 {
0012     std::optional<qulonglong> parseUnsignedInteger(const QString &input, const QLocale &locale)
0013     {
0014         bool ok = false;
0015 
0016         auto v = locale.toULongLong(input, &ok);
0017         if (ok) {
0018             return std::optional<qulonglong>(v);
0019         } else {
0020             /*
0021              * Fall back to parsing according to C locale for better UX.
0022              * This simplifies copy-pasting from websites which may be a bit
0023              * biased towards the Anglosphere.
0024              */
0025             const QLocale c = QLocale::c();
0026             v = c.toULongLong(input, &ok);
0027             return ok ? std::optional<qulonglong>(v) : std::nullopt;
0028         }
0029     }
0030 
0031     UnsignedLongValidator::UnsignedLongValidator(QObject *parent):
0032         QValidator(parent)
0033     {
0034     }
0035 
0036     void UnsignedLongValidator::fixup(QString &input) const
0037     {
0038         /*
0039          * First of all: simplify the input to get rid of 'fluff' such as
0040          * digit group separators in partial input. E.g. if the user wants
0041          * to type the value 123456 then partial input might become "123,4"
0042          * at some point which would be invalid.
0043          */
0044         const QLocale l = locale();
0045         const auto c = l.groupSeparator();
0046         QString fixed = input.replace(c, QLatin1String(""));
0047         fixed = validators::strip_spaces(fixed);
0048 
0049         /*
0050          * Normalise to locale's preferred formatting if possible
0051          * I.e. if valid, re-instate any decorative fluff like digit group
0052          * separators depending on the locale.
0053          *
0054          * This may also involve switching from Latin script (C locale) to
0055          * whatever script the configured locale uses natively.
0056          */
0057         const auto v = parseUnsignedInteger(fixed, l);
0058         if (v) {
0059             fixed = l.toString(v.value());
0060         }
0061 
0062         input = fixed;
0063     }
0064 
0065     QValidator::State UnsignedLongValidator::validate(QString &input, int &cursor) const
0066     {
0067         Q_UNUSED(cursor);
0068         // Avoid a hard error on empty string.
0069         if (input.size() == 0) {
0070             return QValidator::Intermediate;
0071         } else {
0072 
0073             const QLocale l = locale();
0074             const auto parsed = parseUnsignedInteger(input, l);
0075 
0076             /*
0077              * The actual value is a don't care at this point.
0078              * All that matters is the input can be parsed
0079              */
0080             return parsed ? QValidator::Acceptable : QValidator::Invalid;
0081         }
0082     }
0083 }