From c78bd937017212c89c1c7aab07399cec5b6b3bdd Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Wed, 20 Nov 2013 15:56:51 +0100 Subject: [PATCH] [Qt] extend validate line edit and btc address validator - remove btc address length from address validator - add an optional btc address check in validated line edit that defaults to off and is used in GUIUtil::setupAddressWidget() - an isAcceptable() check is added to validated line edit on focus out which only kicks in, when a validator is used with that widget - remove an isAcceptable() check from sendcoinsentry.cpp - remove obsolete attributes from ui files, which are set by calling GUIUtil::setupAddressWidget() - move some more things to GUIUtil::setupAddressWidget() and remove them from normal code e.g. placeholder text --- src/qt/bitcoinaddressvalidator.cpp | 58 +++++++++++++++--------- src/qt/bitcoinaddressvalidator.h | 22 ++++++--- src/qt/forms/editaddressdialog.ui | 9 +++- src/qt/forms/signverifymessagedialog.ui | 6 --- src/qt/guiutil.cpp | 12 +++-- src/qt/guiutil.h | 3 +- src/qt/qvalidatedlineedit.cpp | 60 ++++++++++++++++++++++++- src/qt/qvalidatedlineedit.h | 7 ++- src/qt/sendcoinsdialog.cpp | 9 +--- src/qt/sendcoinsentry.cpp | 4 +- src/qt/signverifymessagedialog.cpp | 5 --- 11 files changed, 140 insertions(+), 55 deletions(-) diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp index 604f24192..293cc168b 100644 --- a/src/qt/bitcoinaddressvalidator.cpp +++ b/src/qt/bitcoinaddressvalidator.cpp @@ -1,9 +1,11 @@ -// Copyright (c) 2011-2013 The Bitcoin developers +// Copyright (c) 2011-2014 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "bitcoinaddressvalidator.h" +#include "base58.h" + /* Base58 characters are: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -11,21 +13,23 @@ - All numbers except for '0' - All upper-case letters except for 'I' and 'O' - All lower-case letters except for 'l' - - User friendly Base58 input can map - - 'l' and 'I' to '1' - - '0' and 'O' to 'o' */ -BitcoinAddressValidator::BitcoinAddressValidator(QObject *parent) : +BitcoinAddressEntryValidator::BitcoinAddressEntryValidator(QObject *parent) : QValidator(parent) { } -QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const +QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &pos) const { + Q_UNUSED(pos); + + // Empty address is "intermediate" input + if (input.isEmpty()) + return QValidator::Intermediate; + // Correction - for(int idx=0; idx= '0' && ch<='9') || - (ch >= 'a' && ch<='z') || - (ch >= 'A' && ch<='Z')) && - ch != 'l' && ch != 'I' && ch != '0' && ch != 'O') + if (((ch >= '0' && ch<='9') || + (ch >= 'a' && ch<='z') || + (ch >= 'A' && ch<='Z')) && + ch != 'l' && ch != 'I' && ch != '0' && ch != 'O') { // Alphanumeric and not a 'forbidden' character } @@ -71,11 +77,21 @@ QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) co } } - // Empty address is "intermediate" input - if(input.isEmpty()) - { - state = QValidator::Intermediate; - } - return state; } + +BitcoinAddressCheckValidator::BitcoinAddressCheckValidator(QObject *parent) : + QValidator(parent) +{ +} + +QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &pos) const +{ + Q_UNUSED(pos); + // Validate the passed Bitcoin address + CBitcoinAddress addr(input.toStdString()); + if (addr.IsValid()) + return QValidator::Acceptable; + + return QValidator::Invalid; +} diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h index 91d248abd..0fb779f7d 100644 --- a/src/qt/bitcoinaddressvalidator.h +++ b/src/qt/bitcoinaddressvalidator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin developers +// Copyright (c) 2011-2014 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,19 +7,29 @@ #include -/** Base58 entry widget validator. - Corrects near-miss characters and refuses characters that are not part of base58. +/** Base58 entry widget validator, checks for valid characters and + * removes some whitespace. */ -class BitcoinAddressValidator : public QValidator +class BitcoinAddressEntryValidator : public QValidator { Q_OBJECT public: - explicit BitcoinAddressValidator(QObject *parent = 0); + explicit BitcoinAddressEntryValidator(QObject *parent); State validate(QString &input, int &pos) const; +}; - static const int MaxAddressLength = 35; +/** Bitcoin address widget validator, checks for a valid bitcoin address. + */ +class BitcoinAddressCheckValidator : public QValidator +{ + Q_OBJECT + +public: + explicit BitcoinAddressCheckValidator(QObject *parent); + + State validate(QString &input, int &pos) const; }; #endif // BITCOINADDRESSVALIDATOR_H diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index 915b3679a..c1aea3633 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -47,7 +47,7 @@ - + The address associated with this address list entry. This can only be modified for sending addresses. @@ -67,6 +67,13 @@ + + + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 989522bb5..aa271b4f2 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -47,9 +47,6 @@ The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - 34 - @@ -260,9 +257,6 @@ The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L) - - 34 - diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 5c3ba05b0..7e1831f03 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -6,6 +6,7 @@ #include "bitcoinaddressvalidator.h" #include "bitcoinunits.h" +#include "qvalidatedlineedit.h" #include "walletmodel.h" #include "core.h" @@ -72,11 +73,16 @@ QFont bitcoinAddressFont() return font; } -void setupAddressWidget(QLineEdit *widget, QWidget *parent) +void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent) { - widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength); - widget->setValidator(new BitcoinAddressValidator(parent)); + parent->setFocusProxy(widget); + widget->setFont(bitcoinAddressFont()); +#if QT_VERSION >= 0x040700 + widget->setPlaceholderText(QObject::tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); +#endif + widget->setValidator(new BitcoinAddressEntryValidator(parent)); + widget->setCheckValidator(new BitcoinAddressCheckValidator(parent)); } void setupAmountWidget(QLineEdit *widget, QWidget *parent) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index c894850a9..52124ff20 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -9,6 +9,7 @@ #include #include +class QValidatedLineEdit; class SendCoinsRecipient; QT_BEGIN_NAMESPACE @@ -32,7 +33,7 @@ namespace GUIUtil QFont bitcoinAddressFont(); // Set up widgets for address and amounts - void setupAddressWidget(QLineEdit *widget, QWidget *parent); + void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent); void setupAmountWidget(QLineEdit *widget, QWidget *parent); // Parse "bitcoin:" URI into recipient object, return true on successful parsing diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index 1e7596c9c..c2567835c 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -4,10 +4,13 @@ #include "qvalidatedlineedit.h" +#include "bitcoinaddressvalidator.h" #include "guiconstants.h" QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : - QLineEdit(parent), valid(true) + QLineEdit(parent), + valid(true), + checkValidator(0) { connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid())); } @@ -34,11 +37,20 @@ void QValidatedLineEdit::focusInEvent(QFocusEvent *evt) { // Clear invalid flag on focus setValid(true); + QLineEdit::focusInEvent(evt); } +void QValidatedLineEdit::focusOutEvent(QFocusEvent *evt) +{ + checkValidity(); + + QLineEdit::focusOutEvent(evt); +} + void QValidatedLineEdit::markValid() { + // As long as a user is typing ensure we display state as valid setValid(true); } @@ -47,3 +59,49 @@ void QValidatedLineEdit::clear() setValid(true); QLineEdit::clear(); } + +void QValidatedLineEdit::setEnabled(bool enabled) +{ + if (!enabled) + { + // A disabled QValidatedLineEdit should be marked valid + setValid(true); + } + else + { + // Recheck validity when QValidatedLineEdit gets enabled + checkValidity(); + } + + QLineEdit::setEnabled(enabled); +} + +void QValidatedLineEdit::checkValidity() +{ + if (text().isEmpty()) + { + setValid(true); + } + else if (hasAcceptableInput()) + { + setValid(true); + + // Check contents on focus out + if (checkValidator) + { + QString address = text(); + int pos = 0; + if (checkValidator->validate(address, pos) == QValidator::Acceptable) + setValid(true); + else + setValid(false); + } + } + else + setValid(false); +} + +void QValidatedLineEdit::setCheckValidator(const QValidator *v) +{ + checkValidator = v; +} diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index 53ef04e4a..c2a4817e6 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -15,20 +15,25 @@ class QValidatedLineEdit : public QLineEdit Q_OBJECT public: - explicit QValidatedLineEdit(QWidget *parent = 0); + explicit QValidatedLineEdit(QWidget *parent); void clear(); + void setCheckValidator(const QValidator *v); protected: void focusInEvent(QFocusEvent *evt); + void focusOutEvent(QFocusEvent *evt); private: bool valid; + const QValidator *checkValidator; public slots: void setValid(bool valid); + void setEnabled(bool enabled); private slots: void markValid(); + void checkValidity(); }; #endif // QVALIDATEDLINEEDIT_H diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index b15f00564..e2d7dc9bd 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -33,9 +33,8 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : ui->clearButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon()); #endif -#if QT_VERSION >= 0x040700 - ui->lineEditCoinControlChange->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); -#endif + + GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this); addEntry(); @@ -43,7 +42,6 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); // Coin Control - ui->lineEditCoinControlChange->setFont(GUIUtil::bitcoinAddressFont()); connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); @@ -536,7 +534,6 @@ void SendCoinsDialog::coinControlChangeChecked(int state) if (state == Qt::Unchecked) { CoinControlDialog::coinControl->destChange = CNoDestination(); - ui->lineEditCoinControlChange->setValid(true); ui->labelCoinControlChangeLabel->clear(); } else @@ -563,7 +560,6 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) } else if (!addr.IsValid()) // Invalid address { - ui->lineEditCoinControlChange->setValid(false); ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address")); } else // Valid address @@ -573,7 +569,6 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) addr.GetKeyID(keyid); if (!model->getPubKey(keyid, pubkey)) // Unknown change address { - ui->lineEditCoinControlChange->setValid(false); ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); } else // Known change address diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index b4e74b078..ad8dd7b73 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -28,9 +28,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) : #endif #if QT_VERSION >= 0x040700 ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); - ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); #endif - setFocusProxy(ui->payTo); // normal bitcoin address field GUIUtil::setupAddressWidget(ui->payTo, this); @@ -121,7 +119,7 @@ bool SendCoinsEntry::validate() if (recipient.paymentRequest.IsInitialized()) return retval; - if (!ui->payTo->hasAcceptableInput() || !model->validateAddress(ui->payTo->text())) + if (!model->validateAddress(ui->payTo->text())) { ui->payTo->setValid(false); retval = false; diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index e319f5075..3e56412c7 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -26,11 +26,8 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) : ui->setupUi(this); #if QT_VERSION >= 0x040700 - ui->addressIn_SM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature")); - ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); - ui->signatureIn_VM->setPlaceholderText(tr("Enter Bitcoin signature")); #endif GUIUtil::setupAddressWidget(ui->addressIn_SM, this); @@ -112,7 +109,6 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); if (!addr.IsValid()) { - ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; @@ -193,7 +189,6 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); if (!addr.IsValid()) { - ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return;