diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 853f2faf..4a8dedc1 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 65005c61..6f503ac0 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 80024415..d47febe9 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 f4178caa..53893398 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 4b0b521a..2bb89804 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 0a147c9e..d207fe30 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -10,6 +10,10 @@ #include #include +#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 1a97f3d6..2538f319 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 aea61d69..5693ae18 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -41,6 +41,7 @@ res/images/about.png res/images/splash2.jpg + res/images/qrcode.png res/movies/update_spinner.mng diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index fb098c82..9b301cbb 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -79,6 +79,17 @@ + + + + Show &QR Code + + + + :/images/qrcode:/images/qrcode + + + diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui new file mode 100644 index 00000000..fa21f60b --- /dev/null +++ b/src/qt/forms/qrcodedialog.ui @@ -0,0 +1,213 @@ + + + QRCodeDialog + + + + 0 + 0 + 320 + 404 + + + + Dialog + + + + + + + 0 + 0 + + + + + 300 + 300 + + + + QR Code + + + Qt::AlignCenter + + + + + + + + + + + + + + true + + + Request Payment + + + + + + + + + + 0 + 0 + + + + Amount: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnReqAmount + + + + + + + false + + + + 60 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + BTC + + + lnReqAmount + + + + + + + + + + + + + Label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnLabel + + + + + + + + 100 + 0 + + + + + + + + Message: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + lnMessage + + + + + + + + 100 + 0 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Save As... + + + + + + + + + + + + + + chkReq + clicked(bool) + lnReqAmount + setEnabled(bool) + + + 92 + 285 + + + 98 + 311 + + + + + diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp new file mode 100644 index 00000000..ed4c758e --- /dev/null +++ b/src/qt/qrcodedialog.cpp @@ -0,0 +1,106 @@ +#include "qrcodedialog.h" +#include "ui_qrcodedialog.h" +#include +#include +#include +#include +#include + +#include + +#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 00000000..7463a881 --- /dev/null +++ b/src/qt/qrcodedialog.h @@ -0,0 +1,37 @@ +#ifndef QRCODEDIALOG_H +#define QRCODEDIALOG_H + +#include +#include + +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 new file mode 100644 index 00000000..c89a49bb Binary files /dev/null and b/src/qt/res/images/qrcode.png differ