QColorDialog: Support hex rgb values with and without leading #

QColorDialog supports entering hex rgb values only with a leading #.
That makes copy/paste impossible whenever the copy source has plain
hex, without the leading #.

This patch automatically adds a leading # character, when missing.
As a drive-by, QObject::connect statements are altered to PTMF syntax,
amending 9eb1b9e86ce3d1004e39e8ab7c7ecb6796d6df1a.

The patch also adds an autotest for the new functionality.

Fixes: QTBUG-111742
Pick-to: 6.5
Change-Id: I4ced29dc8b543457f411a3fa0ac756b550cdb09f
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Axel Spoerl 2023-03-09 17:10:40 +01:00
parent f03fedfaec
commit b04f9388ac
2 changed files with 75 additions and 11 deletions

View File

@ -1180,8 +1180,8 @@ QColorShower::QColorShower(QColorDialog *parent)
#else
gl->addWidget(lab, 0, 0, 1, -1);
#endif
connect(lab, SIGNAL(colorDropped(QRgb)), this, SIGNAL(newCol(QRgb)));
connect(lab, SIGNAL(colorDropped(QRgb)), this, SLOT(setRgb(QRgb)));
connect(lab, &QColorShowLabel::colorDropped, this, &QColorShower::newCol);
connect(lab, &QColorShowLabel::colorDropped, this, &QColorShower::setRgb);
hEd = new QColSpinBox(this);
hEd->setRange(0, 359);
@ -1285,12 +1285,13 @@ QColorShower::QColorShower(QColorDialog *parent)
alphaLab->hide();
lblHtml = new QLabel(this);
htEd = new QLineEdit(this);
htEd->setObjectName("qt_colorname_lineedit");
#ifndef QT_NO_SHORTCUT
lblHtml->setBuddy(htEd);
#endif
#if QT_CONFIG(regularexpression)
QRegularExpression regExp(QStringLiteral("#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"));
QRegularExpression regExp(QStringLiteral("#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"));
QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
htEd->setValidator(validator);
#else
@ -1307,15 +1308,15 @@ QColorShower::QColorShower(QColorDialog *parent)
gl->addWidget(htEd, 5, 2, 1, /*colspan=*/ 3);
#endif
connect(hEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
connect(sEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
connect(vEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
connect(hEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
connect(sEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
connect(vEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
connect(rEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
connect(gEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
connect(bEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
connect(alphaEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
connect(htEd, SIGNAL(textEdited(QString)), this, SLOT(htmlEd()));
connect(rEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(gEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(bEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(alphaEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(htEd, &QLineEdit::textChanged, this, &QColorShower::htmlEd);
retranslateStrings();
}
@ -1384,9 +1385,19 @@ void QColorShower::hsvEd()
void QColorShower::htmlEd()
{
QString t = htEd->text();
if (t.isEmpty())
return;
if (!t.startsWith(QStringLiteral("#"))) {
t = QStringLiteral("#") + t;
QSignalBlocker blocker(htEd);
htEd->setText(t);
}
QColor c = QColor::fromString(t);
if (!c.isValid())
return;
curCol = qRgba(c.red(), c.green(), c.blue(), currentAlpha());
rgb2hsv(curCol, hue, sat, val);

View File

@ -5,6 +5,8 @@
#include <QTest>
#include <QtGui/QtGui>
#include <QtWidgets/QColorDialog>
#include <QtWidgets/QLineEdit>
#include <QSignalSpy>
QT_FORWARD_DECLARE_CLASS(QtTestEventThread)
@ -25,6 +27,8 @@ private slots:
void native_activeModalWidget();
void task247349_alpha();
void QTBUG_43548_initialColor();
void hexColor_data();
void hexColor();
};
class TestNativeDialog : public QColorDialog
@ -126,5 +130,54 @@ void tst_QColorDialog::QTBUG_43548_initialColor()
QCOMPARE(a, dialog.currentColor());
}
void tst_QColorDialog::hexColor_data()
{
QTest::addColumn<const QString>("colorString");
QTest::addColumn<const QString>("expectedHexColor");
QTest::addColumn<const int>("expectedSignalCount");
QTest::newRow("White-#") << "#FFFFFE" << "#FFFFFE" << 1;
QTest::newRow("White") << "FFFFFD" << "#FFFFFD" << 1;
QTest::newRow("Blue-#") << "#77fffb" << "#77fffb" << 2;
QTest::newRow("Blue") << "77fffa" << "#77fffa" << 2;
}
void tst_QColorDialog::hexColor()
{
QColorDialog dialog;
dialog.setOption(QColorDialog::DontUseNativeDialog);
dialog.show();
QVERIFY(QTest::qWaitForWindowExposed(&dialog));
QLineEdit *lineEdit = dialog.findChild<QLineEdit *>("qt_colorname_lineedit",
Qt::FindChildrenRecursively);
QVERIFY2(lineEdit, "QLineEdit for color not found. Adapt this test.");
QVERIFY(lineEdit); // eliminate compiler warning
QFETCH(const QString, colorString);
QFETCH(const QString, expectedHexColor);
QFETCH(const int, expectedSignalCount);
QSignalSpy spy(&dialog, &QColorDialog::currentColorChanged);
// Delete existing color
lineEdit->activateWindow();
QVERIFY(QTest::qWaitForWindowActive(lineEdit));
for (int i = 0; i < 8; ++i)
QTest::keyEvent(QTest::KeyAction::Click, lineEdit, Qt::Key_Backspace);
QVERIFY(lineEdit->text().isEmpty());
// Enter new color
for (const QChar &key : colorString)
QTest::keyEvent(QTest::KeyAction::Click, lineEdit, key.toLatin1());
QCOMPARE(lineEdit->text().toLower(), expectedHexColor.toLower());
// Consume all color change signals
QTRY_COMPARE(spy.count(), expectedSignalCount);
const QColor color = qvariant_cast<QColor>(spy.last().at(0));
QCOMPARE(color.name(QColor::HexRgb), expectedHexColor.toLower());
}
QTEST_MAIN(tst_QColorDialog)
#include "tst_qcolordialog.moc"