Browse Source

[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
0.10
Philip Kaufmann 11 years ago committed by Wladimir J. van der Laan
parent
commit
c78bd93701
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 58
      src/qt/bitcoinaddressvalidator.cpp
  2. 22
      src/qt/bitcoinaddressvalidator.h
  3. 9
      src/qt/forms/editaddressdialog.ui
  4. 6
      src/qt/forms/signverifymessagedialog.ui
  5. 12
      src/qt/guiutil.cpp
  6. 3
      src/qt/guiutil.h
  7. 60
      src/qt/qvalidatedlineedit.cpp
  8. 7
      src/qt/qvalidatedlineedit.h
  9. 9
      src/qt/sendcoinsdialog.cpp
  10. 4
      src/qt/sendcoinsentry.cpp
  11. 5
      src/qt/signverifymessagedialog.cpp

58
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 // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "bitcoinaddressvalidator.h" #include "bitcoinaddressvalidator.h"
#include "base58.h"
/* Base58 characters are: /* Base58 characters are:
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
@ -11,21 +13,23 @@
- All numbers except for '0' - All numbers except for '0'
- All upper-case letters except for 'I' and 'O' - All upper-case letters except for 'I' and 'O'
- All lower-case letters except for 'l' - 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(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 // Correction
for(int idx=0; idx<input.size();) for (int idx = 0; idx < input.size();)
{ {
bool removeChar = false; bool removeChar = false;
QChar ch = input.at(idx); QChar ch = input.at(idx);
@ -42,11 +46,13 @@ QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) co
default: default:
break; break;
} }
// Remove whitespace // Remove whitespace
if(ch.isSpace()) if (ch.isSpace())
removeChar = true; removeChar = true;
// To next character // To next character
if(removeChar) if (removeChar)
input.remove(idx, 1); input.remove(idx, 1);
else else
++idx; ++idx;
@ -54,14 +60,14 @@ QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) co
// Validation // Validation
QValidator::State state = QValidator::Acceptable; QValidator::State state = QValidator::Acceptable;
for(int idx=0; idx<input.size(); ++idx) for (int idx = 0; idx < input.size(); ++idx)
{ {
int ch = input.at(idx).unicode(); int ch = input.at(idx).unicode();
if(((ch >= '0' && ch<='9') || if (((ch >= '0' && ch<='9') ||
(ch >= 'a' && ch<='z') || (ch >= 'a' && ch<='z') ||
(ch >= 'A' && ch<='Z')) && (ch >= 'A' && ch<='Z')) &&
ch != 'l' && ch != 'I' && ch != '0' && ch != 'O') ch != 'l' && ch != 'I' && ch != '0' && ch != 'O')
{ {
// Alphanumeric and not a 'forbidden' character // 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; 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;
}

22
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 // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -7,19 +7,29 @@
#include <QValidator> #include <QValidator>
/** Base58 entry widget validator. /** Base58 entry widget validator, checks for valid characters and
Corrects near-miss characters and refuses characters that are not part of base58. * removes some whitespace.
*/ */
class BitcoinAddressValidator : public QValidator class BitcoinAddressEntryValidator : public QValidator
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit BitcoinAddressValidator(QObject *parent = 0); explicit BitcoinAddressEntryValidator(QObject *parent);
State validate(QString &input, int &pos) const; State validate(QString &input, int &pos) const;
};
/** Bitcoin address widget validator, checks for a valid bitcoin address.
*/
class BitcoinAddressCheckValidator : public QValidator
{
Q_OBJECT
public:
explicit BitcoinAddressCheckValidator(QObject *parent);
static const int MaxAddressLength = 35; State validate(QString &input, int &pos) const;
}; };
#endif // BITCOINADDRESSVALIDATOR_H #endif // BITCOINADDRESSVALIDATOR_H

9
src/qt/forms/editaddressdialog.ui

@ -47,7 +47,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="addressEdit"> <widget class="QValidatedLineEdit" name="addressEdit">
<property name="toolTip"> <property name="toolTip">
<string>The address associated with this address list entry. This can only be modified for sending addresses.</string> <string>The address associated with this address list entry. This can only be modified for sending addresses.</string>
</property> </property>
@ -67,6 +67,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>

6
src/qt/forms/signverifymessagedialog.ui

@ -47,9 +47,6 @@
<property name="toolTip"> <property name="toolTip">
<string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string> <string>The address to sign the message with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property> </property>
<property name="maxLength">
<number>34</number>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -260,9 +257,6 @@
<property name="toolTip"> <property name="toolTip">
<string>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string> <string>The address the message was signed with (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property> </property>
<property name="maxLength">
<number>34</number>
</property>
</widget> </widget>
</item> </item>
<item> <item>

12
src/qt/guiutil.cpp

@ -6,6 +6,7 @@
#include "bitcoinaddressvalidator.h" #include "bitcoinaddressvalidator.h"
#include "bitcoinunits.h" #include "bitcoinunits.h"
#include "qvalidatedlineedit.h"
#include "walletmodel.h" #include "walletmodel.h"
#include "core.h" #include "core.h"
@ -72,11 +73,16 @@ QFont bitcoinAddressFont()
return font; return font;
} }
void setupAddressWidget(QLineEdit *widget, QWidget *parent) void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
{ {
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength); parent->setFocusProxy(widget);
widget->setValidator(new BitcoinAddressValidator(parent));
widget->setFont(bitcoinAddressFont()); 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) void setupAmountWidget(QLineEdit *widget, QWidget *parent)

3
src/qt/guiutil.h

@ -9,6 +9,7 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
class QValidatedLineEdit;
class SendCoinsRecipient; class SendCoinsRecipient;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -32,7 +33,7 @@ namespace GUIUtil
QFont bitcoinAddressFont(); QFont bitcoinAddressFont();
// Set up widgets for address and amounts // 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); void setupAmountWidget(QLineEdit *widget, QWidget *parent);
// Parse "bitcoin:" URI into recipient object, return true on successful parsing // Parse "bitcoin:" URI into recipient object, return true on successful parsing

60
src/qt/qvalidatedlineedit.cpp

@ -4,10 +4,13 @@
#include "qvalidatedlineedit.h" #include "qvalidatedlineedit.h"
#include "bitcoinaddressvalidator.h"
#include "guiconstants.h" #include "guiconstants.h"
QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
QLineEdit(parent), valid(true) QLineEdit(parent),
valid(true),
checkValidator(0)
{ {
connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid())); connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid()));
} }
@ -34,11 +37,20 @@ void QValidatedLineEdit::focusInEvent(QFocusEvent *evt)
{ {
// Clear invalid flag on focus // Clear invalid flag on focus
setValid(true); setValid(true);
QLineEdit::focusInEvent(evt); QLineEdit::focusInEvent(evt);
} }
void QValidatedLineEdit::focusOutEvent(QFocusEvent *evt)
{
checkValidity();
QLineEdit::focusOutEvent(evt);
}
void QValidatedLineEdit::markValid() void QValidatedLineEdit::markValid()
{ {
// As long as a user is typing ensure we display state as valid
setValid(true); setValid(true);
} }
@ -47,3 +59,49 @@ void QValidatedLineEdit::clear()
setValid(true); setValid(true);
QLineEdit::clear(); 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;
}

7
src/qt/qvalidatedlineedit.h

@ -15,20 +15,25 @@ class QValidatedLineEdit : public QLineEdit
Q_OBJECT Q_OBJECT
public: public:
explicit QValidatedLineEdit(QWidget *parent = 0); explicit QValidatedLineEdit(QWidget *parent);
void clear(); void clear();
void setCheckValidator(const QValidator *v);
protected: protected:
void focusInEvent(QFocusEvent *evt); void focusInEvent(QFocusEvent *evt);
void focusOutEvent(QFocusEvent *evt);
private: private:
bool valid; bool valid;
const QValidator *checkValidator;
public slots: public slots:
void setValid(bool valid); void setValid(bool valid);
void setEnabled(bool enabled);
private slots: private slots:
void markValid(); void markValid();
void checkValidity();
}; };
#endif // QVALIDATEDLINEEDIT_H #endif // QVALIDATEDLINEEDIT_H

9
src/qt/sendcoinsdialog.cpp

@ -33,9 +33,8 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
ui->clearButton->setIcon(QIcon()); ui->clearButton->setIcon(QIcon());
ui->sendButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon());
#endif #endif
#if QT_VERSION >= 0x040700
ui->lineEditCoinControlChange->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
#endif
addEntry(); addEntry();
@ -43,7 +42,6 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
// Coin Control // Coin Control
ui->lineEditCoinControlChange->setFont(GUIUtil::bitcoinAddressFont());
connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked()));
connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int)));
connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); 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) if (state == Qt::Unchecked)
{ {
CoinControlDialog::coinControl->destChange = CNoDestination(); CoinControlDialog::coinControl->destChange = CNoDestination();
ui->lineEditCoinControlChange->setValid(true);
ui->labelCoinControlChangeLabel->clear(); ui->labelCoinControlChangeLabel->clear();
} }
else else
@ -563,7 +560,6 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
} }
else if (!addr.IsValid()) // Invalid address else if (!addr.IsValid()) // Invalid address
{ {
ui->lineEditCoinControlChange->setValid(false);
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address")); ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
} }
else // Valid address else // Valid address
@ -573,7 +569,6 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
addr.GetKeyID(keyid); addr.GetKeyID(keyid);
if (!model->getPubKey(keyid, pubkey)) // Unknown change address if (!model->getPubKey(keyid, pubkey)) // Unknown change address
{ {
ui->lineEditCoinControlChange->setValid(false);
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
} }
else // Known change address else // Known change address

4
src/qt/sendcoinsentry.cpp

@ -28,9 +28,7 @@ SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
#endif #endif
#if QT_VERSION >= 0x040700 #if QT_VERSION >= 0x040700
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book")); 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 #endif
setFocusProxy(ui->payTo);
// normal bitcoin address field // normal bitcoin address field
GUIUtil::setupAddressWidget(ui->payTo, this); GUIUtil::setupAddressWidget(ui->payTo, this);
@ -121,7 +119,7 @@ bool SendCoinsEntry::validate()
if (recipient.paymentRequest.IsInitialized()) if (recipient.paymentRequest.IsInitialized())
return retval; return retval;
if (!ui->payTo->hasAcceptableInput() || !model->validateAddress(ui->payTo->text())) if (!model->validateAddress(ui->payTo->text()))
{ {
ui->payTo->setValid(false); ui->payTo->setValid(false);
retval = false; retval = false;

5
src/qt/signverifymessagedialog.cpp

@ -26,11 +26,8 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
#if QT_VERSION >= 0x040700 #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->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)")); ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
ui->signatureIn_VM->setPlaceholderText(tr("Enter Bitcoin signature"));
#endif #endif
GUIUtil::setupAddressWidget(ui->addressIn_SM, this); GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
@ -112,7 +109,6 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
if (!addr.IsValid()) if (!addr.IsValid())
{ {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); 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.")); ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return; return;
@ -193,7 +189,6 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
CBitcoinAddress addr(ui->addressIn_VM->text().toStdString()); CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
if (!addr.IsValid()) if (!addr.IsValid())
{ {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); 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.")); ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return; return;

Loading…
Cancel
Save