File indexing completed on 2024-05-12 04:44:32

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 // Own headers
0005 // First the interface, which forces the header to be self-contained.
0006 #include "extendeddoublevalidator.h"
0007 // Second, the private implementation.
0008 #include "extendeddoublevalidator_p.h" // IWYU pragma: associated
0009 
0010 #include "constpropagatinguniquepointer.h"
0011 #include <qstringbuilder.h>
0012 class QObject;
0013 
0014 namespace PerceptualColor
0015 {
0016 /** @brief Default constructor
0017  *  @param parent pointer to the parent widget, if any */
0018 ExtendedDoubleValidator::ExtendedDoubleValidator(QObject *parent)
0019     : QDoubleValidator(parent)
0020     , d_pointer(new ExtendedDoubleValidatorPrivate)
0021 {
0022 }
0023 
0024 /** @brief Destructor */
0025 ExtendedDoubleValidator::~ExtendedDoubleValidator() noexcept
0026 {
0027 }
0028 
0029 // No documentation here (documentation of properties
0030 // and its getters are in the header)
0031 QString ExtendedDoubleValidator::prefix() const
0032 {
0033     return d_pointer->m_prefix;
0034 }
0035 
0036 /** @brief Set the @ref prefix property. */
0037 void ExtendedDoubleValidator::setPrefix(const QString &prefix)
0038 {
0039     if (prefix != d_pointer->m_prefix) {
0040         d_pointer->m_prefix = prefix;
0041         Q_EMIT prefixChanged(prefix);
0042     }
0043 }
0044 
0045 /** @brief Set the @ref suffix property. */
0046 void ExtendedDoubleValidator::setSuffix(const QString &suffix)
0047 {
0048     if (suffix != d_pointer->m_suffix) {
0049         d_pointer->m_suffix = suffix;
0050         Q_EMIT suffixChanged(suffix);
0051     }
0052 }
0053 
0054 // No documentation here (documentation of properties
0055 // and its getters are in the header)
0056 QString ExtendedDoubleValidator::suffix() const
0057 {
0058     return d_pointer->m_suffix;
0059 }
0060 
0061 QValidator::State ExtendedDoubleValidator::validate(QString &input, int &pos) const
0062 {
0063     QString myInput = input;
0064     int myPos = pos;
0065 
0066     // IF (m_prefix.isEmpty && !m_prefix.isNull)
0067     // THEN input.startsWith(m_prefix)
0068     // →  will be true IF !input.isEmpty
0069     // →  will be false IF input.isEmpty
0070     // This is inconsistent. Therefore, we test is m_prefix is empty.
0071     // If not, we do nothing.
0072     // The same also applies to suffix.
0073     // TODO Bug report, because Qt documentation says at
0074     // https://doc.qt.io/qt-6/qstring.html#distinction-between-null-and-empty-strings
0075     // (and at its Qt-5-counterpart):
0076     //     “All functions except isNull() treat null strings the same
0077     //      as empty strings.”
0078     // This is apparently wrong (at least for Qt 5).
0079     if (!d_pointer->m_prefix.isEmpty()) {
0080         if (myInput.startsWith(d_pointer->m_prefix)) {
0081             myInput.remove(0, d_pointer->m_prefix.size());
0082             // In Qt6, QString::size() returns a qsizetype aka “long long int”.
0083             // HACK We do a simple static_cast because a so long QString isn’t
0084             // useful anyway.
0085             myPos -= static_cast<int>(d_pointer->m_prefix.size());
0086         } else {
0087             return QValidator::State::Invalid;
0088         }
0089     }
0090     if (!d_pointer->m_suffix.isEmpty()) {
0091         if (myInput.endsWith(d_pointer->m_suffix)) {
0092             myInput.chop(d_pointer->m_suffix.size());
0093         } else {
0094             return QValidator::State::Invalid;
0095         }
0096     }
0097 
0098     QValidator::State result = QDoubleValidator::validate(myInput, myPos);
0099     // Following the Qt documentation, QValidator::validate() is allowed
0100     // and indented to make changes to the arguments passed by reference
0101     // (“input” and “pos”). However, we use its child class QDoubleValidator.
0102     // The documentation of QDoubleValidator states that the “pos” argument
0103     // is not used. Therefore, write back only the “input” argument.
0104     input = d_pointer->m_prefix + myInput + d_pointer->m_suffix;
0105 
0106     return result;
0107 }
0108 
0109 } // namespace PerceptualColor