diff options
author | sje397 <sje397@gmail.com> | 2011-11-11 01:20:17 +1100 |
---|---|---|
committer | sje397 <sje397@gmail.com> | 2011-12-20 22:11:24 +1100 |
commit | 22123c85f3722abad896aebb564a89d88da92e81 (patch) | |
tree | 212d80a39a64c31bc7746127306cdb4eb9ce1614 | |
parent | 3528650560a2c417da2303869c743da019defc6d (diff) |
Added QRCode generation functions via libqrencode. Switch on with USE_QRENCODE=1.
Amended build docs for Linux and OSX, and OSX makefile.
Added package 'qrencode' to gitian.yml
-rw-r--r-- | bitcoin-qt.pro | 14 | ||||
-rw-r--r-- | contrib/gitian-descriptors/gitian.yml | 1 | ||||
-rw-r--r-- | doc/build-osx.txt | 3 | ||||
-rw-r--r-- | doc/build-unix.txt | 20 | ||||
-rw-r--r-- | src/makefile.osx | 4 | ||||
-rw-r--r-- | src/qt/addressbookpage.cpp | 30 | ||||
-rw-r--r-- | src/qt/addressbookpage.h | 1 | ||||
-rw-r--r-- | src/qt/bitcoin.qrc | 1 | ||||
-rw-r--r-- | src/qt/forms/addressbookpage.ui | 11 | ||||
-rw-r--r-- | src/qt/forms/qrcodedialog.ui | 213 | ||||
-rw-r--r-- | src/qt/qrcodedialog.cpp | 106 | ||||
-rw-r--r-- | src/qt/qrcodedialog.h | 37 | ||||
-rw-r--r-- | src/qt/res/images/qrcode.png | bin | 0 -> 5993 bytes |
13 files changed, 434 insertions, 7 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 853f2faf93..4a8dedc107 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -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 += \ 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 diff --git a/contrib/gitian-descriptors/gitian.yml b/contrib/gitian-descriptors/gitian.yml index 65005c61ff..6f503ac0bf 100644 --- a/contrib/gitian-descriptors/gitian.yml +++ b/contrib/gitian-descriptors/gitian.yml @@ -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" diff --git a/doc/build-osx.txt b/doc/build-osx.txt index 800244153a..d47febe94b 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -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 diff --git a/doc/build-unix.txt b/doc/build-unix.txt index f4178caae5..538933984c 100644 --- a/doc/build-unix.txt +++ b/doc/build-unix.txt @@ -23,12 +23,13 @@ the graphical bitcoin. Dependencies ------------ - Library Purpose Description - ------- ------- ----------- - libssl SSL Support Secure communications - libdb4.8 Berkeley DB Blockchain & wallet storage - libboost Boost C++ Library - miniupnpc UPnP Support Optional firewall-jumping support + Library Purpose Description + ------- ------- ----------- + libssl SSL Support Secure communications + 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: 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: Boost 1.37 miniupnpc 1.6 - Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- sudo apt-get install build-essential diff --git a/src/makefile.osx b/src/makefile.osx index 4b0b521a33..2bb898049d 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -95,6 +95,10 @@ else endif endif +ifdef USE_QRCODE + DEFS += -DUSE_QRCODE=$(USE_QRCODE) + LIBS += -lqrencode +endif all: bitcoind diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 0a147c9e10..d207fe30fa 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -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) : ui->deleteButton->setIcon(QIcon()); #endif +#ifndef USE_QRCODE + ui->showQRCode->setVisible(false); +#endif + switch(mode) { case ForSending: @@ -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() 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 +} diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 1a97f3d602..2538f319dd 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -54,6 +54,7 @@ private slots: void on_newAddressButton_clicked(); void on_copyToClipboard_clicked(); void selectionChanged(); + void on_showQRCode_clicked(); }; #endif // ADDRESSBOOKDIALOG_H diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index aea61d6982..5693ae187e 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -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> diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index fb098c8280..9b301cbbfa 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -80,6 +80,17 @@ </widget> </item> <item> + <widget class="QPushButton" name="showQRCode"> + <property name="text"> + <string>Show &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"> <string>Delete the currently selected address from the list. Only sending addresses can be deleted.</string> diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui new file mode 100644 index 0000000000..fa21f60b9e --- /dev/null +++ b/src/qt/forms/qrcodedialog.ui @@ -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>&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> diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp new file mode 100644 index 0000000000..ed4c758e38 --- /dev/null +++ b/src/qt/qrcodedialog.cpp @@ -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(); +} diff --git a/src/qt/qrcodedialog.h b/src/qt/qrcodedialog.h new file mode 100644 index 0000000000..7463a8810e --- /dev/null +++ b/src/qt/qrcodedialog.h @@ -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 diff --git a/src/qt/res/images/qrcode.png b/src/qt/res/images/qrcode.png Binary files differnew file mode 100644 index 0000000000..c89a49bbce --- /dev/null +++ b/src/qt/res/images/qrcode.png |