Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added removal of trailing zeros for Text input field #25782

Merged
merged 2 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/framework/uicomponents/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ if (MUSE_MODULE_UI_DISABLE_MODALITY)
endif()

set(MODULE_USE_UNITY OFF)

setup_module()

if (MUSE_MODULE_UI_TESTS)
add_subdirectory(tests)
endif()


Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,12 @@ FocusScope {
event.accepted = false

root.focus = false
root.textEditingFinished(valueInput.text)
}
}

Keys.onPressed: function(event) {
var isAcceptKey = event.key === Qt.Key_Enter || event.key === Qt.Key_Return
var isEscapeKey = event.key === Qt.Key_Escape
if (isAcceptKey || isEscapeKey) {
root.textEditingFinished(valueInput.text)
}

if (isAcceptKey) {
root.accepted()
Expand All @@ -227,7 +223,6 @@ FocusScope {
selectAll()
} else {
deselect()
root.textEditingFinished(valueInput.text)
}
}

Expand All @@ -246,6 +241,10 @@ FocusScope {

root.textEdited(text)
}

onEditingFinished: {
root.textEditingFinished(valueInput.text)
}
}

StyledTextLabel {
Expand Down
31 changes: 31 additions & 0 deletions src/framework/uicomponents/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-3.0-only
# MuseScore-CLA-applies
#
# MuseScore
# Music Composition & Notation
#
# Copyright (C) 2021 MuseScore BVBA and others
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

set(MODULE_TEST muse_uicomponents_tests)

set(MODULE_TEST_SRC
${CMAKE_CURRENT_LIST_DIR}/doubleinputvalidator_tests.cpp
)

set(MODULE_TEST_LINK
muse_uicomponents
)

include(SetupGTest)
90 changes: 90 additions & 0 deletions src/framework/uicomponents/tests/doubleinputvalidator_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2024 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>

#include "uicomponents/view/validators/doubleinputvalidator.h"

using namespace muse;
using namespace muse::uicomponents;

namespace muse::uicomponents {
class DoubleInputValidatorTests : public ::testing::Test, public QObject
{
public:
void SetUp() override
{
m_validator = new DoubleInputValidator(nullptr);
m_validator->setTop(100.0);
m_validator->setBottom(-100.0);
m_validator->setDecimal(2);
}

void TearDown() override
{
delete m_validator;
}

protected:
DoubleInputValidator* m_validator = nullptr;
};

TEST_F(DoubleInputValidatorTests, Validate) {
struct Input
{
QString str;
QValidator::State expectedState;
QString fixedStr;
};

std::vector<Input> validInputs = {
{ "-0.1", QValidator::Acceptable },
{ "0", QValidator::Acceptable },
{ "1.23", QValidator::Acceptable },
{ "99.99", QValidator::Acceptable },
{ "-100", QValidator::Acceptable },
{ "2.5", QValidator::Acceptable },
{ "0.0", QValidator::Intermediate, "0" },
{ "00.", QValidator::Intermediate, "0" },
{ "2.00", QValidator::Intermediate, "2" },
{ "2.", QValidator::Intermediate, "2" },
{ "-100.1", QValidator::Intermediate, "-100" },
{ "100.1", QValidator::Intermediate, "100" },
{ "1.123", QValidator::Intermediate, "1.12" },
{ "abc", QValidator::Invalid, "" }
};

int pos = 0;
for (Input& input : validInputs) {
EXPECT_EQ(m_validator->validate(input.str, pos), input.expectedState);

if (QValidator::Invalid == input.expectedState) {
continue;
}

QString fixInput = input.str;
m_validator->fixup(fixInput);

QString expectedStr = QValidator::Acceptable == input.expectedState ? input.str : input.fixedStr;
EXPECT_EQ(expectedStr, fixInput);
}
}
}
60 changes: 40 additions & 20 deletions src/framework/uicomponents/view/validators/doubleinputvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,67 +31,87 @@ DoubleInputValidator::DoubleInputValidator(QObject* parent)

void DoubleInputValidator::fixup(QString& string) const
{
auto zeros = [](int num)->QString {
QString s = QString();
for (int i = 0; i < num; i++) {
s.append("0");
auto removeTrailingZeros = [](QString& str) {
if (str.isEmpty()) {
return;
}
return s;
};

if (!string.contains(".")) {
string.append("." + zeros(m_decimal));
}
if (!str.contains('.')) {
return;
}

size_t num = str.size();
for (size_t i = num - 1; i > 0; i--) {
Eism marked this conversation as resolved.
Show resolved Hide resolved
if (str[i] == '0') {
str.remove(i, 1);
} else if (str[i] == '.') {
str.remove(i, 1);
break;
} else {
break;
}
}
};

if (string.startsWith(".")) {
string.prepend("0");
}

if (string.endsWith(".")) {
string.append(zeros(m_decimal));
string.remove(string.size() - 1, 1);
}

QStringList strList = string.split(".", Qt::SkipEmptyParts);

QString intPart = strList.at(0);
QString floatPart = strList.at(1);

if (floatPart.length() < m_decimal) {
floatPart.append(zeros(m_decimal - floatPart.length()));
}
QString floatPart = strList.size() > 1 ? strList.at(1) : 0;

if (intPart.contains(QRegularExpression("^0{1,3}$"))) {
intPart = QString("0");
} else if (intPart.contains(QRegularExpression("^\\-0{0,3}$"))) {
intPart = QString("-0");
}

if (intPart == QString("-0") && floatPart == zeros(m_decimal)) {
if (intPart == QString("-0") && floatPart.isEmpty()) {
intPart = QString("0");
}

if (floatPart.size() > m_decimal) {
floatPart = floatPart.remove(m_decimal, floatPart.size() - m_decimal);
}

string = QString("%1.%2").arg(intPart).arg(floatPart);

if (string.toDouble() > m_top) {
string = QString::number(m_top, 'f', m_decimal);
} else if (string.toDouble() < m_bottom) {
string = QString::number(m_bottom, 'f', m_decimal);
}

removeTrailingZeros(string);
}

QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorPos) const
{
QValidator::State state = Invalid;

if (inputStr.contains(QRegularExpression(QString("^\\-?\\d{1,3}\\.\\d{%1}$").arg(m_decimal)))) {
if (inputStr.contains(QRegularExpression("^\\-?0{2,3}\\."))
|| (inputStr.startsWith("-") && muse::RealIsNull(inputStr.toDouble()))) {
const QRegularExpression validRegex(QString("^\\-?\\d{1,3}(\\.\\d{1,%1})?$").arg(m_decimal));

if (inputStr.contains(validRegex)) {
static const QRegularExpression invalidZeroRegex("^\\-?0{2,3}\\."); // for '-000.'
static const QRegularExpression invalidTrailingZeroRegex("^\\-?\\d+\\.0{1,}$"); // for '1.00'
static const QRegularExpression invalidTrailingDotRegex("^\\-?\\d+\\.$"); // for '1.'

if (inputStr.contains(invalidZeroRegex)
|| (inputStr.startsWith("-") && muse::RealIsNull(inputStr.toDouble())) // for "-000"
|| inputStr.contains(invalidTrailingZeroRegex)
|| inputStr.contains(invalidTrailingDotRegex)) {
state = Intermediate;
} else {
state = Acceptable;
}
} else if (inputStr.contains(QRegularExpression("^\\-?\\d{0,3}\\.?$"))
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}\\.\\d{0,%1}$").arg(m_decimal)))) {
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}\\.\\d{%1,}$").arg(m_decimal)))) {
state = Intermediate;
} else {
cursorPos = 0;
Expand Down