Browse Source

Merge pull request #629 from sje397/master

QR Code generation via libqrencode
0.8
Wladimir J. van der Laan 13 years ago
parent
commit
96b1e085c3
  1. 14
      bitcoin-qt.pro
  2. 1
      contrib/gitian-descriptors/gitian.yml
  3. 3
      doc/build-osx.txt
  4. 8
      doc/build-unix.txt
  5. 4
      src/makefile.osx
  6. 30
      src/qt/addressbookpage.cpp
  7. 1
      src/qt/addressbookpage.h
  8. 1
      src/qt/bitcoin.qrc
  9. 11
      src/qt/forms/addressbookpage.ui
  10. 213
      src/qt/forms/qrcodedialog.ui
  11. 106
      src/qt/qrcodedialog.cpp
  12. 37
      src/qt/qrcodedialog.h
  13. BIN
      src/qt/res/images/qrcode.png

14
bitcoin-qt.pro

@ -19,6 +19,14 @@ OBJECTS_DIR = build @@ -19,6 +19,14 @@ OBJECTS_DIR = build
MOC_DIR = build
UI_DIR = build
# use: qmake "USE_QRCODE=1"
# libqrencode (http://fukuchi.org/works/qrencode/index.en.html) must be installed for support
contains(USE_QRCODE, 1) {
message(Building with QRCode support)
DEFINES += USE_QRCODE
LIBS += -lqrencode
}
# use: qmake "RELEASE=1"
contains(RELEASE, 1) {
# Mac: compile for maximum compatibility (10.5, 32-bit)
@ -199,6 +207,12 @@ FORMS += \ @@ -199,6 +207,12 @@ FORMS += \
src/qt/forms/sendcoinsentry.ui \
src/qt/forms/askpassphrasedialog.ui
contains(USE_QRCODE, 1) {
HEADERS += src/qt/qrcodedialog.h
SOURCES += src/qt/qrcodedialog.cpp
FORMS += src/qt/forms/qrcodedialog.ui
}
CODECFORTR = UTF-8
# for lrelease/lupdate

1
contrib/gitian-descriptors/gitian.yml

@ -16,6 +16,7 @@ packages: @@ -16,6 +16,7 @@ packages:
- "libssl-dev"
- "git-core"
- "unzip"
- "qrencode"
reference_datetime: "2011-01-30 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"

3
doc/build-osx.txt

@ -43,6 +43,9 @@ pushd bitcoin/contrib/minipupnpc; sudo port install; popd @@ -43,6 +43,9 @@ pushd bitcoin/contrib/minipupnpc; sudo port install; popd
(this will be unnecessary soon, you will just port install miniupnpc
along with the rest of the dependencies).
Optionally install qrencode (and set USE_QRCODE=1):
sudo port install qrencode
4. Now you should be able to build bitcoind:
cd bitcoin/src

8
doc/build-unix.txt

@ -29,6 +29,7 @@ Dependencies @@ -29,6 +29,7 @@ Dependencies
libdb4.8 Berkeley DB Blockchain & wallet storage
libboost Boost C++ Library
miniupnpc UPnP Support Optional firewall-jumping support
libqrencode QRCode generation Optional QRCode generation
miniupnpc may be used for UPnP port mapping. It can be downloaded from
http://miniupnp.tuxfamily.org/files/. UPnP support is compiled in and
@ -37,6 +38,12 @@ turned off by default. Set USE_UPNP to a different value to control this: @@ -37,6 +38,12 @@ turned off by default. Set USE_UPNP to a different value to control this:
USE_UPNP=0 (the default) UPnP support turned off by default at runtime
USE_UPNP=1 UPnP support turned on by default at runtime
libqrencode may be used for QRCode image generation. It can be downloaded
from http://fukuchi.org/works/qrencode/index.html.en, or installed via
your package manager. Set USE_QRCODE to control this:
USE_QRCODE=0 (the default) No QRCode support - libarcode not required
USE_QRCODE=1 QRCode support enabled
Licenses of statically linked libraries:
Berkeley DB New BSD license with additional requirement that linked
software must be free open source
@ -50,7 +57,6 @@ Versions used in this release: @@ -50,7 +57,6 @@ Versions used in this release:
Boost 1.37
miniupnpc 1.6
Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
sudo apt-get install build-essential

4
src/makefile.osx vendored

@ -96,6 +96,10 @@ else @@ -96,6 +96,10 @@ else
endif
endif
ifdef USE_QRCODE
DEFS += -DUSE_QRCODE=$(USE_QRCODE)
LIBS += -lqrencode
endif
all: bitcoind

30
src/qt/addressbookpage.cpp

@ -10,6 +10,10 @@ @@ -10,6 +10,10 @@
#include <QFileDialog>
#include <QMessageBox>
#ifdef USE_QRCODE
#include "qrcodedialog.h"
#endif
AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
@ -25,6 +29,10 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : @@ -25,6 +29,10 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
ui->deleteButton->setIcon(QIcon());
#endif
#ifndef USE_QRCODE
ui->showQRCode->setVisible(false);
#endif
switch(mode)
{
case ForSending:
@ -169,10 +177,12 @@ void AddressBookPage::selectionChanged() @@ -169,10 +177,12 @@ void AddressBookPage::selectionChanged()
break;
}
ui->copyToClipboard->setEnabled(true);
ui->showQRCode->setEnabled(true);
}
else
{
ui->deleteButton->setEnabled(false);
ui->showQRCode->setEnabled(false);
ui->copyToClipboard->setEnabled(false);
}
}
@ -227,3 +237,23 @@ void AddressBookPage::exportClicked() @@ -227,3 +237,23 @@ void AddressBookPage::exportClicked()
QMessageBox::Abort, QMessageBox::Abort);
}
}
void AddressBookPage::on_showQRCode_clicked()
{
#ifdef USE_QRCODE
QTableView *table = ui->tableView;
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
QRCodeDialog *d;
foreach (QModelIndex index, indexes)
{
QString address = index.data().toString(),
label = index.sibling(index.row(), 0).data().toString(),
title = QString("%1 << %2 >>").arg(label).arg(address);
QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
d->show();
}
#endif
}

1
src/qt/addressbookpage.h

@ -54,6 +54,7 @@ private slots: @@ -54,6 +54,7 @@ private slots:
void on_newAddressButton_clicked();
void on_copyToClipboard_clicked();
void selectionChanged();
void on_showQRCode_clicked();
};
#endif // ADDRESSBOOKDIALOG_H

1
src/qt/bitcoin.qrc

@ -41,6 +41,7 @@ @@ -41,6 +41,7 @@
<qresource prefix="/images">
<file alias="about">res/images/about.png</file>
<file alias="splash">res/images/splash2.jpg</file>
<file alias="qrcode">res/images/qrcode.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="update_spinner">res/movies/update_spinner.mng</file>

11
src/qt/forms/addressbookpage.ui

@ -79,6 +79,17 @@ @@ -79,6 +79,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="showQRCode">
<property name="text">
<string>Show &amp;QR Code</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
<normaloff>:/images/qrcode</normaloff>:/images/qrcode</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="toolTip">

213
src/qt/forms/qrcodedialog.ui

@ -0,0 +1,213 @@ @@ -0,0 +1,213 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QRCodeDialog</class>
<widget class="QDialog" name="QRCodeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>404</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="lblQRCode">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="text">
<string>QR Code</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</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="chkReq">
<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="lblAm1">
<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="lblAm2">
<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>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<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="label_4">
<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>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnSaveAs">
<property name="text">
<string>&amp;Save As...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>chkReq</sender>
<signal>clicked(bool)</signal>
<receiver>lnReqAmount</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>92</x>
<y>285</y>
</hint>
<hint type="destinationlabel">
<x>98</x>
<y>311</y>
</hint>
</hints>
</connection>
</connections>
</ui>

106
src/qt/qrcodedialog.cpp

@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
#include "qrcodedialog.h"
#include "ui_qrcodedialog.h"
#include <QPixmap>
#include <QUrl>
#include <QFileDialog>
#include <QDesktopServices>
#include <QDebug>
#include <qrencode.h>
#define EXPORT_IMAGE_SIZE 256
QRCodeDialog::QRCodeDialog(const QString &title, const QString &addr, const QString &label, bool enableReq, QWidget *parent) :
QDialog(parent),
ui(new Ui::QRCodeDialog),
address(addr)
{
ui->setupUi(this);
setWindowTitle(title);
setAttribute(Qt::WA_DeleteOnClose);
ui->chkReq->setVisible(enableReq);
ui->lnReqAmount->setVisible(enableReq);
ui->lblAm1->setVisible(enableReq);
ui->lblAm2->setVisible(enableReq);
ui->lnLabel->setText(label);
genCode();
}
QRCodeDialog::~QRCodeDialog()
{
delete ui;
}
void QRCodeDialog::genCode() {
QString uri = getURI();
//qDebug() << "Encoding:" << uri.toUtf8().constData();
QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
myImage.fill(0xffffff);
unsigned char *p = code->data;
for(int y = 0; y < code->width; y++) {
for(int x = 0; x < code->width; x++) {
myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
p++;
}
}
QRcode_free(code);
ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
}
QString QRCodeDialog::getURI() {
QString ret = QString("bitcoin:%1").arg(address);
int paramCount = 0;
if(ui->chkReq->isChecked() && ui->lnReqAmount->text().isEmpty() == false) {
bool ok= false;
double amount = ui->lnReqAmount->text().toDouble(&ok);
if(ok) {
ret += QString("?amount=%1X8").arg(ui->lnReqAmount->text());
paramCount++;
}
}
if(ui->lnLabel->text().isEmpty() == false) {
QString lbl(QUrl::toPercentEncoding(ui->lnLabel->text()));
ret += QString("%1label=%2").arg(paramCount == 0 ? "?" : "&").arg(lbl);
paramCount++;
}
if(ui->lnMessage->text().isEmpty() == false) {
QString msg(QUrl::toPercentEncoding(ui->lnMessage->text()));
ret += QString("%1message=%2").arg(paramCount == 0 ? "?" : "&").arg(msg);
paramCount++;
}
return ret;
}
void QRCodeDialog::on_lnReqAmount_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_lnLabel_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_lnMessage_textChanged(const QString &) {
genCode();
}
void QRCodeDialog::on_btnSaveAs_clicked()
{
QString fn = QFileDialog::getSaveFileName(this, "Save Image...", QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation), "Images (*.png)");
if(!fn.isEmpty()) {
myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn);
}
}
void QRCodeDialog::on_chkReq_toggled(bool)
{
genCode();
}

37
src/qt/qrcodedialog.h

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
#ifndef QRCODEDIALOG_H
#define QRCODEDIALOG_H
#include <QDialog>
#include <QImage>
namespace Ui {
class QRCodeDialog;
}
class QRCodeDialog : public QDialog
{
Q_OBJECT
public:
explicit QRCodeDialog(const QString &title, const QString &address, const QString &label, bool allowReq, 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 on_chkReq_toggled(bool checked);
private:
Ui::QRCodeDialog *ui;
QImage myImage;
QString getURI();
QString address;
void genCode();
};
#endif // QRCODEDIALOG_H

BIN
src/qt/res/images/qrcode.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Loading…
Cancel
Save