Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #521 from laanwj/qt

Qt GUI
  • Loading branch information...
commit f7f2a36925bb560363f691fc3ca3dec83830dd15 2 parents f8937b2 + 0465c41
@gavinandresen gavinandresen authored
Showing with 16,008 additions and 33 deletions.
  1. +13 −0 .gitignore
  2. +0 −1  README.md
  3. +185 −0 bitcoin-qt.pro
  4. +43 −0 contrib/miniupnpc/Portfile
  5. +73 −0 doc/assets-attribution.txt
  6. +162 −0 doc/readme-qt.rst
  7. +63 −0 scripts/qt/extract_strings_qt.py
  8. BIN  scripts/qt/img/reload.xcf
  9. +43 −0 scripts/qt/make_spinner.py
  10. +9 −0 scripts/qt/make_windows_icon.py
  11. +2 −2 src/{rpc.cpp → bitcoinrpc.cpp}
  12. 0  src/{rpc.h → bitcoinrpc.h}
  13. +4 −0 src/headers.h
  14. +12 −6 src/init.cpp
  15. +11 −0 src/main.cpp
  16. +1 −0  src/main.h
  17. +2 −2 src/makefile.linux-mingw
  18. +2 −2 src/makefile.mingw
  19. +2 −2 src/makefile.osx
  20. +2 −2 src/makefile.unix
  21. +1 −1  src/makefile.vc
  22. +4 −0 src/noui.h
  23. +26 −0 src/qt/aboutdialog.cpp
  24. +27 −0 src/qt/aboutdialog.h
  25. +215 −0 src/qt/addressbookpage.cpp
  26. +59 −0 src/qt/addressbookpage.h
  27. +347 −0 src/qt/addresstablemodel.cpp
  28. +83 −0 src/qt/addresstablemodel.h
  29. +186 −0 src/qt/askpassphrasedialog.cpp
  30. +40 −0 src/qt/askpassphrasedialog.h
  31. +170 −0 src/qt/bitcoin.cpp
  32. +48 −0 src/qt/bitcoin.qrc
  33. +67 −0 src/qt/bitcoinaddressvalidator.cpp
  34. +24 −0 src/qt/bitcoinaddressvalidator.h
  35. +178 −0 src/qt/bitcoinamountfield.cpp
  36. +59 −0 src/qt/bitcoinamountfield.h
  37. +613 −0 src/qt/bitcoingui.cpp
  38. +120 −0 src/qt/bitcoingui.h
  39. +217 −0 src/qt/bitcoinstrings.cpp
  40. +181 −0 src/qt/bitcoinunits.cpp
  41. +57 −0 src/qt/bitcoinunits.h
  42. +83 −0 src/qt/clientmodel.cpp
  43. +60 −0 src/qt/clientmodel.h
  44. +83 −0 src/qt/csvmodelwriter.cpp
  45. +43 −0 src/qt/csvmodelwriter.h
  46. +115 −0 src/qt/editaddressdialog.cpp
  47. +47 −0 src/qt/editaddressdialog.h
  48. +162 −0 src/qt/forms/aboutdialog.ui
  49. +130 −0 src/qt/forms/addressbookpage.ui
  50. +148 −0 src/qt/forms/askpassphrasedialog.ui
  51. +105 −0 src/qt/forms/editaddressdialog.ui
  52. +161 −0 src/qt/forms/overviewpage.ui
  53. +122 −0 src/qt/forms/sendcoinsdialog.ui
  54. +178 −0 src/qt/forms/sendcoinsentry.ui
  55. +71 −0 src/qt/forms/transactiondescdialog.ui
  56. +23 −0 src/qt/guiconstants.h
  57. +74 −0 src/qt/guiutil.cpp
  58. +34 −0 src/qt/guiutil.h
  59. +1,155 −0 src/qt/locale/bitcoin_de.ts
  60. +1,441 −0 src/qt/locale/bitcoin_nl.ts
  61. +2,173 −0 src/qt/locale/bitcoin_ru.ts
  62. +36 −0 src/qt/monitoreddatamapper.cpp
  63. +32 −0 src/qt/monitoreddatamapper.h
  64. +224 −0 src/qt/notificator.cpp
  65. +63 −0 src/qt/notificator.h
  66. +277 −0 src/qt/optionsdialog.cpp
  67. +50 −0 src/qt/optionsdialog.h
  68. +162 −0 src/qt/optionsmodel.cpp
  69. +56 −0 src/qt/optionsmodel.h
  70. +173 −0 src/qt/overviewpage.cpp
  71. +45 −0 src/qt/overviewpage.h
  72. +45 −0 src/qt/qvalidatedlineedit.cpp
  73. +28 −0 src/qt/qvalidatedlineedit.h
  74. +27 −0 src/qt/qvaluecombobox.cpp
  75. +33 −0 src/qt/qvaluecombobox.h
  76. +1 −0  src/qt/res/bitcoin-qt.rc
  77. BIN  src/qt/res/icons/add.png
  78. BIN  src/qt/res/icons/address-book.png
  79. BIN  src/qt/res/icons/bitcoin.icns
  80. BIN  src/qt/res/icons/bitcoin.ico
  81. BIN  src/qt/res/icons/bitcoin.png
  82. BIN  src/qt/res/icons/bitcoin_testnet.png
  83. BIN  src/qt/res/icons/clock1.png
  84. BIN  src/qt/res/icons/clock2.png
  85. BIN  src/qt/res/icons/clock3.png
  86. BIN  src/qt/res/icons/clock4.png
  87. BIN  src/qt/res/icons/clock5.png
  88. BIN  src/qt/res/icons/configure.png
  89. BIN  src/qt/res/icons/connect0_16.png
  90. BIN  src/qt/res/icons/connect1_16.png
  91. BIN  src/qt/res/icons/connect2_16.png
  92. BIN  src/qt/res/icons/connect3_16.png
  93. BIN  src/qt/res/icons/connect4_16.png
  94. BIN  src/qt/res/icons/edit.png
  95. BIN  src/qt/res/icons/editcopy.png
  96. BIN  src/qt/res/icons/editpaste.png
  97. BIN  src/qt/res/icons/export.png
  98. BIN  src/qt/res/icons/history.png
  99. BIN  src/qt/res/icons/key.png
  100. BIN  src/qt/res/icons/lock_closed.png
  101. BIN  src/qt/res/icons/lock_open.png
  102. BIN  src/qt/res/icons/notsynced.png
  103. BIN  src/qt/res/icons/overview.png
  104. BIN  src/qt/res/icons/quit.png
  105. BIN  src/qt/res/icons/receive.png
  106. BIN  src/qt/res/icons/remove.png
  107. BIN  src/qt/res/icons/send.png
  108. BIN  src/qt/res/icons/synced.png
  109. BIN  src/qt/res/icons/toolbar.png
  110. BIN  src/qt/res/icons/toolbar_testnet.png
  111. BIN  src/qt/res/icons/transaction0.png
  112. BIN  src/qt/res/icons/transaction2.png
  113. BIN  src/qt/res/icons/tx_inout.png
  114. BIN  src/qt/res/icons/tx_input.png
  115. BIN  src/qt/res/icons/tx_mined.png
  116. BIN  src/qt/res/icons/tx_output.png
  117. BIN  src/qt/res/images/about.png
  118. BIN  src/qt/res/images/splash2.jpg
  119. BIN  src/qt/res/movies/update_spinner.mng
  120. +115 −0 src/qt/res/src/bitcoin.svg
  121. +261 −0 src/qt/res/src/clock1.svg
  122. +262 −0 src/qt/res/src/clock2.svg
  123. +261 −0 src/qt/res/src/clock3.svg
  124. +261 −0 src/qt/res/src/clock4.svg
  125. +262 −0 src/qt/res/src/clock5.svg
  126. +262 −0 src/qt/res/src/clock_green.svg
  127. +122 −0 src/qt/res/src/inout.svg
  128. +159 −0 src/qt/res/src/questionmark.svg
  129. +243 −0 src/qt/sendcoinsdialog.cpp
  130. +51 −0 src/qt/sendcoinsdialog.h
  131. +145 −0 src/qt/sendcoinsentry.cpp
  132. +51 −0 src/qt/sendcoinsentry.h
  133. +292 −0 src/qt/transactiondesc.cpp
  134. +24 −0 src/qt/transactiondesc.h
  135. +20 −0 src/qt/transactiondescdialog.cpp
  136. +25 −0 src/qt/transactiondescdialog.h
  137. +86 −0 src/qt/transactionfilterproxy.cpp
  138. +50 −0 src/qt/transactionfilterproxy.h
  139. +264 −0 src/qt/transactionrecord.cpp
  140. +118 −0 src/qt/transactionrecord.h
  141. +622 −0 src/qt/transactiontablemodel.cpp
  142. +79 −0 src/qt/transactiontablemodel.h
  143. +385 −0 src/qt/transactionview.cpp
  144. +77 −0 src/qt/transactionview.h
  145. +277 −0 src/qt/walletmodel.cpp
  146. +143 −0 src/qt/walletmodel.h
  147. +49 −0 src/qtui.h
  148. +1 −0  src/script.cpp
  149. +1 −0  src/serialize.h
  150. +3 −1 src/ui.h
  151. +4 −6 src/util.cpp
  152. +4 −6 src/util.h
  153. +17 −2 src/wallet.cpp
  154. +1 −0  src/wallet.h
View
13 .gitignore
@@ -9,3 +9,16 @@ src/bitcoind
*.o
*.patch
.bitcoin
+#compilation and Qt preprocessor part
+*.o
+ui_*.h
+*.qm
+moc_*
+Makefile
+bitcoin-qt
+#resources cpp
+qrc_*.cpp
+#qt creator
+*.pro.user
+#mac specific
+.DS_Store
View
1  README.md
@@ -27,4 +27,3 @@ help test the Bitcoin core, please contact QA@BitcoinTesting.org.
Feature branches are created when there are major new features being
worked on by several people.
-
View
185 bitcoin-qt.pro
@@ -0,0 +1,185 @@
+TEMPLATE = app
+TARGET =
+INCLUDEPATH += src src/json src/cryptopp src/qt
+DEFINES += QT_GUI
+# DEFINES += SSL
+CONFIG += no_include_pwd
+
+# for boost 1.37, add -mt to the boost libraries
+LIBS += -lssl -lcrypto -ldb_cxx
+unix:!macx:LIBS += -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread
+macx:LIBS += -lboost_system-mt -lboost_filesystem-mt -lboost_program_options-mt -lboost_thread-mt
+macx:DEFINES += __WXMAC_OSX__ MSG_NOSIGNAL=0 BOOST_FILESYSTEM_VERSION=3
+windows:LIBS += -lboost_system-mgw44-mt-1_43 -lboost_filesystem-mgw44-mt-1_43 -lboost_program_options-mgw44-mt-1_43 -lboost_thread-mgw44-mt-1_43 -lws2_32 -lgdi32
+windows:DEFINES += __WXMSW__
+windows:RC_FILE = src/qt/res/bitcoin-qt.rc
+
+# use: qmake "USE_UPNP=1"
+# miniupnpc (http://miniupnp.free.fr/files/) must be installed
+count(USE_UPNP, 1) {
+ message(Building with UPNP support)
+ DEFINES += USE_UPNP=$$USE_UPNP
+ LIBS += -lminiupnpc
+}
+
+count(USE_DBUS, 1) {
+ message(Building with DBUS (Freedesktop notifications) support)
+ DEFINES += QT_DBUS
+ QT += dbus
+}
+
+# for extra security against potential buffer overflows
+QMAKE_CXXFLAGS += -fstack-protector
+QMAKE_LFLAGS += -fstack-protector
+
+# disable quite some warnings because bitcoin core "sins" a lot
+QMAKE_CXXFLAGS_WARN_ON = -fdiagnostics-show-option -Wall -Wno-invalid-offsetof -Wno-unused-variable -Wno-unused-parameter -Wno-sign-compare -Wno-char-subscripts -Wno-unused-value -Wno-sequence-point -Wno-parentheses -Wno-unknown-pragmas -Wno-switch
+
+# Input
+DEPENDPATH += src/qt src src/cryptopp src json/include
+HEADERS += src/qt/bitcoingui.h \
+ src/qt/transactiontablemodel.h \
+ src/qt/addresstablemodel.h \
+ src/qt/optionsdialog.h \
+ src/qt/sendcoinsdialog.h \
+ src/qt/addressbookpage.h \
+ src/qt/aboutdialog.h \
+ src/qt/editaddressdialog.h \
+ src/qt/bitcoinaddressvalidator.h \
+ src/base58.h \
+ src/bignum.h \
+ src/util.h \
+ src/uint256.h \
+ src/serialize.h \
+ src/cryptopp/stdcpp.h \
+ src/cryptopp/smartptr.h \
+ src/cryptopp/simple.h \
+ src/cryptopp/sha.h \
+ src/cryptopp/secblock.h \
+ src/cryptopp/pch.h \
+ src/cryptopp/misc.h \
+ src/cryptopp/iterhash.h \
+ src/cryptopp/cryptlib.h \
+ src/cryptopp/cpu.h \
+ src/cryptopp/config.h \
+ src/strlcpy.h \
+ src/main.h \
+ src/net.h \
+ src/key.h \
+ src/db.h \
+ src/script.h \
+ src/noui.h \
+ src/init.h \
+ src/headers.h \
+ src/irc.h \
+ src/json/json_spirit_writer_template.h \
+ src/json/json_spirit_writer.h \
+ src/json/json_spirit_value.h \
+ src/json/json_spirit_utils.h \
+ src/json/json_spirit_stream_reader.h \
+ src/json/json_spirit_reader_template.h \
+ src/json/json_spirit_reader.h \
+ src/json/json_spirit_error_position.h \
+ src/json/json_spirit.h \
+ src/qt/clientmodel.h \
+ src/qt/guiutil.h \
+ src/qt/transactionrecord.h \
+ src/qt/guiconstants.h \
+ src/qt/optionsmodel.h \
+ src/qt/monitoreddatamapper.h \
+ src/qtui.h \
+ src/qt/transactiondesc.h \
+ src/qt/transactiondescdialog.h \
+ src/qt/bitcoinamountfield.h \
+ src/wallet.h \
+ src/keystore.h \
+ src/qt/transactionfilterproxy.h \
+ src/qt/transactionview.h \
+ src/qt/walletmodel.h \
+ src/bitcoinrpc.h \
+ src/qt/overviewpage.h \
+ src/qt/csvmodelwriter.h \
+ src/crypter.h \
+ src/qt/sendcoinsentry.h \
+ src/qt/qvalidatedlineedit.h \
+ src/qt/bitcoinunits.h \
+ src/qt/qvaluecombobox.h \
+ src/qt/askpassphrasedialog.h \
+ src/protocol.h \
+ src/qt/notificator.h
+
+SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
+ src/qt/transactiontablemodel.cpp \
+ src/qt/addresstablemodel.cpp \
+ src/qt/optionsdialog.cpp \
+ src/qt/sendcoinsdialog.cpp \
+ src/qt/addressbookpage.cpp \
+ src/qt/aboutdialog.cpp \
+ src/qt/editaddressdialog.cpp \
+ src/qt/bitcoinaddressvalidator.cpp \
+ src/cryptopp/sha.cpp \
+ src/cryptopp/cpu.cpp \
+ src/util.cpp \
+ src/script.cpp \
+ src/main.cpp \
+ src/init.cpp \
+ src/net.cpp \
+ src/irc.cpp \
+ src/db.cpp \
+ src/json/json_spirit_writer.cpp \
+ src/json/json_spirit_value.cpp \
+ src/json/json_spirit_reader.cpp \
+ src/qt/clientmodel.cpp \
+ src/qt/guiutil.cpp \
+ src/qt/transactionrecord.cpp \
+ src/qt/optionsmodel.cpp \
+ src/qt/monitoreddatamapper.cpp \
+ src/qt/transactiondesc.cpp \
+ src/qt/transactiondescdialog.cpp \
+ src/qt/bitcoinstrings.cpp \
+ src/qt/bitcoinamountfield.cpp \
+ src/wallet.cpp \
+ src/keystore.cpp \
+ src/qt/transactionfilterproxy.cpp \
+ src/qt/transactionview.cpp \
+ src/qt/walletmodel.cpp \
+ src/bitcoinrpc.cpp \
+ src/qt/overviewpage.cpp \
+ src/qt/csvmodelwriter.cpp \
+ src/crypter.cpp \
+ src/qt/sendcoinsentry.cpp \
+ src/qt/qvalidatedlineedit.cpp \
+ src/qt/bitcoinunits.cpp \
+ src/qt/qvaluecombobox.cpp \
+ src/qt/askpassphrasedialog.cpp \
+ src/protocol.cpp \
+ src/qt/notificator.cpp
+
+RESOURCES += \
+ src/qt/bitcoin.qrc
+
+FORMS += \
+ src/qt/forms/sendcoinsdialog.ui \
+ src/qt/forms/addressbookpage.ui \
+ src/qt/forms/aboutdialog.ui \
+ src/qt/forms/editaddressdialog.ui \
+ src/qt/forms/transactiondescdialog.ui \
+ src/qt/forms/overviewpage.ui \
+ src/qt/forms/sendcoinsentry.ui \
+ src/qt/forms/askpassphrasedialog.ui
+
+CODECFORTR = UTF-8
+# for lrelease/lupdate
+TRANSLATIONS = src/qt/locale/bitcoin_nl.ts src/qt/locale/bitcoin_de.ts \
+ src/qt/locale/bitcoin_ru.ts
+
+OTHER_FILES += \
+ README.rst
+
+# For use with MacPorts
+macx:INCLUDEPATH += /opt/local/include /opt/local/include/db48
+macx:LIBS += -L/opt/local/lib -L/opt/local/lib/db48
+
+# Additional Mac options
+macx:ICON = src/qt/res/icons/bitcoin.icns
+macx:TARGET = "Bitcoin Qt"
View
43 contrib/miniupnpc/Portfile
@@ -0,0 +1,43 @@
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id$
+
+PortSystem 1.0
+
+name miniupnpc
+epoch 2
+version 1.6
+revision 2
+categories net
+platforms darwin
+license BSD
+maintainers singingwolfboy openmaintainer
+description Lightweight client for UPnP protocol
+long_description \
+ ${description}
+
+homepage http://miniupnp.free.fr/
+master_sites http://miniupnp.free.fr/files/download.php?file=${distname}${extract.suffix}&dummy=
+checksums md5 88055f2d4a061cfd4cfe25a9eae22f67 \
+ sha1 ef8f2edb17f2e7c5b8dc67ee80a65c199d823e0a \
+ rmd160 d86b75b331a3fb5525c71708548f311977c0598f
+
+use_configure no
+
+variant universal {}
+if {[variant_isset universal]} {
+ set archflags ${configure.universal_cflags}
+} else {
+ set archflags ${configure.cc_archflags}
+}
+
+build.args-append CC="${configure.cc} ${archflags}"
+
+post-patch {
+ reinplace "s|-Wl,-install_name,|-Wl,-install_name,${prefix}/lib/|" ${worksrcpath}/Makefile
+}
+
+destroot.destdir PREFIX=${prefix} INSTALLPREFIX=${destroot}${prefix}
+
+livecheck.type regex
+livecheck.url http://miniupnp.free.fr/files/
+livecheck.regex ${name}-(\\d+(\\.\\d{1,4})+)${extract.suffix}
View
73 doc/assets-attribution.txt
@@ -0,0 +1,73 @@
+Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png,
+ src/qt/res/src/*.svg
+Designer: Wladimir van der Laan
+License: Creative Commons Attribution
+
+Icon: src/qt/res/icons/send.png
+Icon Pack: Vista Style Arrow
+Designer: Icons Land
+License: Freeware Non-commercial
+Site: http://findicons.com/icon/231371/right3green
+
+Icon: src/qt/res/icons/address-book.png
+Icon Pack: Farm-Fresh Web
+Designer: FatCow Web Hosting
+License: Creative Commons Attribution (by)
+Site: http://findicons.com/icon/163938/book_open
+
+Icon: src/qt/res/icons/connect*.png, src/qt/res/icons/synced.png, src/qt/res/icons/lock_*.png
+Icon Pack: Human-O2
+Designer: schollidesign
+License: GNU/GPL
+Site: http://findicons.com/icon/93743/blocks_gnome_netstatus_0
+
+Icon: src/qt/res/icons/transaction*.png
+Designer: md2k7
+Site: https://forum.bitcoin.org/index.php?topic=15276.0
+License: You are free to do with these icons as you wish, including selling,
+ copying, modifying etc.
+
+Icon: src/qt/res/icons/configure.png, src/qt/res/icons/quit.png,
+ src/qt/res/icons/editcopy.png, src/qt/res/icons/editpaste.png,
+ src/qt/res/icons/add.png, src/qt/res/icons/edit.png,
+ src/qt/res/icons/remove.png (edited)
+Designer: http://www.everaldo.com
+Icon Pack: Crystal SVG
+License: LGPL
+
+Icon: src/qt/res/icons/receive.png, src/qt/res/icons/history.png,
+ src/qt/res/icons/export.png
+Designer: Oxygen team
+Icon Pack: Oxygen
+License: Creative Common Attribution-ShareAlike 3.0 License or LGPL
+Site: http://www.oxygen-icons.org/
+
+Icon: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png
+Designer: Bitboy (optimized for 16x16 by Wladimir van der Laan)
+License: Public Domain
+Site: http://forum.bitcoin.org/?topic=1756.0
+
+Icon: src/qt/res/icons/overview.png
+Icon Pack: Primo
+Designer: Jack Cai
+License: Creative Commons Attribution No Derivatives (by-nd)
+Site: http://findicons.com/icon/175944/home?id=176221#
+
+Icon: scripts/img/reload.xcf (modified),src/qt/res/movies/update_spinner.mng
+Icon Pack: Kids
+Designer: Everaldo (Everaldo Coelho)
+License: GNU/GPL
+Site: http://findicons.com/icon/17102/reload?id=17102
+
+Image: src/qt/res/images/splash2.jpg (Wallet image)
+Designer: Crobbo (forum)
+Site: https://bitcointalk.org/index.php?topic=32273.0
+License: Public domain
+
+Icon: src/qt/res/icons/key.png
+Designer: VisualPharm (Ivan Boyko)
+Icon Pack: Must Have
+Site: http://findicons.com/icon/51009/key?id=51009
+License: Creative Commons Attribution (by)
+
+
View
162 doc/readme-qt.rst
@@ -0,0 +1,162 @@
+Bitcoin-qt: Qt4 based GUI replacement for Bitcoin
+=================================================
+
+Features
+========
+
+- All functionality of the Wx GUI, including wallet encryption
+
+- Compatibility with Linux (both GNOME and KDE), MacOSX and Windows
+
+- Notification on incoming / outgoing transactions (compatible with FreeDesktop and other desktop notification schemes)
+
+- General interface improvements: Splash screen, tabbed interface
+
+- Overview page with current balance, unconfirmed balance, and such
+
+- Better transaction list with status icons, real-time filtering and a context menu
+
+- Asks for confirmation before sending coins, for your own safety
+
+- CSV export of transactions and address book (for Excel bookkeeping)
+
+- Shows alternative icon when connected to testnet, so you never accidentally send real coins during testing
+
+- Shows a progress bar on initial block download, so that you don't have to wonder how many blocks it needs to download to be up to date
+
+- Sendmany support, send to multiple recipients at the same time
+
+- Multiple unit support, can show subdivided bitcoins (uBTC, mBTC) for users that like large numbers
+
+- Support for English, German, Russian and Dutch languages
+
+- Address books and transaction table can be sorted by any column
+
+- Accepts "bitcoin:" URLs from browsers and other sources through drag and drop
+
+Build instructions
+===================
+
+Debian
+-------
+
+First, make sure that the required packages for Qt4 development of your
+distribution are installed, for Debian and Ubuntu these are:
+
+::
+
+ apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \
+ libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \
+ libssl-dev libdb4.8++-dev
+
+then execute the following:
+
+::
+
+ qmake
+ make
+
+Alternatively, install Qt Creator and open the `bitcoin-qt.pro` file.
+
+An executable named `bitcoin-qt` will be built.
+
+
+Windows
+--------
+
+Windows build instructions:
+
+- Download the `QT Windows SDK`_ and install it. You don't need the Symbian stuff, just the desktop Qt.
+
+- Download and extract the `dependencies archive`_ [#]_, or compile openssl, boost and dbcxx yourself.
+
+- Copy the contents of the folder "deps" to "X:\\QtSDK\\mingw", replace X:\\ with the location where you installed the Qt SDK. Make sure that the contents of "deps\\include" end up in the current "include" directory.
+
+- Open the .pro file in QT creator and build as normal (ctrl-B)
+
+.. _`QT Windows SDK`: http://qt.nokia.com/downloads/sdk-windows-cpp
+.. _`dependencies archive`: https://download.visucore.com/bitcoin/qtgui_deps_1.zip
+.. [#] PGP signature: https://download.visucore.com/bitcoin/qtgui_deps_1.zip.sig (signed with RSA key ID `610945D0`_)
+.. _`610945D0`: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x610945D0
+
+
+Mac OS X
+--------
+
+- Download and install the `Qt Mac OS X SDK`_. It is recommended to also install Apple's Xcode with UNIX tools.
+
+- Download and install `MacPorts`_.
+
+- Execute the following commands in a terminal to get the dependencies:
+
+::
+
+ sudo port selfupdate
+ sudo port install boost db48
+
+- Open the .pro file in Qt Creator and build as normal (cmd-B)
+
+.. _`Qt Mac OS X SDK`: http://qt.nokia.com/downloads/sdk-mac-os-cpp
+.. _`MacPorts`: http://www.macports.org/install.php
+
+
+Build configuration options
+============================
+
+UPNnP port forwarding
+---------------------
+
+To use UPnP for port forwarding behind a NAT router (recommended, as more connections overall allow for a faster and more stable bitcoin experience), pass the following argument to qmake:
+
+::
+
+ qmake "USE_UPNP=1"
+
+(in **Qt Creator**, you can find the setting for additional qmake arguments under "Projects" -> "Build Settings" -> "Build Steps", then click "Details" next to **qmake**)
+
+This requires miniupnpc for UPnP port mapping. It can be downloaded from
+http://miniupnp.tuxfamily.org/files/. UPnP support is not compiled in by default.
+
+Set USE_UPNP to a different value to control this:
+
++------------+--------------------------------------------------------------+
+| USE_UPNP= | (the default) no UPnP support, miniupnpc not required; |
++------------+--------------------------------------------------------------+
+| USE_UPNP=0 | UPnP support turned off by default at runtime; |
++------------+--------------------------------------------------------------+
+| USE_UPNP=1 | UPnP support turned on by default at runtime. |
++------------+--------------------------------------------------------------+
+
+Mac OS X users: miniupnpc is currently outdated on MacPorts. An updated Portfile is provided in contrib/miniupnpc within this project.
+You can execute the following commands in a terminal to install it:
+
+::
+
+ cd <location of bitcoin-qt>/contrib/miniupnpc
+ sudo port install
+
+Notification support for recent (k)ubuntu versions
+---------------------------------------------------
+
+To see desktop notifications on (k)ubuntu versions starting from 10.04, enable usage of the
+FreeDesktop notification interface through DBUS using the following qmake option:
+
+::
+
+ qmake "USE_DBUS=1"
+
+Berkely DB version warning
+==========================
+
+A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**).
+
+The static binary version of Bitcoin is linked against libdb4.7 or libdb4.8 (see also `this Debian issue`_).
+
+Now the nasty thing is that databases from 5.X are not compatible with 4.X.
+
+If the globally installed development package of Berkely DB installed on your system is 5.X, any source you
+build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded,
+and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without
+significant hassle!
+
+.. _`this Debian issue`: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425
View
63 scripts/qt/extract_strings_qt.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+'''
+Extract _("...") strings for translation and convert to Qt4 stringdefs so that
+they can be picked up by Qt linguist.
+'''
+from subprocess import Popen, PIPE
+
+OUT_CPP="src/qt/bitcoinstrings.cpp"
+EMPTY=['""']
+
+def parse_po(text):
+ """
+ Parse 'po' format produced by xgettext.
+ Return a list of (msgid,msgstr) tuples.
+ """
+ messages = []
+ msgid = []
+ msgstr = []
+ in_msgid = False
+ in_msgstr = False
+
+ for line in text.split('\n'):
+ line = line.rstrip('\r')
+ if line.startswith('msgid '):
+ if in_msgstr:
+ messages.append((msgid, msgstr))
+ in_msgstr = False
+ # message start
+ in_msgid = True
+
+ msgid = [line[6:]]
+ elif line.startswith('msgstr '):
+ in_msgid = False
+ in_msgstr = True
+ msgstr = [line[7:]]
+ elif line.startswith('"'):
+ if in_msgid:
+ msgid.append(line)
+ if in_msgstr:
+ msgstr.append(line)
+
+ if in_msgstr:
+ messages.append((msgid, msgstr))
+
+ return messages
+
+files = ['src/base58.h', 'src/bignum.h', 'src/db.cpp', 'src/db.h', 'src/headers.h', 'src/init.cpp', 'src/init.h', 'src/irc.cpp', 'src/irc.h', 'src/key.h', 'src/main.cpp', 'src/main.h', 'src/net.cpp', 'src/net.h', 'src/noui.h', 'src/script.cpp', 'src/script.h', 'src/serialize.h', 'src/strlcpy.h', 'src/uint256.h', 'src/util.cpp', 'src/util.h']
+
+# xgettext -n --keyword=_ $FILES
+child = Popen(['xgettext','--output=-','-n','--keyword=_'] + files, stdout=PIPE)
+(out, err) = child.communicate()
+
+messages = parse_po(out)
+
+f = open(OUT_CPP, 'w')
+f.write('#include <QtGlobal>\n')
+f.write('// Automatically generated by extract_strings.py\n')
+f.write('static const char *bitcoin_strings[] = {')
+for (msgid, msgstr) in messages:
+ if msgid != EMPTY:
+ f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid)))
+f.write('};')
+f.close()
View
BIN  scripts/qt/img/reload.xcf
Binary file not shown
View
43 scripts/qt/make_spinner.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# W.J. van der Laan, 2011
+# Make spinning .mng animation from a .png
+# Requires imagemagick 6.7+
+from __future__ import division
+from os import path
+from PIL import Image
+from subprocess import Popen
+
+SRC='img/reload_scaled.png'
+DST='../../src/qt/res/movies/update_spinner.mng'
+TMPDIR='/tmp'
+TMPNAME='tmp-%03i.png'
+NUMFRAMES=35
+FRAMERATE=10.0
+CONVERT='convert'
+CLOCKWISE=True
+DSIZE=(16,16)
+
+im_src = Image.open(SRC)
+
+if CLOCKWISE:
+ im_src = im_src.transpose(Image.FLIP_LEFT_RIGHT)
+
+def frame_to_filename(frame):
+ return path.join(TMPDIR, TMPNAME % frame)
+
+frame_files = []
+for frame in xrange(NUMFRAMES):
+ rotation = (frame + 0.5) / NUMFRAMES * 360.0
+ if CLOCKWISE:
+ rotation = -rotation
+ im_new = im_src.rotate(rotation, Image.BICUBIC)
+ im_new.thumbnail(DSIZE, Image.ANTIALIAS)
+ outfile = frame_to_filename(frame)
+ im_new.save(outfile, 'png')
+ frame_files.append(outfile)
+
+p = Popen([CONVERT, "-delay", str(FRAMERATE), "-dispose", "2"] + frame_files + [DST])
+p.communicate()
+
+
+
View
9 scripts/qt/make_windows_icon.py
@@ -0,0 +1,9 @@
+#!/bin/bash
+# create multiresolution windows icon
+ICON_SRC=../../src/qt/res/icons/bitcoin.png
+ICON_DST=../../src/qt/res/icons/bitcoin.ico
+convert ${ICON_SRC} -resize 16x16 bitcoin-16.png
+convert ${ICON_SRC} -resize 32x32 bitcoin-32.png
+convert ${ICON_SRC} -resize 48x48 bitcoin-48.png
+convert bitcoin-16.png bitcoin-32.png bitcoin-48.png ${ICON_DST}
+
View
4 src/rpc.cpp → src/bitcoinrpc.cpp
@@ -50,13 +50,13 @@ Object JSONRPCError(int code, const string& message)
}
-void PrintConsole(const char* format, ...)
+void PrintConsole(const std::string &format, ...)
{
char buffer[50000];
int limit = sizeof(buffer);
va_list arg_ptr;
va_start(arg_ptr, format);
- int ret = _vsnprintf(buffer, limit, format, arg_ptr);
+ int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
View
0  src/rpc.h → src/bitcoinrpc.h
File renamed without changes
View
4 src/headers.h
@@ -99,8 +99,12 @@
#include "uibase.h"
#include "ui.h"
#else
+#ifdef QT_GUI
+#include "qtui.h"
+#else
#include "noui.h"
#endif
+#endif
#ifdef GUI
#include "xpm/addressbook16.xpm"
View
18 src/init.cpp
@@ -4,7 +4,7 @@
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h"
#include "db.h"
-#include "rpc.h"
+#include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
@@ -80,7 +80,7 @@ void HandleSIGTERM(int)
//
// Start
//
-#ifndef GUI
+#if !defined(QT_GUI) && !defined(GUI)
int main(int argc, char* argv[])
{
bool fRet = false;
@@ -240,10 +240,9 @@ bool AppInit2(int argc, char* argv[])
fServer = GetBoolArg("-server");
/* force fServer when running without GUI */
-#ifndef GUI
+#if !defined(QT_GUI) && !defined(GUI)
fServer = true;
#endif
-
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
@@ -252,6 +251,7 @@ bool AppInit2(int argc, char* argv[])
fNoListen = GetBoolArg("-nolisten") || fTOR;
fLogTimestamps = GetBoolArg("-logtimestamps");
+#ifndef QT_GUI
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]))
fCommandLine = true;
@@ -261,6 +261,7 @@ bool AppInit2(int argc, char* argv[])
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
+#endif
#ifndef __WXMSW__
if (fDaemon)
@@ -373,18 +374,21 @@ bool AppInit2(int argc, char* argv[])
strErrors = "";
int64 nStart;
+ InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n");
nStart = GetTimeMillis();
if (!LoadAddresses())
strErrors += _("Error loading addr.dat \n");
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors += _("Error loading blkindex.dat \n");
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
@@ -415,12 +419,14 @@ bool AppInit2(int argc, char* argv[])
}
if (pindexBest != pindexRescan)
{
+ InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
+ InitMessage(_("Done loading"));
printf("Done loading\n");
//// debug print
@@ -543,7 +549,7 @@ bool AppInit2(int argc, char* argv[])
RandAddSeedPerfmon();
if (!CreateThread(StartNode, NULL))
- wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
+ wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
if (fServer)
CreateThread(ThreadRPCServer, NULL);
@@ -553,7 +559,7 @@ bool AppInit2(int argc, char* argv[])
SetStartOnSystemStartup(true);
#endif
-#ifndef GUI
+#if !defined(QT_GUI) && !defined(GUI)
while (1)
Sleep(5000);
#endif
View
11 src/main.cpp
@@ -32,6 +32,7 @@ uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
const int nTotalBlocksEstimate = 140700; // Conservative estimate of total nr of blocks on main chain
const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
+int nMaxBlocksOfPeers = 0; // Amount of blocks that other nodes claim to have
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
@@ -726,6 +727,12 @@ int GetTotalBlocksEstimate()
}
}
+// Return maximum amount of blocks that other nodes claim to have
+int GetNumBlocksOfPeers()
+{
+ return std::max(nMaxBlocksOfPeers, GetTotalBlocksEstimate());
+}
+
bool IsInitialBlockDownload()
{
if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
@@ -1840,6 +1847,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+ if(pfrom->nStartingHeight > nMaxBlocksOfPeers)
+ {
+ nMaxBlocksOfPeers = pfrom->nStartingHeight;
+ }
}
View
1  src/main.h
@@ -99,6 +99,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
int GetTotalBlocksEstimate();
+int GetNumBlocksOfPeers();
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
View
4 src/makefile.linux-mingw
@@ -49,7 +49,7 @@ HEADERS = \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
@@ -76,7 +76,7 @@ OBJS= \
obj/main.o \
obj/net.o \
obj/protocol.o \
- obj/rpc.o \
+ obj/bitcoinrpc.o \
obj/script.o \
obj/util.o \
obj/wallet.o \
View
4 src/makefile.mingw
@@ -46,7 +46,7 @@ HEADERS = \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
@@ -74,7 +74,7 @@ OBJS= \
obj/main.o \
obj/net.o \
obj/protocol.o \
- obj/rpc.o \
+ obj/bitcoinrpc.o \
obj/script.o \
obj/util.o \
obj/wallet.o \
View
4 src/makefile.osx
@@ -46,7 +46,7 @@ HEADERS = \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
@@ -65,7 +65,7 @@ OBJS= \
obj/main.o \
obj/net.o \
obj/protocol.o \
- obj/rpc.o \
+ obj/bitcoinrpc.o \
obj/script.o \
obj/util.o \
obj/wallet.o \
View
4 src/makefile.unix
@@ -52,7 +52,7 @@ HEADERS = \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
@@ -71,7 +71,7 @@ OBJS= \
obj/main.o \
obj/net.o \
obj/protocol.o \
- obj/rpc.o \
+ obj/bitcoinrpc.o \
obj/script.o \
obj/util.o \
obj/wallet.o \
View
2  src/makefile.vc
@@ -59,7 +59,7 @@ HEADERS = \
net.h \
noui.h \
protocol.h \
- rpc.h \
+ bitcoinrpc.h \
script.h \
serialize.h \
strlcpy.h \
View
4 src/noui.h
@@ -67,4 +67,8 @@ inline void MainFrameRepaint()
{
}
+inline void InitMessage(const std::string &message)
+{
+}
+
#endif
View
26 src/qt/aboutdialog.cpp
@@ -0,0 +1,26 @@
+#include "aboutdialog.h"
+#include "ui_aboutdialog.h"
+#include "clientmodel.h"
+
+AboutDialog::AboutDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AboutDialog)
+{
+ ui->setupUi(this);
+
+}
+
+void AboutDialog::setModel(ClientModel *model)
+{
+ ui->versionLabel->setText(model->formatFullVersion());
+}
+
+AboutDialog::~AboutDialog()
+{
+ delete ui;
+}
+
+void AboutDialog::on_buttonBox_accepted()
+{
+ close();
+}
View
27 src/qt/aboutdialog.h
@@ -0,0 +1,27 @@
+#ifndef ABOUTDIALOG_H
+#define ABOUTDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class AboutDialog;
+}
+class ClientModel;
+
+class AboutDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AboutDialog(QWidget *parent = 0);
+ ~AboutDialog();
+
+ void setModel(ClientModel *model);
+private:
+ Ui::AboutDialog *ui;
+
+private slots:
+ void on_buttonBox_accepted();
+};
+
+#endif // ABOUTDIALOG_H
View
215 src/qt/addressbookpage.cpp
@@ -0,0 +1,215 @@
+#include "addressbookpage.h"
+#include "ui_addressbookpage.h"
+
+#include "addresstablemodel.h"
+#include "editaddressdialog.h"
+#include "csvmodelwriter.h"
+
+#include <QSortFilterProxyModel>
+#include <QClipboard>
+#include <QFileDialog>
+#include <QMessageBox>
+
+AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AddressBookPage),
+ model(0),
+ mode(mode),
+ tab(tab)
+{
+ ui->setupUi(this);
+ switch(mode)
+ {
+ case ForSending:
+ connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept()));
+ ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ ui->tableView->setFocus();
+ break;
+ case ForEditing:
+ ui->buttonBox->hide();
+ break;
+ }
+ switch(tab)
+ {
+ case SendingTab:
+ ui->labelExplanation->hide();
+ break;
+ case ReceivingTab:
+ break;
+ }
+ ui->tableView->setTabKeyNavigation(false);
+
+ connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+}
+
+AddressBookPage::~AddressBookPage()
+{
+ delete ui;
+}
+
+void AddressBookPage::setModel(AddressTableModel *model)
+{
+ this->model = model;
+ // Refresh list from core
+ model->updateList();
+
+ proxyModel = new QSortFilterProxyModel(this);
+ proxyModel->setSourceModel(model);
+ proxyModel->setDynamicSortFilter(true);
+ switch(tab)
+ {
+ case ReceivingTab:
+ // Receive filter
+ proxyModel->setFilterRole(AddressTableModel::TypeRole);
+ proxyModel->setFilterFixedString(AddressTableModel::Receive);
+ break;
+ case SendingTab:
+ // Send filter
+ proxyModel->setFilterRole(AddressTableModel::TypeRole);
+ proxyModel->setFilterFixedString(AddressTableModel::Send);
+ break;
+ }
+ ui->tableView->setModel(proxyModel);
+ ui->tableView->sortByColumn(0, Qt::AscendingOrder);
+
+ // Set column widths
+ ui->tableView->horizontalHeader()->resizeSection(
+ AddressTableModel::Address, 320);
+ ui->tableView->horizontalHeader()->setResizeMode(
+ AddressTableModel::Label, QHeaderView::Stretch);
+
+ connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(selectionChanged()));
+
+ if(mode == ForSending)
+ {
+ // Auto-select first row when in sending mode
+ ui->tableView->selectRow(0);
+ }
+ selectionChanged();
+}
+
+QTableView *AddressBookPage::getCurrentTable()
+{
+ return ui->tableView;
+}
+
+void AddressBookPage::on_copyToClipboard_clicked()
+{
+ // Copy currently selected address to clipboard
+ // (or nothing, if nothing selected)
+ QTableView *table = getCurrentTable();
+ QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
+
+ foreach (QModelIndex index, indexes)
+ {
+ QVariant address = index.data();
+ QApplication::clipboard()->setText(address.toString());
+ }
+}
+
+void AddressBookPage::on_newAddressButton_clicked()
+{
+ EditAddressDialog dlg(
+ tab == SendingTab ?
+ EditAddressDialog::NewSendingAddress :
+ EditAddressDialog::NewReceivingAddress);
+ dlg.setModel(model);
+ if(dlg.exec())
+ {
+ // Select row for newly created address
+ QString address = dlg.getAddress();
+ QModelIndexList lst = proxyModel->match(proxyModel->index(0,
+ AddressTableModel::Address, QModelIndex()),
+ Qt::EditRole, address, 1, Qt::MatchExactly);
+ if(!lst.isEmpty())
+ {
+ ui->tableView->setFocus();
+ ui->tableView->selectRow(lst.at(0).row());
+ }
+ }
+}
+
+void AddressBookPage::on_deleteButton_clicked()
+{
+ QTableView *table = getCurrentTable();
+ QModelIndexList indexes = table->selectionModel()->selectedRows();
+ if(!indexes.isEmpty())
+ {
+ table->model()->removeRow(indexes.at(0).row());
+ }
+}
+
+void AddressBookPage::selectionChanged()
+{
+ // Set button states based on selected tab and selection
+ QTableView *table = getCurrentTable();
+
+ if(table->selectionModel()->hasSelection())
+ {
+ switch(tab)
+ {
+ case SendingTab:
+ ui->deleteButton->setEnabled(true);
+ break;
+ case ReceivingTab:
+ ui->deleteButton->setEnabled(false);
+ break;
+ }
+ ui->copyToClipboard->setEnabled(true);
+ }
+ else
+ {
+ ui->deleteButton->setEnabled(false);
+ ui->copyToClipboard->setEnabled(false);
+ }
+}
+
+void AddressBookPage::done(int retval)
+{
+ // When this is a tab/widget and not a model dialog, ignore "done"
+ if(mode == ForEditing)
+ return;
+
+ // Figure out which address was selected, and return it
+ QTableView *table = getCurrentTable();
+ QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
+
+ foreach (QModelIndex index, indexes)
+ {
+ QVariant address = table->model()->data(index);
+ returnValue = address.toString();
+ }
+
+ if(returnValue.isEmpty())
+ {
+ retval = Rejected;
+ }
+
+ QDialog::done(retval);
+}
+
+void AddressBookPage::exportClicked()
+{
+ // CSV is currently the only supported format
+ QString filename = QFileDialog::getSaveFileName(
+ this,
+ tr("Export Address Book Data"),
+ QDir::currentPath(),
+ tr("Comma separated file (*.csv)"));
+
+ if (filename.isNull()) return;
+
+ CSVModelWriter writer(filename);
+
+ // name, column, role
+ writer.setModel(proxyModel);
+ writer.addColumn("Label", AddressTableModel::Label, Qt::EditRole);
+ writer.addColumn("Address", AddressTableModel::Address, Qt::EditRole);
+
+ if(!writer.write())
+ {
+ QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
+ QMessageBox::Abort, QMessageBox::Abort);
+ }
+}
View
59 src/qt/addressbookpage.h
@@ -0,0 +1,59 @@
+#ifndef ADDRESSBOOKPAGE_H
+#define ADDRESSBOOKPAGE_H
+
+#include <QDialog>
+
+namespace Ui {
+ class AddressBookPage;
+}
+class AddressTableModel;
+
+QT_BEGIN_NAMESPACE
+class QTableView;
+class QItemSelection;
+class QSortFilterProxyModel;
+QT_END_NAMESPACE
+
+class AddressBookPage : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum Tabs {
+ SendingTab = 0,
+ ReceivingTab = 1
+ };
+
+ enum Mode {
+ ForSending, // Pick address for sending
+ ForEditing // Open address book for editing
+ };
+
+ explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent = 0);
+ ~AddressBookPage();
+
+ void setModel(AddressTableModel *model);
+ const QString &getReturnValue() const { return returnValue; }
+
+public slots:
+ void done(int retval);
+ void exportClicked();
+
+private:
+ Ui::AddressBookPage *ui;
+ AddressTableModel *model;
+ Mode mode;
+ Tabs tab;
+ QString returnValue;
+ QSortFilterProxyModel *proxyModel;
+
+ QTableView *getCurrentTable();
+
+private slots:
+ void on_deleteButton_clicked();
+ void on_newAddressButton_clicked();
+ void on_copyToClipboard_clicked();
+ void selectionChanged();
+};
+
+#endif // ADDRESSBOOKDIALOG_H
View
347 src/qt/addresstablemodel.cpp
@@ -0,0 +1,347 @@
+#include "addresstablemodel.h"
+#include "guiutil.h"
+#include "walletmodel.h"
+
+#include "headers.h"
+
+#include <QFont>
+#include <QColor>
+
+const QString AddressTableModel::Send = "S";
+const QString AddressTableModel::Receive = "R";
+
+struct AddressTableEntry
+{
+ enum Type {
+ Sending,
+ Receiving
+ };
+
+ Type type;
+ QString label;
+ QString address;
+
+ AddressTableEntry() {}
+ AddressTableEntry(Type type, const QString &label, const QString &address):
+ type(type), label(label), address(address) {}
+};
+
+// Private implementation
+struct AddressTablePriv
+{
+ CWallet *wallet;
+ QList<AddressTableEntry> cachedAddressTable;
+
+ AddressTablePriv(CWallet *wallet):
+ wallet(wallet) {}
+
+ void refreshAddressTable()
+ {
+ cachedAddressTable.clear();
+
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ {
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, std::string)& item, wallet->mapAddressBook)
+ {
+ const CBitcoinAddress& address = item.first;
+ const std::string& strName = item.second;
+ bool fMine = wallet->HaveKey(address);
+ cachedAddressTable.append(AddressTableEntry(fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending,
+ QString::fromStdString(strName),
+ QString::fromStdString(address.ToString())));
+ }
+ }
+ }
+
+ int size()
+ {
+ return cachedAddressTable.size();
+ }
+
+ AddressTableEntry *index(int idx)
+ {
+ if(idx >= 0 && idx < cachedAddressTable.size())
+ {
+ return &cachedAddressTable[idx];
+ }
+ else
+ {
+ return 0;
+ }
+ }
+};
+
+AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
+ QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
+{
+ columns << tr("Label") << tr("Address");
+ priv = new AddressTablePriv(wallet);
+ priv->refreshAddressTable();
+}
+
+AddressTableModel::~AddressTableModel()
+{
+ delete priv;
+}
+
+int AddressTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return priv->size();
+}
+
+int AddressTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return columns.length();
+}
+
+QVariant AddressTableModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid())
+ return QVariant();
+
+ AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
+
+ if(role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ switch(index.column())
+ {
+ case Label:
+ if(rec->label.isEmpty() && role == Qt::DisplayRole)
+ {
+ return tr("(no label)");
+ }
+ else
+ {
+ return rec->label;
+ }
+ case Address:
+ return rec->address;
+ }
+ }
+ else if (role == Qt::FontRole)
+ {
+ QFont font;
+ if(index.column() == Address)
+ {
+ font = GUIUtil::bitcoinAddressFont();
+ }
+ return font;
+ }
+ else if (role == TypeRole)
+ {
+ switch(rec->type)
+ {
+ case AddressTableEntry::Sending:
+ return Send;
+ case AddressTableEntry::Receiving:
+ return Receive;
+ default: break;
+ }
+ }
+ return QVariant();
+}
+
+bool AddressTableModel::setData(const QModelIndex & index, const QVariant & value, int role)
+{
+ if(!index.isValid())
+ return false;
+ AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
+
+ editStatus = OK;
+
+ if(role == Qt::EditRole)
+ {
+ switch(index.column())
+ {
+ case Label:
+ wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
+ rec->label = value.toString();
+ break;
+ case Address:
+ // Refuse to set invalid address, set error status and return false
+ if(!walletModel->validateAddress(value.toString()))
+ {
+ editStatus = INVALID_ADDRESS;
+ return false;
+ }
+ // Double-check that we're not overwriting a receiving address
+ if(rec->type == AddressTableEntry::Sending)
+ {
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ {
+ // Remove old entry
+ wallet->DelAddressBookName(rec->address.toStdString());
+ // Add new entry with new address
+ wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
+ }
+
+ rec->address = value.toString();
+ }
+ break;
+ }
+ emit dataChanged(index, index);
+
+ return true;
+ }
+ return false;
+}
+
+QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole)
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags AddressTableModel::flags(const QModelIndex & index) const
+{
+ if(!index.isValid())
+ return 0;
+ AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
+
+ Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ // Can edit address and label for sending addresses,
+ // and only label for receiving addresses.
+ if(rec->type == AddressTableEntry::Sending ||
+ (rec->type == AddressTableEntry::Receiving && index.column()==Label))
+ {
+ retval |= Qt::ItemIsEditable;
+ }
+ return retval;
+}
+
+QModelIndex AddressTableModel::index(int row, int column, const QModelIndex & parent) const
+{
+ Q_UNUSED(parent);
+ AddressTableEntry *data = priv->index(row);
+ if(data)
+ {
+ return createIndex(row, column, priv->index(row));
+ }
+ else
+ {
+ return QModelIndex();
+ }
+}
+
+void AddressTableModel::updateList()
+{
+ // Update address book model from Bitcoin core
+ beginResetModel();
+ priv->refreshAddressTable();
+ endResetModel();
+}
+
+QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address)
+{
+ std::string strLabel = label.toStdString();
+ std::string strAddress = address.toStdString();
+
+ editStatus = OK;
+
+ if(type == Send)
+ {
+ if(!walletModel->validateAddress(address))
+ {
+ editStatus = INVALID_ADDRESS;
+ return QString();
+ }
+ // Check for duplicate addresses
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ {
+ if(wallet->mapAddressBook.count(strAddress))
+ {
+ editStatus = DUPLICATE_ADDRESS;
+ return QString();
+ }
+ }
+ }
+ else if(type == Receive)
+ {
+ // Generate a new address to associate with given label
+ WalletModel::UnlockContext ctx(walletModel->requestUnlock());
+ if(!ctx.isValid())
+ {
+ // Unlock wallet failed or was cancelled
+ editStatus = WALLET_UNLOCK_FAILURE;
+ return QString();
+ }
+ std::vector<unsigned char> newKey;
+ if(!wallet->GetKeyFromPool(newKey, true))
+ {
+ editStatus = KEY_GENERATION_FAILURE;
+ return QString();
+ }
+ strAddress = CBitcoinAddress(newKey).ToString();
+ }
+ else
+ {
+ return QString();
+ }
+ // Add entry and update list
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ wallet->SetAddressBookName(strAddress, strLabel);
+ updateList();
+ return QString::fromStdString(strAddress);
+}
+
+bool AddressTableModel::removeRows(int row, int count, const QModelIndex & parent)
+{
+ Q_UNUSED(parent);
+ AddressTableEntry *rec = priv->index(row);
+ if(count != 1 || !rec || rec->type == AddressTableEntry::Receiving)
+ {
+ // Can only remove one row at a time, and cannot remove rows not in model.
+ // Also refuse to remove receiving addresses.
+ return false;
+ }
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ {
+ wallet->DelAddressBookName(rec->address.toStdString());
+ }
+ updateList();
+ return true;
+}
+
+void AddressTableModel::update()
+{
+
+}
+
+/* Look up label for address in address book, if not found return empty string.
+ */
+QString AddressTableModel::labelForAddress(const QString &address) const
+{
+ CRITICAL_BLOCK(wallet->cs_wallet)
+ {
+ CBitcoinAddress address_parsed(address.toStdString());
+ std::map<CBitcoinAddress, std::string>::iterator mi = wallet->mapAddressBook.find(address_parsed);
+ if (mi != wallet->mapAddressBook.end())
+ {
+ return QString::fromStdString(mi->second);
+ }
+ }
+ return QString();
+}
+
+int AddressTableModel::lookupAddress(const QString &address) const
+{
+ QModelIndexList lst = match(index(0, Address, QModelIndex()),
+ Qt::EditRole, address, 1, Qt::MatchExactly);
+ if(lst.isEmpty())
+ {
+ return -1;
+ }
+ else
+ {
+ return lst.at(0).row();
+ }
+}
+
View
83 src/qt/addresstablemodel.h
@@ -0,0 +1,83 @@
+#ifndef ADDRESSTABLEMODEL_H
+#define ADDRESSTABLEMODEL_H
+
+#include <QAbstractTableModel>
+#include <QStringList>
+
+class AddressTablePriv;
+class CWallet;
+class WalletModel;
+
+class AddressTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ explicit AddressTableModel(CWallet *wallet, WalletModel *parent = 0);
+ ~AddressTableModel();
+
+ enum ColumnIndex {
+ Label = 0, /* User specified label */
+ Address = 1 /* Bitcoin address */
+ };
+
+ enum RoleIndex {
+ TypeRole = Qt::UserRole
+ };
+
+ // Return status of last edit/insert operation
+ enum EditStatus {
+ OK,
+ INVALID_ADDRESS,
+ DUPLICATE_ADDRESS,
+ WALLET_UNLOCK_FAILURE,
+ KEY_GENERATION_FAILURE
+ };
+
+ static const QString Send; /* Send addres */
+ static const QString Receive; /* Receive address */
+
+ /* Overridden methods from QAbstractTableModel */
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ bool setData(const QModelIndex & index, const QVariant & value, int role);
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex & parent) const;
+ bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
+ Qt::ItemFlags flags(const QModelIndex & index) const;
+
+ /* Add an address to the model.
+ Returns the added address on success, and an empty string otherwise.
+ */
+ QString addRow(const QString &type, const QString &label, const QString &address);
+
+ /* Update address list from core. Invalidates any indices.
+ */
+ void updateList();
+
+ /* Look up label for address in address book, if not found return empty string.
+ */
+ QString labelForAddress(const QString &address) const;
+
+ /* Look up row index of an address in the model.
+ Return -1 if not found.
+ */
+ int lookupAddress(const QString &address) const;
+
+ EditStatus getEditStatus() const { return editStatus; }
+
+private:
+ WalletModel *walletModel;
+ CWallet *wallet;
+ AddressTablePriv *priv;
+ QStringList columns;
+ EditStatus editStatus;
+
+signals:
+ void defaultAddressChanged(const QString &address);
+
+public slots:
+ void update();
+};
+
+#endif // ADDRESSTABLEMODEL_H
View
186 src/qt/askpassphrasedialog.cpp
@@ -0,0 +1,186 @@
+#include "askpassphrasedialog.h"
+#include "ui_askpassphrasedialog.h"
+
+#include "guiconstants.h"
+#include "walletmodel.h"
+
+#include <QMessageBox>
+#include <QPushButton>
+
+AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::AskPassphraseDialog),
+ mode(mode),
+ model(0)
+{
+ ui->setupUi(this);
+ ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
+ ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
+ ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
+
+ switch(mode)
+ {
+ case Encrypt: // Ask passphrase x2
+ ui->passLabel1->hide();
+ ui->passEdit1->hide();
+ ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>10 or more random characters</b>, or <b>eight or more words</b>."));
+ setWindowTitle(tr("Encrypt wallet"));
+ break;
+ case Unlock: // Ask passphrase
+ ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
+ ui->passLabel2->hide();
+ ui->passEdit2->hide();
+ ui->passLabel3->hide();
+ ui->passEdit3->hide();
+ setWindowTitle(tr("Unlock wallet"));
+ break;
+ case Decrypt: // Ask passphrase
+ ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
+ ui->passLabel2->hide();
+ ui->passEdit2->hide();
+ ui->passLabel3->hide();
+ ui->passEdit3->hide();
+ setWindowTitle(tr("Decrypt wallet"));
+ break;
+ case ChangePass: // Ask old passphrase + new passphrase x2
+ setWindowTitle(tr("Change passphrase"));
+ ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
+ break;
+ }
+ resize(minimumSize()); // Get rid of extra space in dialog
+
+ textChanged();
+ connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
+ connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
+ connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
+}
+
+AskPassphraseDialog::~AskPassphraseDialog()
+{
+ // Attempt to overwrite text so that they do not linger around in memory
+ ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
+ ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
+ ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
+ delete ui;
+}
+
+void AskPassphraseDialog::setModel(WalletModel *model)
+{
+ this->model = model;
+}
+
+void AskPassphraseDialog::accept()
+{
+ std::string oldpass, newpass1, newpass2;
+ // TODO: mlock memory / munlock on return so they will not be swapped out, really need "mlockedstring" wrapper class to do this safely
+ oldpass.reserve(MAX_PASSPHRASE_SIZE);
+ newpass1.reserve(MAX_PASSPHRASE_SIZE);
+ newpass2.reserve(MAX_PASSPHRASE_SIZE);
+ oldpass.assign(ui->passEdit1->text().toStdString());
+ newpass1.assign(ui->passEdit2->text().toStdString());
+ newpass2.assign(ui->passEdit3->text().toStdString());
+
+ switch(mode)
+ {
+ case Encrypt: {
+ if(newpass1.empty() || newpass2.empty())
+ {
+ // Cannot encrypt with empty passphrase
+ break;
+ }
+ QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
+ tr("WARNING: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!\nAre you sure you wish to encrypt your wallet?"),
+ QMessageBox::Yes|QMessageBox::Cancel,
+ QMessageBox::Cancel);
+ if(retval == QMessageBox::Yes)
+ {
+ if(newpass1 == newpass2)
+ {
+ if(model->setWalletEncrypted(true, newpass1))
+ {
+ QMessageBox::warning(this, tr("Wallet encrypted"),
+ tr("Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer."));
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Wallet encryption failed"),
+ tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
+ }
+ QDialog::accept(); // Success
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Wallet encryption failed"),
+ tr("The supplied passphrases do not match."));
+ }
+ }
+ else
+ {
+ QDialog::reject(); // Cancelled
+ }
+ } break;
+ case Unlock:
+ if(!model->setWalletLocked(false, oldpass))
+ {
+ QMessageBox::critical(this, tr("Wallet unlock failed"),
+ tr("The passphrase entered for the wallet decryption was incorrect."));
+ }
+ else
+ {
+ QDialog::accept(); // Success
+ }
+ break;
+ case Decrypt:
+ if(!model->setWalletEncrypted(false, oldpass))
+ {
+ QMessageBox::critical(this, tr("Wallet decryption failed"),
+ tr("The passphrase entered for the wallet decryption was incorrect."));
+ }
+ else
+ {
+ QDialog::accept(); // Success
+ }
+ break;
+ case ChangePass:
+ if(newpass1 == newpass2)
+ {
+ if(model->changePassphrase(oldpass, newpass1))
+ {
+ QMessageBox::information(this, tr("Wallet encrypted"),
+ tr("Wallet passphrase was succesfully changed."));
+ QDialog::accept(); // Success
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Wallet encryption failed"),
+ tr("The passphrase entered for the wallet decryption was incorrect."));
+ }
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Wallet encryption failed"),
+ tr("The supplied passphrases do not match."));
+ }
+ break;
+ }
+}
+
+void AskPassphraseDialog::textChanged()
+{
+ // Validate input, set Ok button to enabled when accepable
+ bool acceptable = false;
+ switch(mode)
+ {
+ case Encrypt: // New passphrase x2
+ acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
+ break;
+ case Unlock: // Old passphrase x1
+ case Decrypt:
+ acceptable = !ui->passEdit1->text().isEmpty();
+ break;
+ case ChangePass: // Old passphrase x1, new passphrase x2
+ acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
+ break;
+ }
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
+}
View
40 src/qt/askpassphrasedialog.h
@@ -0,0 +1,40 @@
+#ifndef ASKPASSPHRASEDIALOG_H
+#define ASKPASSPHRASEDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+ class AskPassphraseDialog;
+}
+
+class WalletModel;
+
+class AskPassphraseDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum Mode {
+ Encrypt, // Ask passphrase x2
+ Unlock, // Ask passphrase
+ ChangePass, // Ask old passphrase + new passphrase x2
+ Decrypt // Ask passphrase
+ };
+
+ explicit AskPassphraseDialog(Mode mode, QWidget *parent = 0);
+ ~AskPassphraseDialog();
+
+ void accept();
+
+ void setModel(WalletModel *model);
+
+private:
+ Ui::AskPassphraseDialog *ui;
+ Mode mode;
+ WalletModel *model;
+
+private slots:
+ void textChanged();
+};
+
+#endif // ASKPASSPHRASEDIALOG_H
View
170 src/qt/bitcoin.cpp
@@ -0,0 +1,170 @@
+/*
+ * W.J. van der Laan 2011
+ */
+#include "bitcoingui.h"
+#include "clientmodel.h"
+#include "walletmodel.h"
+#include "optionsmodel.h"
+
+#include "headers.h"
+#include "init.h"
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QThread>
+#include <QTextCodec>
+#include <QLocale>
+#include <QTranslator>
+#include <QSplashScreen>
+
+// Need a global reference for the notifications to find the GUI
+BitcoinGUI *guiref;
+QSplashScreen *splashref;
+
+int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
+{
+ // Message from main thread
+ if(guiref)
+ {
+ guiref->error(QString::fromStdString(caption),
+ QString::fromStdString(message));
+ }
+ else
+ {
+ QMessageBox::critical(0, QString::fromStdString(caption),
+ QString::fromStdString(message),
+ QMessageBox::Ok, QMessageBox::Ok);
+ }
+ return 4;
+}
+
+int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
+{
+ // Message from network thread
+ if(guiref)
+ {
+ QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
+ Q_ARG(QString, QString::fromStdString(caption)),
+ Q_ARG(QString, QString::fromStdString(message)));
+ }
+ else
+ {
+ printf("%s: %s\n", caption.c_str(), message.c_str());
+ fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ }
+ return 4;
+}
+
+bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
+{
+ if(!guiref)
+ return false;
+ if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
+ return true;
+ bool payFee = false;
+
+ // Call slot on GUI thread.
+ // If called from another thread, use a blocking QueuedConnection.
+ Qt::ConnectionType connectionType = Qt::DirectConnection;
+ if(QThread::currentThread() != QCoreApplication::instance()->thread())
+ {
+ connectionType = Qt::BlockingQueuedConnection;
+ }
+
+ QMetaObject::invokeMethod(guiref, "askFee", connectionType,
+ Q_ARG(qint64, nFeeRequired),
+ Q_ARG(bool*, &payFee));
+
+ return payFee;
+}
+
+void CalledSetStatusBar(const std::string& strText, int nField)
+{
+ // Only used for built-in mining, which is disabled, simple ignore
+}
+
+void UIThreadCall(boost::function0<void> fn)
+{
+ // Only used for built-in mining, which is disabled, simple ignore
+}
+
+void MainFrameRepaint()
+{
+}
+
+void InitMessage(const std::string &message)
+{
+ if(splashref)
+ {
+ splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200));
+ QApplication::instance()->processEvents();
+ }
+}
+
+/*
+ Translate string to current locale using Qt.
+ */
+std::string _(const char* psz)
+{
+ return QCoreApplication::translate("bitcoin-core", psz).toStdString();
+}
+
+int main(int argc, char *argv[])
+{
+ QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
+ QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
+
+ Q_INIT_RESOURCE(bitcoin);
+ QApplication app(argc, argv);
+
+ // Load language file for system locale
+ QString locale = QLocale::system().name();
+ QTranslator translator;
+ translator.load("bitcoin_"+locale);
+ app.installTranslator(&translator);
+
+ QSplashScreen splash(QPixmap(":/images/splash"), 0);
+ splash.show();
+ splash.setAutoFillBackground(true);
+ splashref = &splash;
+
+ app.processEvents();
+
+ app.setQuitOnLastWindowClosed(false);
+
+ try
+ {
+ if(AppInit2(argc, argv))
+ {
+ {
+ // Put this in a block, so that BitcoinGUI is cleaned up properly before
+ // calling Shutdown().
+ BitcoinGUI window;
+ splash.finish(&window);
+ OptionsModel optionsModel(pwalletMain);
+ ClientModel clientModel(&optionsModel);
+ WalletModel walletModel(pwalletMain, &optionsModel);
+
+ guiref = &window;
+ window.setClientModel(&clientModel);
+ window.setWalletModel(&walletModel);
+
+ window.show();
+
+ app.exec();
+
+ guiref = 0;
+ }
+ Shutdown(NULL);
+ }
+ else
+ {
+ return 1;
+ }
+ } catch (std::exception& e) {
+ PrintException(&e, "Runaway exception");
+ } catch (...) {
+ PrintException(NULL, "Runaway exception");
+ }
+ return 0;
+}
View
48 src/qt/bitcoin.qrc
@@ -0,0 +1,48 @@
+<RCC>
+ <qresource prefix="/icons" lang="edit">
+ <file alias="bitcoin">res/icons/bitcoin.png</file>
+ <file alias="address-book">res/icons/address-book.png</file>
+ <file alias="quit">res/icons/quit.png</file>
+ <file alias="send">res/icons/send.png</file>
+ <file alias="toolbar">res/icons/toolbar.png</file>
+ <file alias="connect_0">res/icons/connect0_16.png</file>
+ <file alias="connect_1">res/icons/connect1_16.png</file>
+ <file alias="connect_2">res/icons/connect2_16.png</file>
+ <file alias="connect_3">res/icons/connect3_16.png</file>
+ <file alias="connect_4">res/icons/connect4_16.png</file>
+ <file alias="transaction_0">res/icons/transaction0.png</file>
+ <file alias="transaction_confirmed">res/icons/transaction2.png</file>
+ <file alias="transaction_1">res/icons/clock1.png</file>
+ <file alias="transaction_2">res/icons/clock2.png</file>
+ <file alias="transaction_3">res/icons/clock3.png</file>
+ <file alias="transaction_4">res/icons/clock4.png</file>
+ <file alias="transaction_5">res/icons/clock5.png</file>
+ <file alias="options">res/icons/configure.png</file>
+ <file alias="receiving_addresses">res/icons/receive.png</file>
+ <file alias="editpaste">res/icons/editpaste.png</file>
+ <file alias="editcopy">res/icons/editcopy.png</file>
+ <file alias="add">res/icons/add.png</file>
+ <file alias="bitcoin_testnet">res/icons/bitcoin_testnet.png</file>
+ <file alias="toolbar_testnet">res/icons/toolbar_testnet.png</file>
+ <file alias="edit">res/icons/edit.png</file>
+ <file alias="history">res/icons/history.png</file>
+ <file alias="overview">res/icons/overview.png</file>
+ <file alias="export">res/icons/export.png</file>
+ <file alias="synced">res/icons/synced.png</file>
+ <file alias="remove">res/icons/remove.png</file>
+ <file alias="tx_mined">res/icons/tx_mined.png</file>
+ <file alias="tx_input">res/icons/tx_input.png</file>
+ <file alias="tx_output">res/icons/tx_output.png</file>
+ <file alias="tx_inout">res/icons/tx_inout.png</file>
+ <file alias="lock_closed">res/icons/lock_closed.png</file>
+ <file alias="lock_open">res/icons/lock_open.png</file>
+ <file alias="key">res/icons/key.png</file>
+ </qresource>
+ <qresource prefix="/images">
+ <file alias="about">res/images/about.png</file>
+ <file alias="splash">res/images/splash2.jpg</file>
+ </qresource>
+ <qresource prefix="/movies">
+ <file alias="update_spinner">res/movies/update_spinner.mng</file>
+ </qresource>
+</RCC>
View
67 src/qt/bitcoinaddressvalidator.cpp
@@ -0,0 +1,67 @@
+#include "bitcoinaddressvalidator.h"
+
+/* Base58 characters are:
+ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
+
+ This is:
+ - All numbers except for '0'
+ - All uppercase letters except for 'I' and 'O'
+ - All lowercase letters except for 'l'
+
+ User friendly Base58 input can map
+ - 'l' and 'I' to '1'
+ - '0' and 'O' to 'o'
+*/
+
+BitcoinAddressValidator::BitcoinAddressValidator(QObject *parent) :
+ QValidator(parent)
+{
+}
+
+QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const
+{
+ // Correction
+ for(int idx=0; idx<input.size(); ++idx)
+ {
+ switch(input.at(idx).unicode())
+ {
+ case 'l':
+ case 'I':
+ input[idx] = QChar('1');
+ break;
+ case '0':
+ case 'O':
+ input[idx] = QChar('o');
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Validation
+ QValidator::State state = QValidator::Acceptable;
+ for(int idx=0; idx<input.size(); ++idx)
+ {
+ int ch = input.at(idx).unicode();
+
+ if(((ch >= '0' && ch<='9') ||
+ (ch >= 'a' && ch<='z'<