update QRCodeDialog

- remove unused #include <QDebug> and lblBTC label
- update Bitcoin input field to a BitcoinAmountField to allow Bitcoin unit selection
- use BitcoinUnits::format for the resulting amount parameter in the generated URI (always use BTC as per BIP21)
- move MAX_URI_LENGTH and EXPORT_IMAGE_SIZE to guiconstants.h
- add OptionsModel in AddressBookPage and use it in on_showQRCode_clicked() to pass it to QRCodeDialog
- add OptionsModel in QRCodeDialog to enable display unit updates
- add updateDisplayUnit() slot to be able to imediately update currently set bitcoin unit
- make all labels in the UI-file plain text
- resize dialog to match for an updated layout (fields are now stacked and new field)
- remove unused parameters from private slots
- only enable save button, when QR Code was generated
- show message when entered amound is invalid
- add read-only QPlainTextEdit field to output generated URI
master
Philip Kaufmann 2012-06-24 18:28:05 +02:00
parent 2a919e396d
commit 5c83f797c5
7 changed files with 217 additions and 154 deletions

View File

@ -2,6 +2,7 @@
#include "ui_addressbookpage.h"
#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "bitcoingui.h"
#include "editaddressdialog.h"
#include "csvmodelwriter.h"
@ -20,6 +21,7 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
optionsModel(0),
mode(mode),
tab(tab)
{
@ -139,6 +141,11 @@ void AddressBookPage::setModel(AddressTableModel *model)
selectionChanged();
}
void AddressBookPage::setOptionsModel(OptionsModel *optionsModel)
{
this->optionsModel = optionsModel;
}
void AddressBookPage::on_copyToClipboard_clicked()
{
GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
@ -314,6 +321,8 @@ void AddressBookPage::on_showQRCode_clicked()
QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
if(optionsModel)
dialog->setModel(optionsModel);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
}

View File

@ -7,6 +7,7 @@ namespace Ui {
class AddressBookPage;
}
class AddressTableModel;
class OptionsModel;
QT_BEGIN_NAMESPACE
class QTableView;
@ -37,6 +38,7 @@ public:
~AddressBookPage();
void setModel(AddressTableModel *model);
void setOptionsModel(OptionsModel *optionsModel);
const QString &getReturnValue() const { return returnValue; }
public slots:
@ -46,6 +48,7 @@ public slots:
private:
Ui::AddressBookPage *ui;
AddressTableModel *model;
OptionsModel *optionsModel;
Mode mode;
Tabs tab;
QString returnValue;

View File

@ -357,6 +357,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
rpcConsole->setClientModel(clientModel);
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
}
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>425</height>
<width>340</width>
<height>530</height>
</rect>
</property>
<property name="windowTitle">
@ -28,8 +28,8 @@
<height>300</height>
</size>
</property>
<property name="text">
<string>QR Code</string>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -39,134 +39,123 @@
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="outUri">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="chkReqPayment">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Request Payment</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblAmount">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Amount:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lnReqAmount">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblBTC">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BTC</string>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<widget class="QCheckBox" name="chkReqPayment">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Request Payment</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="lblLabel">
<property name="text">
<string>Label:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnLabel</cstring>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblLabel">
<property name="text">
<string>Label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnLabel</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lnLabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblMessage">
<property name="text">
<string>Message:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnMessage</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lnMessage">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
<item row="1" column="1">
<widget class="QLineEdit" name="lnLabel"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblMessage">
<property name="text">
<string>Message:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnMessage</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lnMessage"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblAmount">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Amount:</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>lnReqAmount</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="BitcoinAmountField" name="lnReqAmount">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@ -194,6 +183,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QSpinBox</extends>
<header>bitcoinamountfield.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

View File

@ -25,4 +25,10 @@ static const int STATUSBAR_ICONSIZE = 16;
*/
static const int TOOLTIP_WRAP_THRESHOLD = 80;
/* Maximum allowed URI length */
static const int MAX_URI_LENGTH = 255;
/* QRCodeDialog -- size of exported QR Code image */
#define EXPORT_IMAGE_SIZE 256
#endif // GUICONSTANTS_H

View File

@ -1,28 +1,34 @@
#include "qrcodedialog.h"
#include "ui_qrcodedialog.h"
#include "bitcoinunits.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
#include <QPixmap>
#include <QUrl>
#include <QDebug>
#include <qrencode.h>
#define EXPORT_IMAGE_SIZE 256
QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) :
QDialog(parent), ui(new Ui::QRCodeDialog), address(addr)
QDialog(parent),
ui(new Ui::QRCodeDialog),
model(0),
address(addr)
{
ui->setupUi(this);
setWindowTitle(QString("%1").arg(address));
ui->chkReqPayment->setVisible(enableReq);
ui->lnReqAmount->setVisible(enableReq);
ui->lblAmount->setVisible(enableReq);
ui->lblBTC->setVisible(enableReq);
ui->lnReqAmount->setVisible(enableReq);
ui->lnLabel->setText(label);
ui->btnSaveAs->setEnabled(false);
genCode();
}
@ -31,6 +37,17 @@ QRCodeDialog::~QRCodeDialog()
delete ui;
}
void QRCodeDialog::setModel(OptionsModel *model)
{
this->model = model;
if (model)
connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
// update the display unit, to not use the default ("BTC")
updateDisplayUnit();
}
void QRCodeDialog::genCode()
{
QString uri = getURI();
@ -57,26 +74,34 @@ void QRCodeDialog::genCode()
}
}
QRcode_free(code);
ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
ui->outUri->setPlainText(uri);
}
else
ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
}
QString QRCodeDialog::getURI()
{
QString ret = QString("bitcoin:%1").arg(address);
int paramCount = 0;
if (ui->chkReqPayment->isChecked() && !ui->lnReqAmount->text().isEmpty())
ui->outUri->clear();
if (ui->chkReqPayment->isChecked())
{
bool ok = false;
ui->lnReqAmount->text().toDouble(&ok);
if (ok)
if (ui->lnReqAmount->validate())
{
ret += QString("?amount=%1").arg(ui->lnReqAmount->text());
// even if we allow a non BTC unit input in lnReqAmount, we generate the URI with BTC as unit (as defined in BIP21)
ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, ui->lnReqAmount->value()));
paramCount++;
}
else
{
ui->btnSaveAs->setEnabled(false);
ui->lblQRCode->setText(tr("The entered amount is invalid, please check."));
return QString("");
}
}
if (!ui->lnLabel->text().isEmpty())
@ -93,24 +118,29 @@ QString QRCodeDialog::getURI()
paramCount++;
}
// limit URI length to 255 chars, to prevent a DoS against the QR-Code dialog
if (ret.length() < 256)
return ret;
else
// limit URI length to prevent a DoS against the QR-Code dialog
if (ret.length() > MAX_URI_LENGTH)
{
ui->btnSaveAs->setEnabled(false);
ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
return QString("");
}
ui->btnSaveAs->setEnabled(true);
return ret;
}
void QRCodeDialog::on_lnReqAmount_textChanged(const QString &arg1)
void QRCodeDialog::on_lnReqAmount_textChanged()
{
genCode();
}
void QRCodeDialog::on_lnLabel_textChanged(const QString &arg1)
void QRCodeDialog::on_lnLabel_textChanged()
{
genCode();
}
void QRCodeDialog::on_lnMessage_textChanged(const QString &arg1)
void QRCodeDialog::on_lnMessage_textChanged()
{
genCode();
}
@ -122,7 +152,20 @@ void QRCodeDialog::on_btnSaveAs_clicked()
myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
}
void QRCodeDialog::on_chkReqPayment_toggled(bool)
void QRCodeDialog::on_chkReqPayment_toggled(bool fChecked)
{
if (!fChecked)
// if chkReqPayment is not active, don't display lnReqAmount as invalid
ui->lnReqAmount->setValid(true);
genCode();
}
void QRCodeDialog::updateDisplayUnit()
{
if (model)
{
// Update lnReqAmount with the current unit
ui->lnReqAmount->setDisplayUnit(model->getDisplayUnit());
}
}

View File

@ -7,6 +7,7 @@
namespace Ui {
class QRCodeDialog;
}
class OptionsModel;
class QRCodeDialog : public QDialog
{
@ -16,22 +17,25 @@ public:
explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0);
~QRCodeDialog();
private slots:
void on_lnReqAmount_textChanged(const QString &arg1);
void on_lnLabel_textChanged(const QString &arg1);
void on_lnMessage_textChanged(const QString &arg1);
void on_btnSaveAs_clicked();
void setModel(OptionsModel *model);
void on_chkReqPayment_toggled(bool checked);
private slots:
void on_lnReqAmount_textChanged();
void on_lnLabel_textChanged();
void on_lnMessage_textChanged();
void on_btnSaveAs_clicked();
void on_chkReqPayment_toggled(bool fChecked);
void updateDisplayUnit();
private:
Ui::QRCodeDialog *ui;
OptionsModel *model;
QString address;
QImage myImage;
QString getURI();
QString address;
void genCode();
QString getURI();
};
#endif // QRCODEDIALOG_H