13
.gitignore
vendored
|
@ -9,3 +9,16 @@ src/bitcoind
|
||||||
*.o
|
*.o
|
||||||
*.patch
|
*.patch
|
||||||
.bitcoin
|
.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
|
||||||
|
|
|
@ -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
|
Feature branches are created when there are major new features being
|
||||||
worked on by several people.
|
worked on by several people.
|
||||||
|
|
||||||
|
|
185
bitcoin-qt.pro
Normal file
|
@ -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"
|
43
contrib/miniupnpc/Portfile
Normal file
|
@ -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}
|
73
doc/assets-attribution.txt
Normal file
|
@ -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)
|
||||||
|
|
||||||
|
|
162
doc/readme-qt.rst
Normal file
|
@ -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
|
63
scripts/qt/extract_strings_qt.py
Executable file
|
@ -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()
|
BIN
scripts/qt/img/reload.xcf
Normal file
43
scripts/qt/make_spinner.py
Executable file
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
9
scripts/qt/make_windows_icon.py
Executable file
|
@ -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}
|
||||||
|
|
|
@ -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];
|
char buffer[50000];
|
||||||
int limit = sizeof(buffer);
|
int limit = sizeof(buffer);
|
||||||
va_list arg_ptr;
|
va_list arg_ptr;
|
||||||
va_start(arg_ptr, format);
|
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);
|
va_end(arg_ptr);
|
||||||
if (ret < 0 || ret >= limit)
|
if (ret < 0 || ret >= limit)
|
||||||
{
|
{
|
|
@ -99,8 +99,12 @@
|
||||||
#include "uibase.h"
|
#include "uibase.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#else
|
#else
|
||||||
|
#ifdef QT_GUI
|
||||||
|
#include "qtui.h"
|
||||||
|
#else
|
||||||
#include "noui.h"
|
#include "noui.h"
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GUI
|
#ifdef GUI
|
||||||
#include "xpm/addressbook16.xpm"
|
#include "xpm/addressbook16.xpm"
|
||||||
|
|
18
src/init.cpp
|
@ -4,7 +4,7 @@
|
||||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||||
#include "headers.h"
|
#include "headers.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "rpc.h"
|
#include "bitcoinrpc.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "strlcpy.h"
|
#include "strlcpy.h"
|
||||||
|
@ -80,7 +80,7 @@ void HandleSIGTERM(int)
|
||||||
//
|
//
|
||||||
// Start
|
// Start
|
||||||
//
|
//
|
||||||
#ifndef GUI
|
#if !defined(QT_GUI) && !defined(GUI)
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
bool fRet = false;
|
bool fRet = false;
|
||||||
|
@ -240,10 +240,9 @@ bool AppInit2(int argc, char* argv[])
|
||||||
fServer = GetBoolArg("-server");
|
fServer = GetBoolArg("-server");
|
||||||
|
|
||||||
/* force fServer when running without GUI */
|
/* force fServer when running without GUI */
|
||||||
#ifndef GUI
|
#if !defined(QT_GUI) && !defined(GUI)
|
||||||
fServer = true;
|
fServer = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fPrintToConsole = GetBoolArg("-printtoconsole");
|
fPrintToConsole = GetBoolArg("-printtoconsole");
|
||||||
fPrintToDebugger = GetBoolArg("-printtodebugger");
|
fPrintToDebugger = GetBoolArg("-printtodebugger");
|
||||||
|
|
||||||
|
@ -252,6 +251,7 @@ bool AppInit2(int argc, char* argv[])
|
||||||
fNoListen = GetBoolArg("-nolisten") || fTOR;
|
fNoListen = GetBoolArg("-nolisten") || fTOR;
|
||||||
fLogTimestamps = GetBoolArg("-logtimestamps");
|
fLogTimestamps = GetBoolArg("-logtimestamps");
|
||||||
|
|
||||||
|
#ifndef QT_GUI
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
if (!IsSwitchChar(argv[i][0]))
|
if (!IsSwitchChar(argv[i][0]))
|
||||||
fCommandLine = true;
|
fCommandLine = true;
|
||||||
|
@ -261,6 +261,7 @@ bool AppInit2(int argc, char* argv[])
|
||||||
int ret = CommandLineRPC(argc, argv);
|
int ret = CommandLineRPC(argc, argv);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __WXMSW__
|
#ifndef __WXMSW__
|
||||||
if (fDaemon)
|
if (fDaemon)
|
||||||
|
@ -373,18 +374,21 @@ bool AppInit2(int argc, char* argv[])
|
||||||
strErrors = "";
|
strErrors = "";
|
||||||
int64 nStart;
|
int64 nStart;
|
||||||
|
|
||||||
|
InitMessage(_("Loading addresses..."));
|
||||||
printf("Loading addresses...\n");
|
printf("Loading addresses...\n");
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
if (!LoadAddresses())
|
if (!LoadAddresses())
|
||||||
strErrors += _("Error loading addr.dat \n");
|
strErrors += _("Error loading addr.dat \n");
|
||||||
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||||
|
|
||||||
|
InitMessage(_("Loading block index..."));
|
||||||
printf("Loading block index...\n");
|
printf("Loading block index...\n");
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
if (!LoadBlockIndex())
|
if (!LoadBlockIndex())
|
||||||
strErrors += _("Error loading blkindex.dat \n");
|
strErrors += _("Error loading blkindex.dat \n");
|
||||||
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||||
|
|
||||||
|
InitMessage(_("Loading wallet..."));
|
||||||
printf("Loading wallet...\n");
|
printf("Loading wallet...\n");
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
bool fFirstRun;
|
bool fFirstRun;
|
||||||
|
@ -415,12 +419,14 @@ bool AppInit2(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
if (pindexBest != pindexRescan)
|
if (pindexBest != pindexRescan)
|
||||||
{
|
{
|
||||||
|
InitMessage(_("Rescanning..."));
|
||||||
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
|
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
|
||||||
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitMessage(_("Done loading"));
|
||||||
printf("Done loading\n");
|
printf("Done loading\n");
|
||||||
|
|
||||||
//// debug print
|
//// debug print
|
||||||
|
@ -543,7 +549,7 @@ bool AppInit2(int argc, char* argv[])
|
||||||
RandAddSeedPerfmon();
|
RandAddSeedPerfmon();
|
||||||
|
|
||||||
if (!CreateThread(StartNode, NULL))
|
if (!CreateThread(StartNode, NULL))
|
||||||
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
|
wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
|
||||||
|
|
||||||
if (fServer)
|
if (fServer)
|
||||||
CreateThread(ThreadRPCServer, NULL);
|
CreateThread(ThreadRPCServer, NULL);
|
||||||
|
@ -553,7 +559,7 @@ bool AppInit2(int argc, char* argv[])
|
||||||
SetStartOnSystemStartup(true);
|
SetStartOnSystemStartup(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef GUI
|
#if !defined(QT_GUI) && !defined(GUI)
|
||||||
while (1)
|
while (1)
|
||||||
Sleep(5000);
|
Sleep(5000);
|
||||||
#endif
|
#endif
|
||||||
|
|
11
src/main.cpp
|
@ -32,6 +32,7 @@ uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3
|
||||||
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
|
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
|
||||||
const int nTotalBlocksEstimate = 140700; // Conservative estimate of total nr of blocks on main chain
|
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"
|
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;
|
CBlockIndex* pindexGenesisBlock = NULL;
|
||||||
int nBestHeight = -1;
|
int nBestHeight = -1;
|
||||||
CBigNum bnBestChainWork = 0;
|
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()
|
bool IsInitialBlockDownload()
|
||||||
{
|
{
|
||||||
if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
|
if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
|
||||||
|
@ -1840,6 +1847,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
pfrom->fSuccessfullyConnected = true;
|
pfrom->fSuccessfullyConnected = true;
|
||||||
|
|
||||||
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
|
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
|
||||||
|
if(pfrom->nStartingHeight > nMaxBlocksOfPeers)
|
||||||
|
{
|
||||||
|
nMaxBlocksOfPeers = pfrom->nStartingHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash
|
||||||
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
|
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
|
||||||
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
|
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
|
||||||
int GetTotalBlocksEstimate();
|
int GetTotalBlocksEstimate();
|
||||||
|
int GetNumBlocksOfPeers();
|
||||||
bool IsInitialBlockDownload();
|
bool IsInitialBlockDownload();
|
||||||
std::string GetWarnings(std::string strFor);
|
std::string GetWarnings(std::string strFor);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ HEADERS = \
|
||||||
net.h \
|
net.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
rpc.h \
|
bitcoinrpc.h \
|
||||||
script.h \
|
script.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
strlcpy.h \
|
strlcpy.h \
|
||||||
|
@ -76,7 +76,7 @@ OBJS= \
|
||||||
obj/main.o \
|
obj/main.o \
|
||||||
obj/net.o \
|
obj/net.o \
|
||||||
obj/protocol.o \
|
obj/protocol.o \
|
||||||
obj/rpc.o \
|
obj/bitcoinrpc.o \
|
||||||
obj/script.o \
|
obj/script.o \
|
||||||
obj/util.o \
|
obj/util.o \
|
||||||
obj/wallet.o \
|
obj/wallet.o \
|
||||||
|
|
|
@ -46,7 +46,7 @@ HEADERS = \
|
||||||
net.h \
|
net.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
rpc.h \
|
bitcoinrpc.h \
|
||||||
script.h \
|
script.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
strlcpy.h \
|
strlcpy.h \
|
||||||
|
@ -74,7 +74,7 @@ OBJS= \
|
||||||
obj/main.o \
|
obj/main.o \
|
||||||
obj/net.o \
|
obj/net.o \
|
||||||
obj/protocol.o \
|
obj/protocol.o \
|
||||||
obj/rpc.o \
|
obj/bitcoinrpc.o \
|
||||||
obj/script.o \
|
obj/script.o \
|
||||||
obj/util.o \
|
obj/util.o \
|
||||||
obj/wallet.o \
|
obj/wallet.o \
|
||||||
|
|
|
@ -46,7 +46,7 @@ HEADERS = \
|
||||||
net.h \
|
net.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
rpc.h \
|
bitcoinrpc.h \
|
||||||
script.h \
|
script.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
strlcpy.h \
|
strlcpy.h \
|
||||||
|
@ -65,7 +65,7 @@ OBJS= \
|
||||||
obj/main.o \
|
obj/main.o \
|
||||||
obj/net.o \
|
obj/net.o \
|
||||||
obj/protocol.o \
|
obj/protocol.o \
|
||||||
obj/rpc.o \
|
obj/bitcoinrpc.o \
|
||||||
obj/script.o \
|
obj/script.o \
|
||||||
obj/util.o \
|
obj/util.o \
|
||||||
obj/wallet.o \
|
obj/wallet.o \
|
||||||
|
|
|
@ -52,7 +52,7 @@ HEADERS = \
|
||||||
net.h \
|
net.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
rpc.h \
|
bitcoinrpc.h \
|
||||||
script.h \
|
script.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
strlcpy.h \
|
strlcpy.h \
|
||||||
|
@ -71,7 +71,7 @@ OBJS= \
|
||||||
obj/main.o \
|
obj/main.o \
|
||||||
obj/net.o \
|
obj/net.o \
|
||||||
obj/protocol.o \
|
obj/protocol.o \
|
||||||
obj/rpc.o \
|
obj/bitcoinrpc.o \
|
||||||
obj/script.o \
|
obj/script.o \
|
||||||
obj/util.o \
|
obj/util.o \
|
||||||
obj/wallet.o \
|
obj/wallet.o \
|
||||||
|
|
|
@ -59,7 +59,7 @@ HEADERS = \
|
||||||
net.h \
|
net.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
protocol.h \
|
protocol.h \
|
||||||
rpc.h \
|
bitcoinrpc.h \
|
||||||
script.h \
|
script.h \
|
||||||
serialize.h \
|
serialize.h \
|
||||||
strlcpy.h \
|
strlcpy.h \
|
||||||
|
|
|
@ -67,4 +67,8 @@ inline void MainFrameRepaint()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void InitMessage(const std::string &message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
26
src/qt/aboutdialog.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
27
src/qt/aboutdialog.h
Normal file
|
@ -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
|
215
src/qt/addressbookpage.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
59
src/qt/addressbookpage.h
Normal file
|
@ -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
|
347
src/qt/addresstablemodel.cpp
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
83
src/qt/addresstablemodel.h
Normal file
|
@ -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
|
186
src/qt/askpassphrasedialog.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
40
src/qt/askpassphrasedialog.h
Normal file
|
@ -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
|
170
src/qt/bitcoin.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
48
src/qt/bitcoin.qrc
Normal file
|
@ -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>
|
67
src/qt/bitcoinaddressvalidator.cpp
Normal file
|
@ -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') ||
|
||||||
|
(ch >= 'A' && ch<='Z')) &&
|
||||||
|
ch != 'l' && ch != 'I' && ch != '0' && ch != 'O')
|
||||||
|
{
|
||||||
|
// Alphanumeric and not a 'forbidden' character
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = QValidator::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty address is "intermediate" input
|
||||||
|
if(input.isEmpty())
|
||||||
|
{
|
||||||
|
state = QValidator::Intermediate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
24
src/qt/bitcoinaddressvalidator.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef BITCOINADDRESSVALIDATOR_H
|
||||||
|
#define BITCOINADDRESSVALIDATOR_H
|
||||||
|
|
||||||
|
#include <QRegExpValidator>
|
||||||
|
|
||||||
|
/* Base48 entry widget validator.
|
||||||
|
Corrects near-miss characters and refuses characters that are no part of base48.
|
||||||
|
*/
|
||||||
|
class BitcoinAddressValidator : public QValidator
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BitcoinAddressValidator(QObject *parent = 0);
|
||||||
|
|
||||||
|
State validate(QString &input, int &pos) const;
|
||||||
|
|
||||||
|
static const int MaxAddressLength = 34;
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITCOINADDRESSVALIDATOR_H
|
178
src/qt/bitcoinamountfield.cpp
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#include "bitcoinamountfield.h"
|
||||||
|
#include "qvalidatedlineedit.h"
|
||||||
|
#include "qvaluecombobox.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QRegExpValidator>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
BitcoinAmountField::BitcoinAmountField(QWidget *parent):
|
||||||
|
QWidget(parent), amount(0), decimals(0), currentUnit(-1)
|
||||||
|
{
|
||||||
|
amount = new QValidatedLineEdit(this);
|
||||||
|
amount->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), this));
|
||||||
|
amount->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||||
|
amount->installEventFilter(this);
|
||||||
|
amount->setMaximumWidth(75);
|
||||||
|
decimals = new QValidatedLineEdit(this);
|
||||||
|
decimals->setValidator(new QRegExpValidator(QRegExp("[0-9]+"), this));
|
||||||
|
decimals->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
|
||||||
|
decimals->setMaximumWidth(75);
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
layout->addWidget(amount);
|
||||||
|
layout->addWidget(new QLabel(QString("<b>.</b>")));
|
||||||
|
layout->addWidget(decimals);
|
||||||
|
unit = new QValueComboBox(this);
|
||||||
|
unit->setModel(new BitcoinUnits(this));
|
||||||
|
layout->addWidget(unit);
|
||||||
|
layout->addStretch(1);
|
||||||
|
layout->setContentsMargins(0,0,0,0);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
setFocusPolicy(Qt::TabFocus);
|
||||||
|
setFocusProxy(amount);
|
||||||
|
|
||||||
|
// If one if the widgets changes, the combined content changes as well
|
||||||
|
connect(amount, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
|
||||||
|
connect(decimals, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
|
||||||
|
connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));
|
||||||
|
|
||||||
|
// Set default based on configuration
|
||||||
|
unitChanged(unit->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::setText(const QString &text)
|
||||||
|
{
|
||||||
|
const QStringList parts = text.split(QString("."));
|
||||||
|
if(parts.size() == 2)
|
||||||
|
{
|
||||||
|
amount->setText(parts[0]);
|
||||||
|
decimals->setText(parts[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
amount->setText(QString());
|
||||||
|
decimals->setText(QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::clear()
|
||||||
|
{
|
||||||
|
amount->clear();
|
||||||
|
decimals->clear();
|
||||||
|
unit->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitcoinAmountField::validate()
|
||||||
|
{
|
||||||
|
bool valid = true;
|
||||||
|
if(decimals->text().isEmpty())
|
||||||
|
{
|
||||||
|
decimals->setValid(false);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
if(!BitcoinUnits::parse(currentUnit, text(), 0))
|
||||||
|
{
|
||||||
|
setValid(false);
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::setValid(bool valid)
|
||||||
|
{
|
||||||
|
amount->setValid(valid);
|
||||||
|
decimals->setValid(valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BitcoinAmountField::text() const
|
||||||
|
{
|
||||||
|
if(decimals->text().isEmpty() && amount->text().isEmpty())
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return amount->text() + QString(".") + decimals->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intercept '.' and ',' keys, if pressed focus a specified widget
|
||||||
|
bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(object);
|
||||||
|
if(event->type() == QEvent::KeyPress)
|
||||||
|
{
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma)
|
||||||
|
{
|
||||||
|
decimals->setFocus();
|
||||||
|
decimals->selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
|
||||||
|
{
|
||||||
|
QWidget::setTabOrder(prev, amount);
|
||||||
|
QWidget::setTabOrder(amount, decimals);
|
||||||
|
return decimals;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 BitcoinAmountField::value(bool *valid_out) const
|
||||||
|
{
|
||||||
|
qint64 val_out = 0;
|
||||||
|
bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
|
||||||
|
if(valid_out)
|
||||||
|
{
|
||||||
|
*valid_out = valid;
|
||||||
|
}
|
||||||
|
return val_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::setValue(qint64 value)
|
||||||
|
{
|
||||||
|
setText(BitcoinUnits::format(currentUnit, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::unitChanged(int idx)
|
||||||
|
{
|
||||||
|
// Use description tooltip for current unit for the combobox
|
||||||
|
unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());
|
||||||
|
|
||||||
|
// Determine new unit ID
|
||||||
|
int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();
|
||||||
|
|
||||||
|
// Parse current value and convert to new unit
|
||||||
|
bool valid = false;
|
||||||
|
qint64 currentValue = value(&valid);
|
||||||
|
|
||||||
|
currentUnit = newUnit;
|
||||||
|
|
||||||
|
// Set max length after retrieving the value, to prevent truncation
|
||||||
|
amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit));
|
||||||
|
decimals->setMaxLength(BitcoinUnits::decimals(currentUnit));
|
||||||
|
|
||||||
|
if(valid)
|
||||||
|
{
|
||||||
|
// If value was valid, re-place it in the widget with the new unit
|
||||||
|
setValue(currentValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If current value is invalid, just clear field
|
||||||
|
setText("");
|
||||||
|
}
|
||||||
|
setValid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinAmountField::setDisplayUnit(int newUnit)
|
||||||
|
{
|
||||||
|
unit->setValue(newUnit);
|
||||||
|
}
|
59
src/qt/bitcoinamountfield.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef BITCOINFIELD_H
|
||||||
|
#define BITCOINFIELD_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QValidatedLineEdit;
|
||||||
|
class QValueComboBox;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
// Coin amount entry widget with separate parts for whole
|
||||||
|
// coins and decimals.
|
||||||
|
class BitcoinAmountField: public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY textChanged USER true);
|
||||||
|
public:
|
||||||
|
explicit BitcoinAmountField(QWidget *parent = 0);
|
||||||
|
|
||||||
|
qint64 value(bool *valid=0) const;
|
||||||
|
void setValue(qint64 value);
|
||||||
|
|
||||||
|
// Mark current valid as invalid in UI
|
||||||
|
void setValid(bool valid);
|
||||||
|
bool validate();
|
||||||
|
|
||||||
|
// Change current unit
|
||||||
|
void setDisplayUnit(int unit);
|
||||||
|
|
||||||
|
// Make field empty and ready for new input
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// Qt messes up the tab chain by default in some cases (issue http://bugreports.qt.nokia.com/browse/QTBUG-10907)
|
||||||
|
// Hence we have to set it up manually
|
||||||
|
QWidget *setupTabChain(QWidget *prev);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void textChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Intercept '.' and ',' keys, if pressed focus a specified widget
|
||||||
|
bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QValidatedLineEdit *amount;
|
||||||
|
QValidatedLineEdit *decimals;
|
||||||
|
QValueComboBox *unit;
|
||||||
|
int currentUnit;
|
||||||
|
|
||||||
|
void setText(const QString &text);
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void unitChanged(int idx);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BITCOINFIELD_H
|
613
src/qt/bitcoingui.cpp
Normal file
|
@ -0,0 +1,613 @@
|
||||||
|
/*
|
||||||
|
* Qt4 bitcoin GUI.
|
||||||
|
*
|
||||||
|
* W.J. van der Laan 2011
|
||||||
|
*/
|
||||||
|
#include "bitcoingui.h"
|
||||||
|
#include "transactiontablemodel.h"
|
||||||
|
#include "addressbookpage.h"
|
||||||
|
#include "sendcoinsdialog.h"
|
||||||
|
#include "optionsdialog.h"
|
||||||
|
#include "aboutdialog.h"
|
||||||
|
#include "clientmodel.h"
|
||||||
|
#include "walletmodel.h"
|
||||||
|
#include "editaddressdialog.h"
|
||||||
|
#include "optionsmodel.h"
|
||||||
|
#include "transactiondescdialog.h"
|
||||||
|
#include "addresstablemodel.h"
|
||||||
|
#include "transactionview.h"
|
||||||
|
#include "overviewpage.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
#include "guiconstants.h"
|
||||||
|
#include "askpassphrasedialog.h"
|
||||||
|
#include "notificator.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QMenuBar>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QStatusBar>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QStackedWidget>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QMovie>
|
||||||
|
|
||||||
|
#include <QDragEnterEvent>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
BitcoinGUI::BitcoinGUI(QWidget *parent):
|
||||||
|
QMainWindow(parent),
|
||||||
|
clientModel(0),
|
||||||
|
walletModel(0),
|
||||||
|
encryptWalletAction(0),
|
||||||
|
changePassphraseAction(0),
|
||||||
|
trayIcon(0),
|
||||||
|
notificator(0)
|
||||||
|
{
|
||||||
|
resize(850, 550);
|
||||||
|
setWindowTitle(tr("Bitcoin Wallet"));
|
||||||
|
setWindowIcon(QIcon(":icons/bitcoin"));
|
||||||
|
// Accept D&D of URIs
|
||||||
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
createActions();
|
||||||
|
|
||||||
|
// Menus
|
||||||
|
QMenu *file = menuBar()->addMenu(tr("&File"));
|
||||||
|
file->addAction(sendCoinsAction);
|
||||||
|
file->addAction(receiveCoinsAction);
|
||||||
|
file->addSeparator();
|
||||||
|
file->addAction(quitAction);
|
||||||
|
|
||||||
|
QMenu *settings = menuBar()->addMenu(tr("&Settings"));
|
||||||
|
settings->addAction(encryptWalletAction);
|
||||||
|
settings->addAction(changePassphraseAction);
|
||||||
|
settings->addSeparator();
|
||||||
|
settings->addAction(optionsAction);
|
||||||
|
|
||||||
|
QMenu *help = menuBar()->addMenu(tr("&Help"));
|
||||||
|
help->addAction(aboutAction);
|
||||||
|
|
||||||
|
// Toolbars
|
||||||
|
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
|
||||||
|
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||||
|
toolbar->addAction(overviewAction);
|
||||||
|
toolbar->addAction(sendCoinsAction);
|
||||||
|
toolbar->addAction(receiveCoinsAction);
|
||||||
|
toolbar->addAction(historyAction);
|
||||||
|
toolbar->addAction(addressBookAction);
|
||||||
|
|
||||||
|
QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
|
||||||
|
toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||||
|
toolbar2->addAction(exportAction);
|
||||||
|
|
||||||
|
// Create tabs
|
||||||
|
overviewPage = new OverviewPage();
|
||||||
|
|
||||||
|
transactionsPage = new QWidget(this);
|
||||||
|
QVBoxLayout *vbox = new QVBoxLayout();
|
||||||
|
transactionView = new TransactionView(this);
|
||||||
|
vbox->addWidget(transactionView);
|
||||||
|
transactionsPage->setLayout(vbox);
|
||||||
|
|
||||||
|
addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab);
|
||||||
|
|
||||||
|
receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
|
||||||
|
|
||||||
|
sendCoinsPage = new SendCoinsDialog(this);
|
||||||
|
|
||||||
|
centralWidget = new QStackedWidget(this);
|
||||||
|
centralWidget->addWidget(overviewPage);
|
||||||
|
centralWidget->addWidget(transactionsPage);
|
||||||
|
centralWidget->addWidget(addressBookPage);
|
||||||
|
centralWidget->addWidget(receiveCoinsPage);
|
||||||
|
centralWidget->addWidget(sendCoinsPage);
|
||||||
|
setCentralWidget(centralWidget);
|
||||||
|
|
||||||
|
// Create status bar
|
||||||
|
statusBar();
|
||||||
|
|
||||||
|
// Status bar notification icons
|
||||||
|
QFrame *frameBlocks = new QFrame();
|
||||||
|
//frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
|
||||||
|
frameBlocks->setContentsMargins(0,0,0,0);
|
||||||
|
frameBlocks->setMinimumWidth(56);
|
||||||
|
frameBlocks->setMaximumWidth(56);
|
||||||
|
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
|
||||||
|
frameBlocksLayout->setContentsMargins(3,0,3,0);
|
||||||
|
frameBlocksLayout->setSpacing(3);
|
||||||
|
labelEncryptionIcon = new QLabel();
|
||||||
|
labelConnectionsIcon = new QLabel();
|
||||||
|
labelBlocksIcon = new QLabel();
|
||||||
|
frameBlocksLayout->addStretch();
|
||||||
|
frameBlocksLayout->addWidget(labelEncryptionIcon);
|
||||||
|
frameBlocksLayout->addStretch();
|
||||||
|
frameBlocksLayout->addWidget(labelConnectionsIcon);
|
||||||
|
frameBlocksLayout->addStretch();
|
||||||
|
frameBlocksLayout->addWidget(labelBlocksIcon);
|
||||||
|
frameBlocksLayout->addStretch();
|
||||||
|
|
||||||
|
// Progress bar for blocks download
|
||||||
|
progressBarLabel = new QLabel(tr("Synchronizing with network..."));
|
||||||
|
progressBarLabel->setVisible(false);
|
||||||
|
progressBar = new QProgressBar();
|
||||||
|
progressBar->setToolTip(tr("Block chain synchronization in progress"));
|
||||||
|
progressBar->setVisible(false);
|
||||||
|
|
||||||
|
statusBar()->addWidget(progressBarLabel);
|
||||||
|
statusBar()->addWidget(progressBar);
|
||||||
|
statusBar()->addPermanentWidget(frameBlocks);
|
||||||
|
|
||||||
|
createTrayIcon();
|
||||||
|
|
||||||
|
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
|
||||||
|
|
||||||
|
// Clicking on a transaction on the overview page simply sends you to transaction history page
|
||||||
|
connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage()));
|
||||||
|
|
||||||
|
// Doubleclicking on a transaction on the transaction history page shows details
|
||||||
|
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
|
||||||
|
|
||||||
|
gotoOverviewPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::createActions()
|
||||||
|
{
|
||||||
|
QActionGroup *tabGroup = new QActionGroup(this);
|
||||||
|
|
||||||
|
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
|
||||||
|
overviewAction->setToolTip(tr("Show general overview of wallet"));
|
||||||
|
overviewAction->setCheckable(true);
|
||||||
|
tabGroup->addAction(overviewAction);
|
||||||
|
|
||||||
|
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
|
||||||
|
historyAction->setToolTip(tr("Browse transaction history"));
|
||||||
|
historyAction->setCheckable(true);
|
||||||
|
tabGroup->addAction(historyAction);
|
||||||
|
|
||||||
|
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
|
||||||
|
addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
|
||||||
|
addressBookAction->setCheckable(true);
|
||||||
|
tabGroup->addAction(addressBookAction);
|
||||||
|
|
||||||
|
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
|
||||||
|
receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
|
||||||
|
receiveCoinsAction->setCheckable(true);
|
||||||
|
tabGroup->addAction(receiveCoinsAction);
|
||||||
|
|
||||||
|
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
|
||||||
|
sendCoinsAction->setToolTip(tr("Send coins to a bitcoin address"));
|
||||||
|
sendCoinsAction->setCheckable(true);
|
||||||
|
tabGroup->addAction(sendCoinsAction);
|
||||||
|
|
||||||
|
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
|
||||||
|
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
|
||||||
|
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
|
||||||
|
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
|
||||||
|
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
|
||||||
|
|
||||||
|
quitAction = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this);
|
||||||
|
quitAction->setToolTip(tr("Quit application"));
|
||||||
|
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this);
|
||||||
|
aboutAction->setToolTip(tr("Show information about Bitcoin"));
|
||||||
|
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
|
||||||
|
optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
|
||||||
|
openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
|
||||||
|
openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
|
||||||
|
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
|
||||||
|
exportAction->setToolTip(tr("Export the current view to a file"));
|
||||||
|
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
|
||||||
|
encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
|
||||||
|
encryptWalletAction->setCheckable(true);
|
||||||
|
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
|
||||||
|
changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
|
||||||
|
|
||||||
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||||
|
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
||||||
|
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
||||||
|
connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormal()));
|
||||||
|
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
|
||||||
|
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
||||||
|
{
|
||||||
|
this->clientModel = clientModel;
|
||||||
|
|
||||||
|
if(clientModel->isTestNet())
|
||||||
|
{
|
||||||
|
QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]");
|
||||||
|
setWindowTitle(title_testnet);
|
||||||
|
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
|
||||||
|
if(trayIcon)
|
||||||
|
{
|
||||||
|
trayIcon->setToolTip(title_testnet);
|
||||||
|
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep up to date with client
|
||||||
|
setNumConnections(clientModel->getNumConnections());
|
||||||
|
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
|
||||||
|
|
||||||
|
setNumBlocks(clientModel->getNumBlocks());
|
||||||
|
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
|
||||||
|
|
||||||
|
// Report errors from network/worker thread
|
||||||
|
connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::setWalletModel(WalletModel *walletModel)
|
||||||
|
{
|
||||||
|
this->walletModel = walletModel;
|
||||||
|
|
||||||
|
// Report errors from wallet thread
|
||||||
|
connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
|
||||||
|
|
||||||
|
// Put transaction list in tabs
|
||||||
|
transactionView->setModel(walletModel);
|
||||||
|
|
||||||
|
overviewPage->setModel(walletModel);
|
||||||
|
addressBookPage->setModel(walletModel->getAddressTableModel());
|
||||||
|
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
|
||||||
|
sendCoinsPage->setModel(walletModel);
|
||||||
|
|
||||||
|
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||||
|
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
|
||||||
|
|
||||||
|
// Balloon popup for new transaction
|
||||||
|
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||||
|
this, SLOT(incomingTransaction(QModelIndex,int,int)));
|
||||||
|
|
||||||
|
// Ask for passphrase if needed
|
||||||
|
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::createTrayIcon()
|
||||||
|
{
|
||||||
|
QMenu *trayIconMenu = new QMenu(this);
|
||||||
|
trayIconMenu->addAction(openBitcoinAction);
|
||||||
|
trayIconMenu->addAction(optionsAction);
|
||||||
|
trayIconMenu->addSeparator();
|
||||||
|
trayIconMenu->addAction(quitAction);
|
||||||
|
|
||||||
|
trayIcon = new QSystemTrayIcon(this);
|
||||||
|
trayIcon->setContextMenu(trayIconMenu);
|
||||||
|
trayIcon->setToolTip("Bitcoin client");
|
||||||
|
trayIcon->setIcon(QIcon(":/icons/toolbar"));
|
||||||
|
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||||
|
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
|
||||||
|
trayIcon->show();
|
||||||
|
|
||||||
|
notificator = new Notificator(tr("bitcoin-qt"), trayIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||||
|
{
|
||||||
|
if(reason == QSystemTrayIcon::Trigger)
|
||||||
|
{
|
||||||
|
// Click on system tray icon triggers "open bitcoin"
|
||||||
|
openBitcoinAction->trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::optionsClicked()
|
||||||
|
{
|
||||||
|
OptionsDialog dlg;
|
||||||
|
dlg.setModel(clientModel->getOptionsModel());
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::aboutClicked()
|
||||||
|
{
|
||||||
|
AboutDialog dlg;
|
||||||
|
dlg.setModel(clientModel);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::setNumConnections(int count)
|
||||||
|
{
|
||||||
|
QString icon;
|
||||||
|
switch(count)
|
||||||
|
{
|
||||||
|
case 0: icon = ":/icons/connect_0"; break;
|
||||||
|
case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
|
||||||
|
case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
|
||||||
|
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
|
||||||
|
default: icon = ":/icons/connect_4"; break;
|
||||||
|
}
|
||||||
|
labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
|
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::setNumBlocks(int count)
|
||||||
|
{
|
||||||
|
int initTotal = clientModel->getNumBlocksAtStartup();
|
||||||
|
int total = clientModel->getNumBlocksOfPeers();
|
||||||
|
QString tooltip;
|
||||||
|
|
||||||
|
if(count < total)
|
||||||
|
{
|
||||||
|
progressBarLabel->setVisible(true);
|
||||||
|
progressBar->setVisible(true);
|
||||||
|
progressBar->setMaximum(total - initTotal);
|
||||||
|
progressBar->setValue(count - initTotal);
|
||||||
|
tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressBarLabel->setVisible(false);
|
||||||
|
progressBar->setVisible(false);
|
||||||
|
tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
QDateTime lastBlockDate = clientModel->getLastBlockDate();
|
||||||
|
int secs = lastBlockDate.secsTo(now);
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
// Represent time from last generated block in human readable text
|
||||||
|
if(secs < 60)
|
||||||
|
{
|
||||||
|
text = tr("%n second(s) ago","",secs);
|
||||||
|
}
|
||||||
|
else if(secs < 60*60)
|
||||||
|
{
|
||||||
|
text = tr("%n minute(s) ago","",secs/60);
|
||||||
|
}
|
||||||
|
else if(secs < 24*60*60)
|
||||||
|
{
|
||||||
|
text = tr("%n hour(s) ago","",secs/(60*60));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = tr("%n day(s) ago","",secs/(60*60*24));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set icon state: spinning if catching up, tick otherwise
|
||||||
|
if(secs < 30*60)
|
||||||
|
{
|
||||||
|
tooltip = tr("Up to date") + QString("\n") + tooltip;
|
||||||
|
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tooltip = tr("Catching up...") + QString("\n") + tooltip;
|
||||||
|
labelBlocksIcon->setMovie(syncIconMovie);
|
||||||
|
syncIconMovie->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip += QString("\n");
|
||||||
|
tooltip += tr("Last received block was generated %1.").arg(text);
|
||||||
|
|
||||||
|
labelBlocksIcon->setToolTip(tooltip);
|
||||||
|
progressBarLabel->setToolTip(tooltip);
|
||||||
|
progressBar->setToolTip(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::error(const QString &title, const QString &message)
|
||||||
|
{
|
||||||
|
// Report errors from network/worker thread
|
||||||
|
notificator->notify(Notificator::Critical, title, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::changeEvent(QEvent *e)
|
||||||
|
{
|
||||||
|
if (e->type() == QEvent::WindowStateChange)
|
||||||
|
{
|
||||||
|
if(clientModel->getOptionsModel()->getMinimizeToTray())
|
||||||
|
{
|
||||||
|
if (isMinimized())
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
e->ignore();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
e->accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QMainWindow::changeEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
|
||||||
|
!clientModel->getOptionsModel()->getMinimizeOnClose())
|
||||||
|
{
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
QMainWindow::closeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
|
||||||
|
{
|
||||||
|
QString strMessage =
|
||||||
|
tr("This transaction is over the size limit. You can still send it for a fee of %1, "
|
||||||
|
"which goes to the nodes that process your transaction and helps to support the network. "
|
||||||
|
"Do you want to pay the fee?").arg(
|
||||||
|
BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
|
||||||
|
QMessageBox::StandardButton retval = QMessageBox::question(
|
||||||
|
this, tr("Sending..."), strMessage,
|
||||||
|
QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
|
||||||
|
*payFee = (retval == QMessageBox::Yes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
|
||||||
|
{
|
||||||
|
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
|
||||||
|
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
|
||||||
|
.data(Qt::EditRole).toULongLong();
|
||||||
|
if(!clientModel->inInitialBlockDownload())
|
||||||
|
{
|
||||||
|
// On new transaction, make an info balloon
|
||||||
|
// Unless the initial block download is in progress, to prevent balloon-spam
|
||||||
|
QString date = ttm->index(start, TransactionTableModel::Date, parent)
|
||||||
|
.data().toString();
|
||||||
|
QString type = ttm->index(start, TransactionTableModel::Type, parent)
|
||||||
|
.data().toString();
|
||||||
|
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
|
||||||
|
.data().toString();
|
||||||
|
QIcon icon = qvariant_cast<QIcon>(ttm->index(start,
|
||||||
|
TransactionTableModel::ToAddress, parent)
|
||||||
|
.data(Qt::DecorationRole));
|
||||||
|
|
||||||
|
notificator->notify(Notificator::Information,
|
||||||
|
(amount)<0 ? tr("Sent transaction") :
|
||||||
|
tr("Incoming transaction"),
|
||||||
|
tr("Date: %1\n"
|
||||||
|
"Amount: %2\n"
|
||||||
|
"Type: %3\n"
|
||||||
|
"Address: %4\n")
|
||||||
|
.arg(date)
|
||||||
|
.arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
|
||||||
|
.arg(type)
|
||||||
|
.arg(address), icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::gotoOverviewPage()
|
||||||
|
{
|
||||||
|
overviewAction->setChecked(true);
|
||||||
|
centralWidget->setCurrentWidget(overviewPage);
|
||||||
|
|
||||||
|
exportAction->setEnabled(false);
|
||||||
|
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::gotoHistoryPage()
|
||||||
|
{
|
||||||
|
historyAction->setChecked(true);
|
||||||
|
centralWidget->setCurrentWidget(transactionsPage);
|
||||||
|
|
||||||
|
exportAction->setEnabled(true);
|
||||||
|
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
|
||||||
|
connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::gotoAddressBookPage()
|
||||||
|
{
|
||||||
|
addressBookAction->setChecked(true);
|
||||||
|
centralWidget->setCurrentWidget(addressBookPage);
|
||||||
|
|
||||||
|
exportAction->setEnabled(true);
|
||||||
|
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
|
||||||
|
connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::gotoReceiveCoinsPage()
|
||||||
|
{
|
||||||
|
receiveCoinsAction->setChecked(true);
|
||||||
|
centralWidget->setCurrentWidget(receiveCoinsPage);
|
||||||
|
|
||||||
|
exportAction->setEnabled(true);
|
||||||
|
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
|
||||||
|
connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::gotoSendCoinsPage()
|
||||||
|
{
|
||||||
|
sendCoinsAction->setChecked(true);
|
||||||
|
if(centralWidget->currentWidget() != sendCoinsPage)
|
||||||
|
{
|
||||||
|
// Clear the current contents if we arrived from another tab
|
||||||
|
sendCoinsPage->clear();
|
||||||
|
}
|
||||||
|
centralWidget->setCurrentWidget(sendCoinsPage);
|
||||||
|
|
||||||
|
exportAction->setEnabled(false);
|
||||||
|
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
|
||||||
|
{
|
||||||
|
// Accept only URLs
|
||||||
|
if(event->mimeData()->hasUrls())
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::dropEvent(QDropEvent *event)
|
||||||
|
{
|
||||||
|
if(event->mimeData()->hasUrls())
|
||||||
|
{
|
||||||
|
gotoSendCoinsPage();
|
||||||
|
QList<QUrl> urls = event->mimeData()->urls();
|
||||||
|
foreach(const QUrl &url, urls)
|
||||||
|
{
|
||||||
|
sendCoinsPage->handleURL(&url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::setEncryptionStatus(int status)
|
||||||
|
{
|
||||||
|
switch(status)
|
||||||
|
{
|
||||||
|
case WalletModel::Unencrypted:
|
||||||
|
labelEncryptionIcon->hide();
|
||||||
|
encryptWalletAction->setChecked(false);
|
||||||
|
changePassphraseAction->setEnabled(false);
|
||||||
|
encryptWalletAction->setEnabled(true);
|
||||||
|
break;
|
||||||
|
case WalletModel::Unlocked:
|
||||||
|
labelEncryptionIcon->show();
|
||||||
|
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
|
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
|
||||||
|
encryptWalletAction->setChecked(true);
|
||||||
|
changePassphraseAction->setEnabled(true);
|
||||||
|
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||||
|
break;
|
||||||
|
case WalletModel::Locked:
|
||||||
|
labelEncryptionIcon->show();
|
||||||
|
labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
|
||||||
|
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
|
||||||
|
encryptWalletAction->setChecked(true);
|
||||||
|
changePassphraseAction->setEnabled(true);
|
||||||
|
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::encryptWallet(bool status)
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
|
||||||
|
AskPassphraseDialog::Decrypt, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
|
||||||
|
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::changePassphrase()
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcoinGUI::unlockWallet()
|
||||||
|
{
|
||||||
|
// Unlock wallet when requested by wallet model
|
||||||
|
if(walletModel->getEncryptionStatus() == WalletModel::Locked)
|
||||||
|
{
|
||||||
|
AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this);
|
||||||
|
dlg.setModel(walletModel);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
}
|
120
src/qt/bitcoingui.h
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#ifndef BITCOINGUI_H
|
||||||
|
#define BITCOINGUI_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
|
||||||
|
class TransactionTableModel;
|
||||||
|
class ClientModel;
|
||||||
|
class WalletModel;
|
||||||
|
class TransactionView;
|
||||||
|
class OverviewPage;
|
||||||
|
class AddressBookPage;
|
||||||
|
class SendCoinsDialog;
|
||||||
|
class Notificator;
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QLabel;
|
||||||
|
class QLineEdit;
|
||||||
|
class QTableView;
|
||||||
|
class QAbstractItemModel;
|
||||||
|
class QModelIndex;
|
||||||
|
class QProgressBar;
|
||||||
|
class QStackedWidget;
|
||||||
|
class QUrl;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class BitcoinGUI : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BitcoinGUI(QWidget *parent = 0);
|
||||||
|
void setClientModel(ClientModel *clientModel);
|
||||||
|
void setWalletModel(WalletModel *walletModel);
|
||||||
|
|
||||||
|
/* Transaction table tab indices */
|
||||||
|
enum {
|
||||||
|
AllTransactions = 0,
|
||||||
|
SentReceived = 1,
|
||||||
|
Sent = 2,
|
||||||
|
Received = 3
|
||||||
|
} TabIndex;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void changeEvent(QEvent *e);
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
|
void dragEnterEvent(QDragEnterEvent *event);
|
||||||
|
void dropEvent(QDropEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClientModel *clientModel;
|
||||||
|
WalletModel *walletModel;
|
||||||
|
|
||||||
|
QStackedWidget *centralWidget;
|
||||||
|
|
||||||
|
OverviewPage *overviewPage;
|
||||||
|
QWidget *transactionsPage;
|
||||||
|
AddressBookPage *addressBookPage;
|
||||||
|
AddressBookPage *receiveCoinsPage;
|
||||||
|
SendCoinsDialog *sendCoinsPage;
|
||||||
|
|
||||||
|
QLabel *labelEncryptionIcon;
|
||||||
|
QLabel *labelConnectionsIcon;
|
||||||
|
QLabel *labelBlocksIcon;
|
||||||
|
QLabel *progressBarLabel;
|
||||||
|
QProgressBar *progressBar;
|
||||||
|
|
||||||
|
QAction *overviewAction;
|
||||||
|
QAction *historyAction;
|
||||||
|
QAction *quitAction;
|
||||||
|
QAction *sendCoinsAction;
|
||||||
|
QAction *addressBookAction;
|
||||||
|
QAction *aboutAction;
|
||||||
|
QAction *receiveCoinsAction;
|
||||||
|
QAction *optionsAction;
|
||||||
|
QAction *openBitcoinAction;
|
||||||
|
QAction *exportAction;
|
||||||
|
QAction *encryptWalletAction;
|
||||||
|
QAction *changePassphraseAction;
|
||||||
|
|
||||||
|
QSystemTrayIcon *trayIcon;
|
||||||
|
Notificator *notificator;
|
||||||
|
TransactionView *transactionView;
|
||||||
|
|
||||||
|
QMovie *syncIconMovie;
|
||||||
|
|
||||||
|
void createActions();
|
||||||
|
QWidget *createTabs();
|
||||||
|
void createTrayIcon();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setNumConnections(int count);
|
||||||
|
void setNumBlocks(int count);
|
||||||
|
void setEncryptionStatus(int status);
|
||||||
|
|
||||||
|
void error(const QString &title, const QString &message);
|
||||||
|
/* It is currently not possible to pass a return value to another thread through
|
||||||
|
BlockingQueuedConnection, so use an indirected pointer.
|
||||||
|
http://bugreports.qt.nokia.com/browse/QTBUG-10440
|
||||||
|
*/
|
||||||
|
void askFee(qint64 nFeeRequired, bool *payFee);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// UI pages
|
||||||
|
void gotoOverviewPage();
|
||||||
|
void gotoHistoryPage();
|
||||||
|
void gotoAddressBookPage();
|
||||||
|
void gotoReceiveCoinsPage();
|
||||||
|
void gotoSendCoinsPage();
|
||||||
|
|
||||||
|
// Misc actions
|
||||||
|
void optionsClicked();
|
||||||
|
void aboutClicked();
|
||||||
|
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
|
void incomingTransaction(const QModelIndex & parent, int start, int end);
|
||||||
|
void encryptWallet(bool status);
|
||||||
|
void changePassphrase();
|
||||||
|
void unlockWallet();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
217
src/qt/bitcoinstrings.cpp
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#include <QtGlobal>
|
||||||
|
// Automatically generated by extract_strings.py
|
||||||
|
static const char *bitcoin_strings[] = {QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Usage:"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Send command to -server or bitcoind\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "List commands\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Options:\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Specify configuration file (default: bitcoin.conf)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Start minimized\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout (in milliseconds)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks4 proxy\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for addnode and connect\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Don't accept connections from outside\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Don't attempt to use UPnP to map the listening port\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to use UPnP to map the listening port\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Accept command line and JSON-RPC commands\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on <port> (default: 8332)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Send commands to node running on <ip> (default: 127.0.0.1)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"\n"
|
||||||
|
"SSL options: (see the Bitcoin Wiki for SSL setup instructions)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Use OpenSSL (https) for JSON-RPC connections\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
|
||||||
|
"@STRENGTH)\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "This help message\n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
|
||||||
|
"running."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading addr.dat \n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading blkindex.dat \n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted \n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Error loading wallet.dat: Wallet requires newer version of Bitcoin \n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat \n"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Warning: -paytxfee is set very high. This is the transaction fee you will "
|
||||||
|
"pay if you send a transaction."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error: CreateThread(StartNode) failed"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Unable to bind to port %d on this computer. Bitcoin is probably already "
|
||||||
|
"running."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"This transaction is over the size limit. You can still send it for a fee of "
|
||||||
|
"%s, which goes to the nodes that process your transaction and helps to "
|
||||||
|
"support the network. Do you want to pay the fee?"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Enter the current passphrase to the wallet."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Passphrase"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Please supply the current wallet decryption passphrase."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "The passphrase entered for the wallet decryption was incorrect."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Status"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Date"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Description"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Debit"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Credit"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Open for %d blocks"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Open until %s"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "%d/offline?"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "%d/unconfirmed"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "%d confirmations"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Generated"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Generated (%s matures in %d more blocks)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Generated - Warning: This block was not received by any other nodes and will "
|
||||||
|
"probably not be accepted!"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Generated (not accepted)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "From: "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Received with: "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Payment to yourself"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "To: "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", " Generating"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "(not connected)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", " %d connections %d blocks %d transactions"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet already encrypted."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Enter the new passphrase to the wallet.\n"
|
||||||
|
"Please use a passphrase of 10 or more random characters, or eight or more "
|
||||||
|
"words."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error: The supplied passphrase was too short."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"WARNING: If you encrypt your wallet and lose your passphrase, you will LOSE "
|
||||||
|
"ALL OF YOUR BITCOINS!\n"
|
||||||
|
"Are you sure you wish to encrypt your wallet?"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Please re-enter your new wallet passphrase."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error: the supplied passphrases didn't match."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet encryption failed."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Wallet Encrypted.\n"
|
||||||
|
"Remember that encrypting your wallet cannot fully protect your bitcoins from "
|
||||||
|
"being stolen by malware infecting your computer."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet is unencrypted, please encrypt it first."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Enter the new passphrase for the wallet."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Re-enter the new passphrase for the wallet."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet Passphrase Changed."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "New Receiving Address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"You should use a new address for each payment you receive.\n"
|
||||||
|
"\n"
|
||||||
|
"Label"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Status:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ", has not been successfully broadcast yet"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ", broadcast through %d node"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ", broadcast through %d nodes"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Date:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Source:</b> Generated<br>"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>From:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "unknown"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>To:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", " (yours, label: "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", " (yours)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Credit:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "(%s matures in %d more blocks)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "(not accepted)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Debit:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Transaction fee:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "<b>Net amount:</b> "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Message:"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Comment:"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Generated coins must wait 120 blocks before they can be spent. When you "
|
||||||
|
"generated this block, it was broadcast to the network to be added to the "
|
||||||
|
"block chain. If it fails to get into the chain, it will change to \"not "
|
||||||
|
"accepted\" and not be spendable. This may occasionally happen if another "
|
||||||
|
"node generates a block within a few seconds of yours."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write autostart/bitcoin.desktop file"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Main"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "&Start Bitcoin on window system startup"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "&Minimize on close"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "version %s"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error in amount "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Send Coins"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Amount exceeds your balance "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Total exceeds your balance when the "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", " transaction fee is included "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Payment sent "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid address "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Sending %s to %s"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "CANCELLED"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Cancelled"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Transfer cancelled "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Error: "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Connecting..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to connect"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Requesting public key..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Received public key..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Recipient is not accepting transactions sent by IP address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Transfer was not accepted"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid response received"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Creating transaction..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"This transaction requires a transaction fee of at least %s because of its "
|
||||||
|
"amount, complexity, or use of recently received funds"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction creation failed"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction aborted"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Lost connection, transaction cancelled"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Sending payment..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"The transaction was rejected. This might happen if some of the coins in "
|
||||||
|
"your wallet were already spent, such as if you used a copy of wallet.dat and "
|
||||||
|
"coins were spent in the copy but not marked as spent here."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Waiting for confirmation..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"The payment was sent, but the recipient was unable to verify it.\n"
|
||||||
|
"The transaction is recorded and will credit to the recipient,\n"
|
||||||
|
"but the comment information will be blank."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Payment was sent, but an invalid response was received"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Payment completed"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Name"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Label"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"This is one of your own addresses for receiving payments and cannot be "
|
||||||
|
"entered in the address book. "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Edit Address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Edit Address Label"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Add Address"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin - Generating"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin - (not connected)"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "&Open Bitcoin"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "&Send Bitcoins"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "O&ptions..."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "E&xit"),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "Program has crashed and will terminate. "),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", ""
|
||||||
|
"Warning: Please check that your computer's date and time are correct. If "
|
||||||
|
"your clock is wrong Bitcoin will not work properly."),
|
||||||
|
QT_TRANSLATE_NOOP("bitcoin-core", "beta"),
|
||||||
|
};
|
181
src/qt/bitcoinunits.cpp
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
BitcoinUnits::BitcoinUnits(QObject *parent):
|
||||||
|
QAbstractListModel(parent),
|
||||||
|
unitlist(availableUnits())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<BitcoinUnits::Unit> BitcoinUnits::availableUnits()
|
||||||
|
{
|
||||||
|
QList<BitcoinUnits::Unit> unitlist;
|
||||||
|
unitlist.append(BTC);
|
||||||
|
unitlist.append(mBTC);
|
||||||
|
unitlist.append(uBTC);
|
||||||
|
return unitlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitcoinUnits::valid(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC:
|
||||||
|
case mBTC:
|
||||||
|
case uBTC:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BitcoinUnits::name(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC: return QString("BTC");
|
||||||
|
case mBTC: return QString("mBTC");
|
||||||
|
case uBTC: return QString::fromUtf8("μBTC");
|
||||||
|
default: return QString("???");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BitcoinUnits::description(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC: return QString("Bitcoins");
|
||||||
|
case mBTC: return QString("Milli-Bitcoins (1 / 1,000)");
|
||||||
|
case uBTC: return QString("Micro-Bitcoins (1 / 1,000,000)");
|
||||||
|
default: return QString("???");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 BitcoinUnits::factor(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC: return 100000000;
|
||||||
|
case mBTC: return 100000;
|
||||||
|
case uBTC: return 100;
|
||||||
|
default: return 100000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BitcoinUnits::amountDigits(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC: return 8; // 21,000,000 (# digits, without commas)
|
||||||
|
case mBTC: return 11; // 21,000,000,000
|
||||||
|
case uBTC: return 14; // 21,000,000,000,000
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BitcoinUnits::decimals(int unit)
|
||||||
|
{
|
||||||
|
switch(unit)
|
||||||
|
{
|
||||||
|
case BTC: return 8;
|
||||||
|
case mBTC: return 5;
|
||||||
|
case uBTC: return 2;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BitcoinUnits::format(int unit, qint64 n, bool fPlus)
|
||||||
|
{
|
||||||
|
// Note: not using straight sprintf here because we do NOT want
|
||||||
|
// localized number formatting.
|
||||||
|
if(!valid(unit))
|
||||||
|
return QString(); // Refuse to format invalid unit
|
||||||
|
qint64 coin = factor(unit);
|
||||||
|
int num_decimals = decimals(unit);
|
||||||
|
qint64 n_abs = (n > 0 ? n : -n);
|
||||||
|
qint64 quotient = n_abs / coin;
|
||||||
|
qint64 remainder = n_abs % coin;
|
||||||
|
QString quotient_str = QString::number(quotient);
|
||||||
|
QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0');
|
||||||
|
|
||||||
|
// Right-trim excess 0's after the decimal point
|
||||||
|
int nTrim = 0;
|
||||||
|
for (int i = remainder_str.size()-1; i>=2 && (remainder_str.at(i) == '0'); --i)
|
||||||
|
++nTrim;
|
||||||
|
remainder_str.chop(nTrim);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
quotient_str.insert(0, '-');
|
||||||
|
else if (fPlus && n > 0)
|
||||||
|
quotient_str.insert(0, '+');
|
||||||
|
return quotient_str + QString(".") + remainder_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign)
|
||||||
|
{
|
||||||
|
return format(unit, amount, plussign) + QString(" ") + name(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
|
||||||
|
{
|
||||||
|
if(!valid(unit) || value.isEmpty())
|
||||||
|
return false; // Refuse to parse invalid unit or empty string
|
||||||
|
int num_decimals = decimals(unit);
|
||||||
|
QStringList parts = value.split(".");
|
||||||
|
|
||||||
|
if(parts.size() > 2)
|
||||||
|
{
|
||||||
|
return false; // More than one dot
|
||||||
|
}
|
||||||
|
QString whole = parts[0];
|
||||||
|
QString decimals;
|
||||||
|
|
||||||
|
if(parts.size() > 1)
|
||||||
|
{
|
||||||
|
decimals = parts[1];
|
||||||
|
}
|
||||||
|
if(decimals.size() > num_decimals)
|
||||||
|
{
|
||||||
|
return false; // Exceeds max precision
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
QString str = whole + decimals.leftJustified(num_decimals, '0');
|
||||||
|
|
||||||
|
if(str.size() > 18)
|
||||||
|
{
|
||||||
|
return false; // Longer numbers will exceed 63 bits
|
||||||
|
}
|
||||||
|
qint64 retvalue = str.toLongLong(&ok);
|
||||||
|
if(val_out)
|
||||||
|
{
|
||||||
|
*val_out = retvalue;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BitcoinUnits::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
return unitlist.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant BitcoinUnits::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
int row = index.row();
|
||||||
|
if(row >= 0 && row < unitlist.size())
|
||||||
|
{
|
||||||
|
Unit unit = unitlist.at(row);
|
||||||
|
switch(role)
|
||||||
|
{
|
||||||
|
case Qt::EditRole:
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return QVariant(name(unit));
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return QVariant(description(unit));
|
||||||
|
case UnitRole:
|
||||||
|
return QVariant(static_cast<int>(unit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
57
src/qt/bitcoinunits.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef BITCOINUNITS_H
|
||||||
|
#define BITCOINUNITS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
// Bitcoin unit definitions, encapsulates parsing and formatting
|
||||||
|
// and serves as list model for dropdown selection boxes.
|
||||||
|
class BitcoinUnits: public QAbstractListModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BitcoinUnits(QObject *parent);
|
||||||
|
|
||||||
|
enum Unit
|
||||||
|
{
|
||||||
|
// Source: https://en.bitcoin.it/wiki/Units
|
||||||
|
// Please add only sensible ones
|
||||||
|
BTC,
|
||||||
|
mBTC,
|
||||||
|
uBTC
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Static API
|
||||||
|
// Get list of units, for dropdown box
|
||||||
|
static QList<Unit> availableUnits();
|
||||||
|
// Is unit ID valid?
|
||||||
|
static bool valid(int unit);
|
||||||
|
// Short name
|
||||||
|
static QString name(int unit);
|
||||||
|
// Longer description
|
||||||
|
static QString description(int unit);
|
||||||
|
// Number of satoshis / unit
|
||||||
|
static qint64 factor(int unit);
|
||||||
|
// Number of amount digits (to represent max number of coins)
|
||||||
|
static int amountDigits(int unit);
|
||||||
|
// Number of decimals left
|
||||||
|
static int decimals(int unit);
|
||||||
|
// Format as string
|
||||||
|
static QString format(int unit, qint64 amount, bool plussign=false);
|
||||||
|
// Format as string (with unit)
|
||||||
|
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
|
||||||
|
// Parse string to coin amount
|
||||||
|
static bool parse(int unit, const QString &value, qint64 *val_out);
|
||||||
|
|
||||||
|
/// AbstractListModel implementation
|
||||||
|
enum {
|
||||||
|
// Unit identifier
|
||||||
|
UnitRole = Qt::UserRole
|
||||||
|
} RoleIndex;
|
||||||
|
int rowCount(const QModelIndex &parent) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
private:
|
||||||
|
QList<BitcoinUnits::Unit> unitlist;
|
||||||
|
};
|
||||||
|
typedef BitcoinUnits::Unit BitcoinUnit;
|
||||||
|
|
||||||
|
#endif // BITCOINUNITS_H
|
83
src/qt/clientmodel.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include "clientmodel.h"
|
||||||
|
#include "guiconstants.h"
|
||||||
|
#include "optionsmodel.h"
|
||||||
|
#include "addresstablemodel.h"
|
||||||
|
#include "transactiontablemodel.h"
|
||||||
|
|
||||||
|
#include "headers.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
|
||||||
|
QObject(parent), optionsModel(optionsModel),
|
||||||
|
cachedNumConnections(0), cachedNumBlocks(0)
|
||||||
|
{
|
||||||
|
// Until signal notifications is built into the bitcoin core,
|
||||||
|
// simply update everything after polling using a timer.
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||||
|
timer->start(MODEL_UPDATE_DELAY);
|
||||||
|
|
||||||
|
numBlocksAtStartup = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClientModel::getNumConnections() const
|
||||||
|
{
|
||||||
|
return vNodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClientModel::getNumBlocks() const
|
||||||
|
{
|
||||||
|
return nBestHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClientModel::getNumBlocksAtStartup()
|
||||||
|
{
|
||||||
|
if (numBlocksAtStartup == -1) numBlocksAtStartup = getNumBlocks();
|
||||||
|
return numBlocksAtStartup;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime ClientModel::getLastBlockDate() const
|
||||||
|
{
|
||||||
|
return QDateTime::fromTime_t(pindexBest->GetBlockTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientModel::update()
|
||||||
|
{
|
||||||
|
int newNumConnections = getNumConnections();
|
||||||
|
int newNumBlocks = getNumBlocks();
|
||||||
|
|
||||||
|
if(cachedNumConnections != newNumConnections)
|
||||||
|
emit numConnectionsChanged(newNumConnections);
|
||||||
|
if(cachedNumBlocks != newNumBlocks)
|
||||||
|
emit numBlocksChanged(newNumBlocks);
|
||||||
|
|
||||||
|
cachedNumConnections = newNumConnections;
|
||||||
|
cachedNumBlocks = newNumBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientModel::isTestNet() const
|
||||||
|
{
|
||||||
|
return fTestNet;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientModel::inInitialBlockDownload() const
|
||||||
|
{
|
||||||
|
return IsInitialBlockDownload();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClientModel::getNumBlocksOfPeers() const
|
||||||
|
{
|
||||||
|
return GetNumBlocksOfPeers();
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionsModel *ClientModel::getOptionsModel()
|
||||||
|
{
|
||||||
|
return optionsModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClientModel::formatFullVersion() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(FormatFullVersion());
|
||||||
|
}
|
60
src/qt/clientmodel.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef CLIENTMODEL_H
|
||||||
|
#define CLIENTMODEL_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class OptionsModel;
|
||||||
|
class AddressTableModel;
|
||||||
|
class TransactionTableModel;
|
||||||
|
class CWallet;
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QDateTime;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
// Model for Bitcoin network client
|
||||||
|
class ClientModel : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ClientModel(OptionsModel *optionsModel, QObject *parent = 0);
|
||||||
|
|
||||||
|
OptionsModel *getOptionsModel();
|
||||||
|
|
||||||
|
int getNumConnections() const;
|
||||||
|
int getNumBlocks() const;
|
||||||
|
int getNumBlocksAtStartup();
|
||||||
|
|
||||||
|
QDateTime getLastBlockDate() const;
|
||||||
|
|
||||||
|
// Return true if client connected to testnet
|
||||||
|
bool isTestNet() const;
|
||||||
|
// Return true if core is doing initial block download
|
||||||
|
bool inInitialBlockDownload() const;
|
||||||
|
// Return conservative estimate of total number of blocks, or 0 if unknown
|
||||||
|
int getNumBlocksOfPeers() const;
|
||||||
|
|
||||||
|
QString formatFullVersion() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OptionsModel *optionsModel;
|
||||||
|
|
||||||
|
int cachedNumConnections;
|
||||||
|
int cachedNumBlocks;
|
||||||
|
|
||||||
|
int numBlocksAtStartup;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void numConnectionsChanged(int count);
|
||||||
|
void numBlocksChanged(int count);
|
||||||
|
|
||||||
|
// Asynchronous error notification
|
||||||
|
void error(const QString &title, const QString &message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CLIENTMODEL_H
|
83
src/qt/csvmodelwriter.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include "csvmodelwriter.h"
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
filename(filename)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVModelWriter::setModel(const QAbstractItemModel *model)
|
||||||
|
{
|
||||||
|
this->model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVModelWriter::addColumn(const QString &title, int column, int role)
|
||||||
|
{
|
||||||
|
Column col;
|
||||||
|
col.title = title;
|
||||||
|
col.column = column;
|
||||||
|
col.role = role;
|
||||||
|
|
||||||
|
columns.append(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeValue(QTextStream &f, const QString &value)
|
||||||
|
{
|
||||||
|
// TODO: quoting if " or \n in string
|
||||||
|
f << "\"" << value << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSep(QTextStream &f)
|
||||||
|
{
|
||||||
|
f << ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeNewline(QTextStream &f)
|
||||||
|
{
|
||||||
|
f << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CSVModelWriter::write()
|
||||||
|
{
|
||||||
|
QFile file(filename);
|
||||||
|
if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
return false;
|
||||||
|
QTextStream out(&file);
|
||||||
|
|
||||||
|
int numRows = model->rowCount();
|
||||||
|
|
||||||
|
// Header row
|
||||||
|
for(int i=0; i<columns.size(); ++i)
|
||||||
|
{
|
||||||
|
if(i!=0)
|
||||||
|
{
|
||||||
|
writeSep(out);
|
||||||
|
}
|
||||||
|
writeValue(out, columns[i].title);
|
||||||
|
}
|
||||||
|
writeNewline(out);
|
||||||
|
|
||||||
|
// Data rows
|
||||||
|
for(int j=0; j<numRows; ++j)
|
||||||
|
{
|
||||||
|
for(int i=0; i<columns.size(); ++i)
|
||||||
|
{
|
||||||
|
if(i!=0)
|
||||||
|
{
|
||||||
|
writeSep(out);
|
||||||
|
}
|
||||||
|
QVariant data = model->index(j, columns[i].column).data(columns[i].role);
|
||||||
|
writeValue(out, data.toString());
|
||||||
|
}
|
||||||
|
writeNewline(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return file.error() == QFile::NoError;
|
||||||
|
}
|
||||||
|
|
43
src/qt/csvmodelwriter.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef CSVMODELWRITER_H
|
||||||
|
#define CSVMODELWRITER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QAbstractItemModel;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
// Export TableModel to CSV file
|
||||||
|
class CSVModelWriter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CSVModelWriter(const QString &filename, QObject *parent = 0);
|
||||||
|
|
||||||
|
void setModel(const QAbstractItemModel *model);
|
||||||
|
void addColumn(const QString &title, int column, int role=Qt::EditRole);
|
||||||
|
|
||||||
|
// Perform write operation
|
||||||
|
// Returns true on success, false otherwise
|
||||||
|
bool write();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString filename;
|
||||||
|
const QAbstractItemModel *model;
|
||||||
|
|
||||||
|
struct Column
|
||||||
|
{
|
||||||
|
QString title;
|
||||||
|
int column;
|
||||||
|
int role;
|
||||||
|
};
|
||||||
|
QList<Column> columns;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CSVMODELWRITER_H
|
115
src/qt/editaddressdialog.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include "editaddressdialog.h"
|
||||||
|
#include "ui_editaddressdialog.h"
|
||||||
|
#include "addresstablemodel.h"
|
||||||
|
#include "guiutil.h"
|
||||||
|
|
||||||
|
#include <QDataWidgetMapper>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::EditAddressDialog), mapper(0), mode(mode), model(0)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
GUIUtil::setupAddressWidget(ui->addressEdit, this);
|
||||||
|
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case NewReceivingAddress:
|
||||||
|
setWindowTitle(tr("New receiving address"));
|
||||||
|
ui->addressEdit->setEnabled(false);
|
||||||
|
break;
|
||||||
|
case NewSendingAddress:
|
||||||
|
setWindowTitle(tr("New sending address"));
|
||||||
|
break;
|
||||||
|
case EditReceivingAddress:
|
||||||
|
setWindowTitle(tr("Edit receiving address"));
|
||||||
|
ui->addressEdit->setDisabled(true);
|
||||||
|
break;
|
||||||
|
case EditSendingAddress:
|
||||||
|
setWindowTitle(tr("Edit sending address"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper = new QDataWidgetMapper(this);
|
||||||
|
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditAddressDialog::~EditAddressDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditAddressDialog::setModel(AddressTableModel *model)
|
||||||
|
{
|
||||||
|
this->model = model;
|
||||||
|
mapper->setModel(model);
|
||||||
|
mapper->addMapping(ui->labelEdit, AddressTableModel::Label);
|
||||||
|
mapper->addMapping(ui->addressEdit, AddressTableModel::Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditAddressDialog::loadRow(int row)
|
||||||
|
{
|
||||||
|
mapper->setCurrentIndex(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditAddressDialog::saveCurrentRow()
|
||||||
|
{
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
case NewReceivingAddress:
|
||||||
|
case NewSendingAddress:
|
||||||
|
address = model->addRow(
|
||||||
|
mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive,
|
||||||
|
ui->labelEdit->text(),
|
||||||
|
ui->addressEdit->text());
|
||||||
|
break;
|
||||||
|
case EditReceivingAddress:
|
||||||
|
case EditSendingAddress:
|
||||||
|
if(mapper->submit())
|
||||||
|
{
|
||||||
|
address = ui->addressEdit->text();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return !address.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditAddressDialog::accept()
|
||||||
|
{
|
||||||
|
if(!saveCurrentRow())
|
||||||
|
{
|
||||||
|
switch(model->getEditStatus())
|
||||||
|
{
|
||||||
|
case AddressTableModel::DUPLICATE_ADDRESS:
|
||||||
|
QMessageBox::warning(this, windowTitle(),
|
||||||
|
tr("The entered address \"%1\" is already in the address book.").arg(ui->addressEdit->text()),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
break;
|
||||||
|
case AddressTableModel::INVALID_ADDRESS:
|
||||||
|
QMessageBox::warning(this, windowTitle(),
|
||||||
|
tr("The entered address \"%1\" is not a valid bitcoin address.").arg(ui->addressEdit->text()),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
case AddressTableModel::WALLET_UNLOCK_FAILURE:
|
||||||
|
QMessageBox::critical(this, windowTitle(),
|
||||||
|
tr("Could not unlock wallet."),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
case AddressTableModel::KEY_GENERATION_FAILURE:
|
||||||
|
QMessageBox::critical(this, windowTitle(),
|
||||||
|
tr("New key generation failed."),
|
||||||
|
QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EditAddressDialog::getAddress() const
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
47
src/qt/editaddressdialog.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef EDITADDRESSDIALOG_H
|
||||||
|
#define EDITADDRESSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QDataWidgetMapper;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class EditAddressDialog;
|
||||||
|
}
|
||||||
|
class AddressTableModel;
|
||||||
|
|
||||||
|
class EditAddressDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Mode {
|
||||||
|
NewReceivingAddress,
|
||||||
|
NewSendingAddress,
|
||||||
|
EditReceivingAddress,
|
||||||
|
EditSendingAddress
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit EditAddressDialog(Mode mode, QWidget *parent = 0);
|
||||||
|
~EditAddressDialog();
|
||||||
|
|
||||||
|
void setModel(AddressTableModel *model);
|
||||||
|
void loadRow(int row);
|
||||||
|
|
||||||
|
void accept();
|
||||||
|
|
||||||
|
QString getAddress() const;
|
||||||
|
private:
|
||||||
|
bool saveCurrentRow();
|
||||||
|
|
||||||
|
Ui::EditAddressDialog *ui;
|
||||||
|
QDataWidgetMapper *mapper;
|
||||||
|
Mode mode;
|
||||||
|
AddressTableModel *model;
|
||||||
|
|
||||||
|
QString address;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EDITADDRESSDIALOG_H
|
162
src/qt/forms/aboutdialog.ui
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AboutDialog</class>
|
||||||
|
<widget class="QDialog" name="AboutDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>593</width>
|
||||||
|
<height>319</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>About Bitcoin</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Ignored">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../bitcoin.qrc">:/images/about</pixmap>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string><b>Bitcoin</b> version</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="versionLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">0.3.666-beta</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copyright © 2009-2011 Bitcoin Developers
|
||||||
|
|
||||||
|
This is experimental software.
|
||||||
|
|
||||||
|
Distributed under the MIT/X11 software license, see the accompanying file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../bitcoin.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>AboutDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>360</x>
|
||||||
|
<y>308</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>AboutDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>428</x>
|
||||||
|
<y>308</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
130
src/qt/forms/addressbookpage.ui
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AddressBookPage</class>
|
||||||
|
<widget class="QWidget" name="AddressBookPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>627</width>
|
||||||
|
<height>347</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Address Book</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelExplanation">
|
||||||
|
<property name="text">
|
||||||
|
<string>These are your Bitcoin addresses for receiving payments. You may want to give a different one to each sender so you can keep track of who is paying you.</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::AutoText</enum>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tableView">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Double-click to edit address or label</string>
|
||||||
|
</property>
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="verticalHeaderVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="newAddressButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Create a new address</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&New Address...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="copyToClipboard">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Copy the currently selected address to the system clipboard</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Copy to Clipboard</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/editcopy</normaloff>:/icons/editcopy</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>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../bitcoin.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
148
src/qt/forms/askpassphrasedialog.ui
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AskPassphraseDialog</class>
|
||||||
|
<widget class="QDialog" name="AskPassphraseDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>589</width>
|
||||||
|
<height>228</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>550</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="warningLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel1">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enter passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit1">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel2">
|
||||||
|
<property name="text">
|
||||||
|
<string>New passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit2">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="passLabel3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Repeat new passphrase</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="passEdit3">
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>AskPassphraseDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>AskPassphraseDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
105
src/qt/forms/editaddressdialog.ui
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>EditAddressDialog</class>
|
||||||
|
<widget class="QDialog" name="EditAddressDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>457</width>
|
||||||
|
<height>126</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Edit Address</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Label</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>labelEdit</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="labelEdit">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The label associated with this address book entry</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Address</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>addressEdit</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="addressEdit">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The address associated with this address book entry. This can only be modified for sending addresses.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>EditAddressDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>EditAddressDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
161
src/qt/forms/overviewpage.ui
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>OverviewPage</class>
|
||||||
|
<widget class="QWidget" name="OverviewPage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>552</width>
|
||||||
|
<height>342</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Balance:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="labelBalance">
|
||||||
|
<property name="text">
|
||||||
|
<string>123.456 BTC</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number of transactions:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLabel" name="labelNumTransactions">
|
||||||
|
<property name="text">
|
||||||
|
<string>0</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Unconfirmed:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="labelUnconfirmed">
|
||||||
|
<property name="text">
|
||||||
|
<string>0 BTC</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Wallet</span></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string><b>Recent transactions</b></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="listTransactions">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
122
src/qt/forms/sendcoinsdialog.ui
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SendCoinsDialog</class>
|
||||||
|
<widget class="QDialog" name="SendCoinsDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>686</width>
|
||||||
|
<height>217</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Send Coins</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>666</width>
|
||||||
|
<height>162</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="entries">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Send to multiple recipients at once</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Add recipient...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/add</normaloff>:/icons/add</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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="sendButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Confirm the send action</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Send</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/send</normaloff>:/icons/send</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="default">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../bitcoin.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
178
src/qt/forms/sendcoinsentry.ui
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SendCoinsEntry</class>
|
||||||
|
<widget class="QFrame" name="SendCoinsEntry">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>729</width>
|
||||||
|
<height>136</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Sunken</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>A&mount:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>payAmount</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pay &To:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>payTo</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="BitcoinAmountField" name="payAmount"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QValidatedLineEdit" name="addAsLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Enter a label for this address to add it to your address book</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Label:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>addAsLabel</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QValidatedLineEdit" name="payTo">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
|
||||||
|
</property>
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>34</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addressBookButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Choose adress from address book</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/address-book</normaloff>:/icons/address-book</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Alt+A</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pasteButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Paste address from clipboard</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/editpaste</normaloff>:/icons/editpaste</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Alt+P</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="deleteButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Remove this recipient</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../bitcoin.qrc">
|
||||||
|
<normaloff>:/icons/remove</normaloff>:/icons/remove</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>BitcoinAmountField</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>bitcoinamountfield.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>QValidatedLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>qvalidatedlineedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="../bitcoin.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
71
src/qt/forms/transactiondescdialog.ui
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>TransactionDescDialog</class>
|
||||||
|
<widget class="QDialog" name="TransactionDescDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Transaction details</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="detailText">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>This pane shows a detailed description of the transaction</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>TransactionDescDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>TransactionDescDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
23
src/qt/guiconstants.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef GUICONSTANTS_H
|
||||||
|
#define GUICONSTANTS_H
|
||||||
|
|
||||||
|
/* Milliseconds between model updates */
|
||||||
|
static const int MODEL_UPDATE_DELAY = 500;
|
||||||
|
|
||||||
|
/* Maximum passphrase length */
|
||||||
|
static const int MAX_PASSPHRASE_SIZE = 1024;
|
||||||
|
|
||||||
|
/* Size of icons in status bar */
|
||||||
|
static const int STATUSBAR_ICONSIZE = 16;
|
||||||
|
|
||||||
|
/* Invalid field background style */
|
||||||
|
#define STYLE_INVALID "background:#FF8080"
|
||||||
|
|
||||||
|
/* Transaction list -- unconfirmed transaction */
|
||||||
|
#define COLOR_UNCONFIRMED QColor(128, 128, 128)
|
||||||
|
/* Transaction list -- negative amount */
|
||||||
|
#define COLOR_NEGATIVE QColor(255, 0, 0)
|
||||||
|
/* Transaction list -- bare address (without label) */
|
||||||
|
#define COLOR_BAREADDRESS QColor(140, 140, 140)
|
||||||
|
|
||||||
|
#endif // GUICONSTANTS_H
|
74
src/qt/guiutil.cpp
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include "guiutil.h"
|
||||||
|
#include "bitcoinaddressvalidator.h"
|
||||||
|
#include "walletmodel.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
|
||||||
|
#include "headers.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
QString GUIUtil::dateTimeStr(qint64 nTime)
|
||||||
|
{
|
||||||
|
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GUIUtil::dateTimeStr(const QDateTime &date)
|
||||||
|
{
|
||||||
|
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont GUIUtil::bitcoinAddressFont()
|
||||||
|
{
|
||||||
|
QFont font("Monospace");
|
||||||
|
font.setStyleHint(QFont::TypeWriter);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent)
|
||||||
|
{
|
||||||
|
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
|
||||||
|
widget->setValidator(new BitcoinAddressValidator(parent));
|
||||||
|
widget->setFont(bitcoinAddressFont());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
|
||||||
|
{
|
||||||
|
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
|
||||||
|
amountValidator->setDecimals(8);
|
||||||
|
amountValidator->setBottom(0.0);
|
||||||
|
widget->setValidator(amountValidator);
|
||||||
|
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUIUtil::parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out)
|
||||||
|
{
|
||||||
|
if(url->scheme() != QString("bitcoin"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SendCoinsRecipient rv;
|
||||||
|
rv.address = url->path();
|
||||||
|
rv.label = url->queryItemValue("label");
|
||||||
|
|
||||||
|
QString amount = url->queryItemValue("amount");
|
||||||
|
if(amount.isEmpty())
|
||||||
|
{
|
||||||
|
rv.amount = 0;
|
||||||
|
}
|
||||||
|
else // Amount is non-empty
|
||||||
|
{
|
||||||
|
if(!BitcoinUnits::parse(BitcoinUnits::BTC, amount, &rv.amount))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(out)
|
||||||
|
{
|
||||||
|
*out = rv;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
34
src/qt/guiutil.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef GUIUTIL_H
|
||||||
|
#define GUIUTIL_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QFont;
|
||||||
|
class QLineEdit;
|
||||||
|
class QWidget;
|
||||||
|
class QDateTime;
|
||||||
|
class QUrl;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
class SendCoinsRecipient;
|
||||||
|
|
||||||
|
class GUIUtil
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Create human-readable string from date
|
||||||
|
static QString dateTimeStr(qint64 nTime);
|
||||||
|
static QString dateTimeStr(const QDateTime &datetime);
|
||||||
|
|
||||||
|
// Render bitcoin addresses in monospace font
|
||||||
|
static QFont bitcoinAddressFont();
|
||||||
|
|
||||||
|
// Set up widgets for address and amounts
|
||||||
|
static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
|
||||||
|
static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
|
||||||
|
|
||||||
|
// Parse "bitcoin:" URL into recipient object, return true on succesful parsing
|
||||||
|
// See Bitcoin URL definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
|
||||||
|
static bool parseBitcoinURL(const QUrl *url, SendCoinsRecipient *out);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GUIUTIL_H
|
1155
src/qt/locale/bitcoin_de.ts
Normal file
1441
src/qt/locale/bitcoin_nl.ts
Normal file
2173
src/qt/locale/bitcoin_ru.ts
Normal file
36
src/qt/monitoreddatamapper.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "monitoreddatamapper.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QMetaObject>
|
||||||
|
#include <QMetaProperty>
|
||||||
|
|
||||||
|
MonitoredDataMapper::MonitoredDataMapper(QObject *parent) :
|
||||||
|
QDataWidgetMapper(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MonitoredDataMapper::addMapping(QWidget *widget, int section)
|
||||||
|
{
|
||||||
|
QDataWidgetMapper::addMapping(widget, section);
|
||||||
|
addChangeMonitor(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MonitoredDataMapper::addMapping(QWidget *widget, int section, const QByteArray &propertyName)
|
||||||
|
{
|
||||||
|
QDataWidgetMapper::addMapping(widget, section, propertyName);
|
||||||
|
addChangeMonitor(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MonitoredDataMapper::addChangeMonitor(QWidget *widget)
|
||||||
|
{
|
||||||
|
// Watch user property of widget for changes, and connect
|
||||||
|
// the signal to our viewModified signal.
|
||||||
|
QMetaProperty prop = widget->metaObject()->userProperty();
|
||||||
|
int signal = prop.notifySignalIndex();
|
||||||
|
int method = this->metaObject()->indexOfMethod("viewModified()");
|
||||||
|
if(signal != -1 && method != -1)
|
||||||
|
{
|
||||||
|
QMetaObject::connect(widget, signal, this, method);
|
||||||
|
}
|
||||||
|
}
|
32
src/qt/monitoreddatamapper.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef MONITOREDDATAMAPPER_H
|
||||||
|
#define MONITOREDDATAMAPPER_H
|
||||||
|
|
||||||
|
#include <QDataWidgetMapper>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QWidget;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
/* Data <-> Widget mapper that watches for changes,
|
||||||
|
to be able to notify when 'dirty' (for example, to
|
||||||
|
enable a commit/apply button).
|
||||||
|
*/
|
||||||
|
class MonitoredDataMapper : public QDataWidgetMapper
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MonitoredDataMapper(QObject *parent=0);
|
||||||
|
|
||||||
|
void addMapping(QWidget *widget, int section);
|
||||||
|
void addMapping(QWidget *widget, int section, const QByteArray &propertyName);
|
||||||
|
private:
|
||||||
|
void addChangeMonitor(QWidget *widget);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void viewModified();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MONITOREDDATAMAPPER_H
|
224
src/qt/notificator.cpp
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
#include "notificator.h"
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QSystemTrayIcon>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
#include <QtDBus/QtDBus>
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// https://wiki.ubuntu.com/NotificationDevelopmentGuidelines recommends at least 128
|
||||||
|
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
|
||||||
|
|
||||||
|
Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent):
|
||||||
|
QObject(parent),
|
||||||
|
parent(parent),
|
||||||
|
programName(programName),
|
||||||
|
mode(None),
|
||||||
|
trayIcon(trayicon)
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
,interface(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(trayicon && trayicon->supportsMessages())
|
||||||
|
{
|
||||||
|
mode = QSystemTray;
|
||||||
|
}
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
interface = new QDBusInterface("org.freedesktop.Notifications",
|
||||||
|
"/org/freedesktop/Notifications", "org.freedesktop.Notifications");
|
||||||
|
if(interface->isValid())
|
||||||
|
{
|
||||||
|
mode = Freedesktop;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Notificator::~Notificator()
|
||||||
|
{
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
delete interface;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
|
||||||
|
// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
|
||||||
|
class FreedesktopImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FreedesktopImage() {}
|
||||||
|
FreedesktopImage(const QImage &img);
|
||||||
|
|
||||||
|
static int metaType();
|
||||||
|
|
||||||
|
// Image to variant that can be marshaled over DBus
|
||||||
|
static QVariant toVariant(const QImage &img);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int width, height, stride;
|
||||||
|
bool hasAlpha;
|
||||||
|
int channels;
|
||||||
|
int bitsPerSample;
|
||||||
|
QByteArray image;
|
||||||
|
|
||||||
|
friend QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i);
|
||||||
|
friend const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i);
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(FreedesktopImage);
|
||||||
|
|
||||||
|
// Image configuration settings
|
||||||
|
const int CHANNELS = 4;
|
||||||
|
const int BYTES_PER_PIXEL = 4;
|
||||||
|
const int BITS_PER_SAMPLE = 8;
|
||||||
|
|
||||||
|
FreedesktopImage::FreedesktopImage(const QImage &img):
|
||||||
|
width(img.width()),
|
||||||
|
height(img.height()),
|
||||||
|
stride(img.width() * BYTES_PER_PIXEL),
|
||||||
|
hasAlpha(true),
|
||||||
|
channels(CHANNELS),
|
||||||
|
bitsPerSample(BITS_PER_SAMPLE)
|
||||||
|
{
|
||||||
|
// Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
|
||||||
|
QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
|
||||||
|
const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.constBits());
|
||||||
|
|
||||||
|
unsigned int num_pixels = width * height;
|
||||||
|
image.resize(num_pixels * BYTES_PER_PIXEL);
|
||||||
|
|
||||||
|
for(unsigned int ptr = 0; ptr < num_pixels; ++ptr)
|
||||||
|
{
|
||||||
|
image[ptr*BYTES_PER_PIXEL+0] = data[ptr] >> 16; // R
|
||||||
|
image[ptr*BYTES_PER_PIXEL+1] = data[ptr] >> 8; // G
|
||||||
|
image[ptr*BYTES_PER_PIXEL+2] = data[ptr]; // B
|
||||||
|
image[ptr*BYTES_PER_PIXEL+3] = data[ptr] >> 24; // A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDBusArgument &operator<<(QDBusArgument &a, const FreedesktopImage &i)
|
||||||
|
{
|
||||||
|
a.beginStructure();
|
||||||
|
a << i.width << i.height << i.stride << i.hasAlpha << i.bitsPerSample << i.channels << i.image;
|
||||||
|
a.endStructure();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDBusArgument &operator>>(const QDBusArgument &a, FreedesktopImage &i)
|
||||||
|
{
|
||||||
|
a.beginStructure();
|
||||||
|
a >> i.width >> i.height >> i.stride >> i.hasAlpha >> i.bitsPerSample >> i.channels >> i.image;
|
||||||
|
a.endStructure();
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FreedesktopImage::metaType()
|
||||||
|
{
|
||||||
|
return qDBusRegisterMetaType<FreedesktopImage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant FreedesktopImage::toVariant(const QImage &img)
|
||||||
|
{
|
||||||
|
FreedesktopImage fimg(img);
|
||||||
|
return QVariant(FreedesktopImage::metaType(), &fimg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notificator::notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cls);
|
||||||
|
// Arguments for DBus call:
|
||||||
|
QList<QVariant> args;
|
||||||
|
|
||||||
|
// Program Name:
|
||||||
|
args.append(programName);
|
||||||
|
|
||||||
|
// Unique ID of this notification type:
|
||||||
|
args.append(0U);
|
||||||
|
|
||||||
|
// Application Icon, empty string
|
||||||
|
args.append(QString());
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
args.append(title);
|
||||||
|
|
||||||
|
// Body
|
||||||
|
args.append(text);
|
||||||
|
|
||||||
|
// Actions (none, actions are deprecated)
|
||||||
|
QStringList actions;
|
||||||
|
args.append(actions);
|
||||||
|
|
||||||
|
// Hints
|
||||||
|
QVariantMap hints;
|
||||||
|
|
||||||
|
// If no icon specified, set icon based on class
|
||||||
|
QIcon tmpicon;
|
||||||
|
if(icon.isNull())
|
||||||
|
{
|
||||||
|
QStyle::StandardPixmap sicon = QStyle::SP_MessageBoxQuestion;
|
||||||
|
switch(cls)
|
||||||
|
{
|
||||||
|
case Information: sicon = QStyle::SP_MessageBoxInformation; break;
|
||||||
|
case Warning: sicon = QStyle::SP_MessageBoxWarning; break;
|
||||||
|
case Critical: sicon = QStyle::SP_MessageBoxCritical; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
tmpicon = QApplication::style()->standardIcon(sicon);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpicon = icon;
|
||||||
|
}
|
||||||
|
hints["icon_data"] = FreedesktopImage::toVariant(tmpicon.pixmap(FREEDESKTOP_NOTIFICATION_ICON_SIZE).toImage());
|
||||||
|
args.append(hints);
|
||||||
|
|
||||||
|
// Timeout (in msec)
|
||||||
|
args.append(millisTimeout);
|
||||||
|
|
||||||
|
// "Fire and forget"
|
||||||
|
interface->callWithArgumentList(QDBus::NoBlock, "Notify", args);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Notificator::notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
|
||||||
|
{
|
||||||
|
Q_UNUSED(icon);
|
||||||
|
QSystemTrayIcon::MessageIcon sicon = QSystemTrayIcon::NoIcon;
|
||||||
|
switch(cls) // Set icon based on class
|
||||||
|
{
|
||||||
|
case Information: sicon = QSystemTrayIcon::Information; break;
|
||||||
|
case Warning: sicon = QSystemTrayIcon::Warning; break;
|
||||||
|
case Critical: sicon = QSystemTrayIcon::Critical; break;
|
||||||
|
}
|
||||||
|
trayIcon->showMessage(title, text, sicon, millisTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notificator::notify(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout)
|
||||||
|
{
|
||||||
|
switch(mode)
|
||||||
|
{
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
case Freedesktop:
|
||||||
|
notifyDBus(cls, title, text, icon, millisTimeout);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case QSystemTray:
|
||||||
|
notifySystray(cls, title, text, icon, millisTimeout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if(cls == Critical)
|
||||||
|
{
|
||||||
|
// Fall back to old fashioned popup dialog if critical and no other notification available
|
||||||
|
QMessageBox::critical(parent, title, text, QMessageBox::Ok, QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
63
src/qt/notificator.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef NOTIFICATOR_H
|
||||||
|
#define NOTIFICATOR_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QSystemTrayIcon;
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
class QDBusInterface;
|
||||||
|
#endif
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
// Cross-platform desktop notification client
|
||||||
|
class Notificator: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
// Create a new notificator
|
||||||
|
// Ownership of trayIcon is not transferred to this object
|
||||||
|
Notificator(const QString &programName=QString(), QSystemTrayIcon *trayIcon=0, QWidget *parent=0);
|
||||||
|
~Notificator();
|
||||||
|
|
||||||
|
// Message class
|
||||||
|
enum Class
|
||||||
|
{
|
||||||
|
Information,
|
||||||
|
Warning,
|
||||||
|
Critical,
|
||||||
|
};
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
/* Show notification message.
|
||||||
|
*
|
||||||
|
* cls: general message class
|
||||||
|
* title: title shown with message
|
||||||
|
* text: message content
|
||||||
|
* icon: optional icon to show with message
|
||||||
|
* millisTimeout: notification timeout in milliseconds (default 10 seconds)
|
||||||
|
*/
|
||||||
|
void notify(Class cls, const QString &title, const QString &text,
|
||||||
|
const QIcon &icon = QIcon(), int millisTimeout = 10000);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *parent;
|
||||||
|
enum Mode {
|
||||||
|
None,
|
||||||
|
Freedesktop, // Use DBus org.freedesktop.Notifications
|
||||||
|
QSystemTray, // Use QSystemTray::showMessage
|
||||||
|
};
|
||||||
|
QString programName;
|
||||||
|
Mode mode;
|
||||||
|
QSystemTrayIcon *trayIcon;
|
||||||
|
#ifdef QT_DBUS
|
||||||
|
QDBusInterface *interface;
|
||||||
|
|
||||||
|
void notifyDBus(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
|
||||||
|
#endif
|
||||||
|
void notifySystray(Class cls, const QString &title, const QString &text, const QIcon &icon, int millisTimeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NOTIFICATOR_H
|
277
src/qt/optionsdialog.cpp
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
#include "optionsdialog.h"
|
||||||
|
#include "optionsmodel.h"
|
||||||
|
#include "bitcoinamountfield.h"
|
||||||
|
#include "monitoreddatamapper.h"
|
||||||
|
#include "guiutil.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
#include "qvaluecombobox.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QStackedWidget>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QDoubleValidator>
|
||||||
|
#include <QRegExpValidator>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
|
||||||
|
/* First page of options */
|
||||||
|
class MainOptionsPage : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MainOptionsPage(QWidget *parent=0);
|
||||||
|
|
||||||
|
void setMapper(MonitoredDataMapper *mapper);
|
||||||
|
private:
|
||||||
|
QCheckBox *bitcoin_at_startup;
|
||||||
|
QCheckBox *minimize_to_tray;
|
||||||
|
QCheckBox *map_port_upnp;
|
||||||
|
QCheckBox *minimize_on_close;
|
||||||
|
QCheckBox *connect_socks4;
|
||||||
|
QLineEdit *proxy_ip;
|
||||||
|
QLineEdit *proxy_port;
|
||||||
|
BitcoinAmountField *fee_edit;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class DisplayOptionsPage : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DisplayOptionsPage(QWidget *parent=0);
|
||||||
|
|
||||||
|
void setMapper(MonitoredDataMapper *mapper);
|
||||||
|
private:
|
||||||
|
QValueComboBox *unit;
|
||||||
|
QCheckBox *display_addresses;
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OptionsDialog::OptionsDialog(QWidget *parent):
|
||||||
|
QDialog(parent), contents_widget(0), pages_widget(0),
|
||||||
|
model(0), main_page(0), display_page(0)
|
||||||
|
{
|
||||||
|
contents_widget = new QListWidget();
|
||||||
|
contents_widget->setMaximumWidth(128);
|
||||||
|
|
||||||
|
pages_widget = new QStackedWidget();
|
||||||
|
pages_widget->setMinimumWidth(300);
|
||||||
|
|
||||||
|
QListWidgetItem *item_main = new QListWidgetItem(tr("Main"));
|
||||||
|
contents_widget->addItem(item_main);
|
||||||
|
main_page = new MainOptionsPage(this);
|
||||||
|
pages_widget->addWidget(main_page);
|
||||||
|
|
||||||
|
QListWidgetItem *item_display = new QListWidgetItem(tr("Display"));
|
||||||
|
contents_widget->addItem(item_display);
|
||||||
|
display_page = new DisplayOptionsPage(this);
|
||||||
|
pages_widget->addWidget(display_page);
|
||||||
|
|
||||||
|
contents_widget->setCurrentRow(0);
|
||||||
|
|
||||||
|
QHBoxLayout *main_layout = new QHBoxLayout();
|
||||||
|
main_layout->addWidget(contents_widget);
|
||||||
|
main_layout->addWidget(pages_widget, 1);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
layout->addLayout(main_layout);
|
||||||
|
|
||||||
|
QDialogButtonBox *buttonbox = new QDialogButtonBox();
|
||||||
|
buttonbox->setStandardButtons(QDialogButtonBox::Apply|QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
|
||||||
|
apply_button = buttonbox->button(QDialogButtonBox::Apply);
|
||||||
|
layout->addWidget(buttonbox);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
setWindowTitle(tr("Options"));
|
||||||
|
|
||||||
|
/* Widget-to-option mapper */
|
||||||
|
mapper = new MonitoredDataMapper(this);
|
||||||
|
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
||||||
|
mapper->setOrientation(Qt::Vertical);
|
||||||
|
/* enable apply button when data modified */
|
||||||
|
connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApply()));
|
||||||
|
/* disable apply button when new data loaded */
|
||||||
|
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApply()));
|
||||||
|
|
||||||
|
/* Event bindings */
|
||||||
|
connect(contents_widget, SIGNAL(currentRowChanged(int)), this, SLOT(changePage(int)));
|
||||||
|
connect(buttonbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(okClicked()));
|
||||||
|
connect(buttonbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(cancelClicked()));
|
||||||
|
connect(buttonbox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(applyClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::setModel(OptionsModel *model)
|
||||||
|
{
|
||||||
|
this->model = model;
|
||||||
|
|
||||||
|
mapper->setModel(model);
|
||||||
|
main_page->setMapper(mapper);
|
||||||
|
display_page->setMapper(mapper);
|
||||||
|
|
||||||
|
mapper->toFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::changePage(int index)
|
||||||
|
{
|
||||||
|
pages_widget->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::okClicked()
|
||||||
|
{
|
||||||
|
mapper->submit();
|
||||||
|
accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::cancelClicked()
|
||||||
|
{
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::applyClicked()
|
||||||
|
{
|
||||||
|
mapper->submit();
|
||||||
|
apply_button->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::enableApply()
|
||||||
|
{
|
||||||
|
apply_button->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsDialog::disableApply()
|
||||||
|
{
|
||||||
|
apply_button->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainOptionsPage::MainOptionsPage(QWidget *parent):
|
||||||
|
QWidget(parent)
|
||||||
|
{
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
|
||||||
|
bitcoin_at_startup = new QCheckBox(tr("&Start Bitcoin on window system startup"));
|
||||||
|
bitcoin_at_startup->setToolTip(tr("Automatically start Bitcoin after the computer is turned on"));
|
||||||
|
layout->addWidget(bitcoin_at_startup);
|
||||||
|
|
||||||
|
minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
|
||||||
|
minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
|
||||||
|
layout->addWidget(minimize_to_tray);
|
||||||
|
|
||||||
|
map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
|
||||||
|
map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
|
||||||
|
layout->addWidget(map_port_upnp);
|
||||||
|
|
||||||
|
minimize_on_close = new QCheckBox(tr("M&inimize on close"));
|
||||||
|
minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
|
||||||
|
layout->addWidget(minimize_on_close);
|
||||||
|
|
||||||
|
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
|
||||||
|
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
|
||||||
|
layout->addWidget(connect_socks4);
|
||||||
|
|
||||||
|
QHBoxLayout *proxy_hbox = new QHBoxLayout();
|
||||||
|
proxy_hbox->addSpacing(18);
|
||||||
|
QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP: "));
|
||||||
|
proxy_hbox->addWidget(proxy_ip_label);
|
||||||
|
proxy_ip = new QLineEdit();
|
||||||
|
proxy_ip->setMaximumWidth(140);
|
||||||
|
proxy_ip->setEnabled(false);
|
||||||
|
proxy_ip->setValidator(new QRegExpValidator(QRegExp("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"), this));
|
||||||
|
proxy_ip->setToolTip(tr("IP address of the proxy (e.g. 127.0.0.1)"));
|
||||||
|
proxy_ip_label->setBuddy(proxy_ip);
|
||||||
|
proxy_hbox->addWidget(proxy_ip);
|
||||||
|
QLabel *proxy_port_label = new QLabel(tr("&Port: "));
|
||||||
|
proxy_hbox->addWidget(proxy_port_label);
|
||||||
|
proxy_port = new QLineEdit();
|
||||||
|
proxy_port->setMaximumWidth(55);
|
||||||
|
proxy_port->setValidator(new QIntValidator(0, 65535, this));
|
||||||
|
proxy_port->setEnabled(false);
|
||||||
|
proxy_port->setToolTip(tr("Port of the proxy (e.g. 1234)"));
|
||||||
|
proxy_port_label->setBuddy(proxy_port);
|
||||||
|
proxy_hbox->addWidget(proxy_port);
|
||||||
|
proxy_hbox->addStretch(1);
|
||||||
|
|
||||||
|
layout->addLayout(proxy_hbox);
|
||||||
|
QLabel *fee_help = new QLabel(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly. Most transactions are 1KB. Fee 0.01 recommended."));
|
||||||
|
fee_help->setWordWrap(true);
|
||||||
|
layout->addWidget(fee_help);
|
||||||
|
|
||||||
|
QHBoxLayout *fee_hbox = new QHBoxLayout();
|
||||||
|
fee_hbox->addSpacing(18);
|
||||||
|
QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
|
||||||
|
fee_hbox->addWidget(fee_label);
|
||||||
|
fee_edit = new BitcoinAmountField();
|
||||||
|
fee_edit->setToolTip(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly. Most transactions are 1KB. Fee 0.01 recommended."));
|
||||||
|
|
||||||
|
fee_label->setBuddy(fee_edit);
|
||||||
|
fee_hbox->addWidget(fee_edit);
|
||||||
|
fee_hbox->addStretch(1);
|
||||||
|
|
||||||
|
layout->addLayout(fee_hbox);
|
||||||
|
|
||||||
|
layout->addStretch(1); // Extra space at bottom
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_ip, SLOT(setEnabled(bool)));
|
||||||
|
connect(connect_socks4, SIGNAL(toggled(bool)), proxy_port, SLOT(setEnabled(bool)));
|
||||||
|
|
||||||
|
#ifndef USE_UPNP
|
||||||
|
map_port_upnp->setDisabled(true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainOptionsPage::setMapper(MonitoredDataMapper *mapper)
|
||||||
|
{
|
||||||
|
// Map model to widgets
|
||||||
|
mapper->addMapping(bitcoin_at_startup, OptionsModel::StartAtStartup);
|
||||||
|
mapper->addMapping(minimize_to_tray, OptionsModel::MinimizeToTray);
|
||||||
|
mapper->addMapping(map_port_upnp, OptionsModel::MapPortUPnP);
|
||||||
|
mapper->addMapping(minimize_on_close, OptionsModel::MinimizeOnClose);
|
||||||
|
mapper->addMapping(connect_socks4, OptionsModel::ConnectSOCKS4);
|
||||||
|
mapper->addMapping(proxy_ip, OptionsModel::ProxyIP);
|
||||||
|
mapper->addMapping(proxy_port, OptionsModel::ProxyPort);
|
||||||
|
mapper->addMapping(fee_edit, OptionsModel::Fee);
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
|
||||||
|
QWidget(parent)
|
||||||
|
{
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
|
||||||
|
QHBoxLayout *unit_hbox = new QHBoxLayout();
|
||||||
|
unit_hbox->addSpacing(18);
|
||||||
|
QLabel *unit_label = new QLabel(tr("&Unit to show amounts in: "));
|
||||||
|
unit_hbox->addWidget(unit_label);
|
||||||
|
unit = new QValueComboBox(this);
|
||||||
|
unit->setModel(new BitcoinUnits(this));
|
||||||
|
unit->setToolTip(tr("Choose the default subdivision unit to show in the interface, and when sending coins"));
|
||||||
|
|
||||||
|
unit_label->setBuddy(unit);
|
||||||
|
unit_hbox->addWidget(unit);
|
||||||
|
|
||||||
|
layout->addLayout(unit_hbox);
|
||||||
|
|
||||||
|
display_addresses = new QCheckBox(tr("Display addresses in transaction list"), this);
|
||||||
|
layout->addWidget(display_addresses);
|
||||||
|
|
||||||
|
layout->addStretch();
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayOptionsPage::setMapper(MonitoredDataMapper *mapper)
|
||||||
|
{
|
||||||
|
mapper->addMapping(unit, OptionsModel::DisplayUnit);
|
||||||
|
mapper->addMapping(display_addresses, OptionsModel::DisplayAddresses);
|
||||||
|
}
|
50
src/qt/optionsdialog.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef OPTIONSDIALOG_H
|
||||||
|
#define OPTIONSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QStackedWidget;
|
||||||
|
class QListWidget;
|
||||||
|
class QListWidgetItem;
|
||||||
|
class QPushButton;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
class OptionsModel;
|
||||||
|
class MainOptionsPage;
|
||||||
|
class DisplayOptionsPage;
|
||||||
|
class MonitoredDataMapper;
|
||||||
|
|
||||||
|
class OptionsDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit OptionsDialog(QWidget *parent=0);
|
||||||
|
|
||||||
|
void setModel(OptionsModel *model);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void changePage(int index);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void okClicked();
|
||||||
|
void cancelClicked();
|
||||||
|
void applyClicked();
|
||||||
|
void enableApply();
|
||||||
|
void disableApply();
|
||||||
|
private:
|
||||||
|
QListWidget *contents_widget;
|
||||||
|
QStackedWidget *pages_widget;
|
||||||
|
OptionsModel *model;
|
||||||
|
MonitoredDataMapper *mapper;
|
||||||
|
QPushButton *apply_button;
|
||||||
|
|
||||||
|
// Pages
|
||||||
|
MainOptionsPage *main_page;
|
||||||
|
DisplayOptionsPage *display_page;
|
||||||
|
|
||||||
|
void setupMainPage();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OPTIONSDIALOG_H
|
162
src/qt/optionsmodel.cpp
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
#include "optionsmodel.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
|
||||||
|
#include "headers.h"
|
||||||
|
|
||||||
|
OptionsModel::OptionsModel(CWallet *wallet, QObject *parent) :
|
||||||
|
QAbstractListModel(parent),
|
||||||
|
wallet(wallet),
|
||||||
|
nDisplayUnit(BitcoinUnits::BTC),
|
||||||
|
bDisplayAddresses(false)
|
||||||
|
{
|
||||||
|
// Read our specific settings from the wallet db
|
||||||
|
CWalletDB walletdb(wallet->strWalletFile);
|
||||||
|
walletdb.ReadSetting("nDisplayUnit", nDisplayUnit);
|
||||||
|
walletdb.ReadSetting("bDisplayAddresses", bDisplayAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OptionsModel::rowCount(const QModelIndex & parent) const
|
||||||
|
{
|
||||||
|
return OptionIDRowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant OptionsModel::data(const QModelIndex & index, int role) const
|
||||||
|
{
|
||||||
|
if(role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
switch(index.row())
|
||||||
|
{
|
||||||
|
case StartAtStartup:
|
||||||
|
return QVariant();
|
||||||
|
case MinimizeToTray:
|
||||||
|
return QVariant(fMinimizeToTray);
|
||||||
|
case MapPortUPnP:
|
||||||
|
return QVariant(fUseUPnP);
|
||||||
|
case MinimizeOnClose:
|
||||||
|
return QVariant(fMinimizeOnClose);
|
||||||
|
case ConnectSOCKS4:
|
||||||
|
return QVariant(fUseProxy);
|
||||||
|
case ProxyIP:
|
||||||
|
return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
|
||||||
|
case ProxyPort:
|
||||||
|
return QVariant(QString::fromStdString(addrProxy.ToStringPort()));
|
||||||
|
case Fee:
|
||||||
|
return QVariant(nTransactionFee);
|
||||||
|
case DisplayUnit:
|
||||||
|
return QVariant(nDisplayUnit);
|
||||||
|
case DisplayAddresses:
|
||||||
|
return QVariant(bDisplayAddresses);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
|
||||||
|
{
|
||||||
|
bool successful = true; /* set to false on parse error */
|
||||||
|
if(role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
CWalletDB walletdb(wallet->strWalletFile);
|
||||||
|
switch(index.row())
|
||||||
|
{
|
||||||
|
case StartAtStartup:
|
||||||
|
successful = false; /*TODO*/
|
||||||
|
break;
|
||||||
|
case MinimizeToTray:
|
||||||
|
fMinimizeToTray = value.toBool();
|
||||||
|
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
|
||||||
|
break;
|
||||||
|
case MapPortUPnP:
|
||||||
|
fUseUPnP = value.toBool();
|
||||||
|
walletdb.WriteSetting("fUseUPnP", fUseUPnP);
|
||||||
|
#ifdef USE_UPNP
|
||||||
|
MapPort(fUseUPnP);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case MinimizeOnClose:
|
||||||
|
fMinimizeOnClose = value.toBool();
|
||||||
|
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
|
||||||
|
break;
|
||||||
|
case ConnectSOCKS4:
|
||||||
|
fUseProxy = value.toBool();
|
||||||
|
walletdb.WriteSetting("fUseProxy", fUseProxy);
|
||||||
|
break;
|
||||||
|
case ProxyIP:
|
||||||
|
{
|
||||||
|
// Use CAddress to parse and check IP
|
||||||
|
CAddress addr(value.toString().toStdString() + ":1");
|
||||||
|
if (addr.ip != INADDR_NONE)
|
||||||
|
{
|
||||||
|
addrProxy.ip = addr.ip;
|
||||||
|
walletdb.WriteSetting("addrProxy", addrProxy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ProxyPort:
|
||||||
|
{
|
||||||
|
int nPort = atoi(value.toString().toAscii().data());
|
||||||
|
if (nPort > 0 && nPort < USHRT_MAX)
|
||||||
|
{
|
||||||
|
addrProxy.port = htons(nPort);
|
||||||
|
walletdb.WriteSetting("addrProxy", addrProxy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
successful = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Fee: {
|
||||||
|
nTransactionFee = value.toLongLong();
|
||||||
|
walletdb.WriteSetting("nTransactionFee", nTransactionFee);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DisplayUnit: {
|
||||||
|
int unit = value.toInt();
|
||||||
|
nDisplayUnit = unit;
|
||||||
|
walletdb.WriteSetting("nDisplayUnit", nDisplayUnit);
|
||||||
|
emit displayUnitChanged(unit);
|
||||||
|
}
|
||||||
|
case DisplayAddresses: {
|
||||||
|
bDisplayAddresses = value.toBool();
|
||||||
|
walletdb.WriteSetting("bDisplayAddresses", bDisplayAddresses);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 OptionsModel::getTransactionFee()
|
||||||
|
{
|
||||||
|
return nTransactionFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsModel::getMinimizeToTray()
|
||||||
|
{
|
||||||
|
return fMinimizeToTray;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsModel::getMinimizeOnClose()
|
||||||
|
{
|
||||||
|
return fMinimizeOnClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OptionsModel::getDisplayUnit()
|
||||||
|
{
|
||||||
|
return nDisplayUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OptionsModel::getDisplayAddresses()
|
||||||
|
{
|
||||||
|
return bDisplayAddresses;
|
||||||
|
}
|
56
src/qt/optionsmodel.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef OPTIONSMODEL_H
|
||||||
|
#define OPTIONSMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
class CWallet;
|
||||||
|
|
||||||
|
/* Interface from QT to configuration data structure for bitcoin client.
|
||||||
|
To QT, the options are presented as a list with the different options
|
||||||
|
laid out vertically.
|
||||||
|
This can be changed to a tree once the settings become sufficiently
|
||||||
|
complex.
|
||||||
|
*/
|
||||||
|
class OptionsModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit OptionsModel(CWallet *wallet, QObject *parent = 0);
|
||||||
|
|
||||||
|
enum OptionID {
|
||||||
|
StartAtStartup, // bool
|
||||||
|
MinimizeToTray, // bool
|
||||||
|
MapPortUPnP, // bool
|
||||||
|
MinimizeOnClose, // bool
|
||||||
|
ConnectSOCKS4, // bool
|
||||||
|
ProxyIP, // QString
|
||||||
|
ProxyPort, // QString
|
||||||
|
Fee, // qint64
|
||||||
|
DisplayUnit, // BitcoinUnits::Unit
|
||||||
|
DisplayAddresses, // bool
|
||||||
|
OptionIDRowCount
|
||||||
|
};
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex & parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
|
||||||
|
|
||||||
|
/* Explicit getters */
|
||||||
|
qint64 getTransactionFee();
|
||||||
|
bool getMinimizeToTray();
|
||||||
|
bool getMinimizeOnClose();
|
||||||
|
int getDisplayUnit();
|
||||||
|
bool getDisplayAddresses();
|
||||||
|
private:
|
||||||
|
// Wallet stores persistent options
|
||||||
|
CWallet *wallet;
|
||||||
|
int nDisplayUnit;
|
||||||
|
bool bDisplayAddresses;
|
||||||
|
signals:
|
||||||
|
void displayUnitChanged(int unit);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OPTIONSMODEL_H
|
173
src/qt/overviewpage.cpp
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#include "overviewpage.h"
|
||||||
|
#include "ui_overviewpage.h"
|
||||||
|
|
||||||
|
#include "walletmodel.h"
|
||||||
|
#include "bitcoinunits.h"
|
||||||
|
#include "optionsmodel.h"
|
||||||
|
#include "transactiontablemodel.h"
|
||||||
|
#include "transactionfilterproxy.h"
|
||||||
|
#include "guiutil.h"
|
||||||
|
#include "guiconstants.h"
|
||||||
|
|
||||||
|
#include <QAbstractItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#define DECORATION_SIZE 64
|
||||||
|
#define NUM_ITEMS 3
|
||||||
|
|
||||||
|
class TxViewDelegate : public QAbstractItemDelegate
|
||||||
|
{
|
||||||
|
//Q_OBJECT
|
||||||
|
public:
|
||||||
|
TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index ) const
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
QIcon icon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
|
||||||
|
QRect mainRect = option.rect;
|
||||||
|
QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE));
|
||||||
|
int xspace = DECORATION_SIZE + 8;
|
||||||
|
int ypad = 6;
|
||||||
|
int halfheight = (mainRect.height() - 2*ypad)/2;
|
||||||
|
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
|
||||||
|
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
|
||||||
|
icon.paint(painter, decorationRect);
|
||||||
|
|
||||||
|
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
|
||||||
|
QString address = index.data(Qt::DisplayRole).toString();
|
||||||
|
qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong();
|
||||||
|
bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool();
|
||||||
|
QVariant value = index.data(Qt::ForegroundRole);
|
||||||
|
QColor foreground = option.palette.color(QPalette::Text);
|
||||||
|
if(qVariantCanConvert<QColor>(value))
|
||||||
|
{
|
||||||
|
foreground = qvariant_cast<QColor>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setPen(foreground);
|
||||||
|
painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address);
|
||||||
|
|
||||||
|
if(amount < 0)
|
||||||
|
{
|
||||||
|
foreground = COLOR_NEGATIVE;
|
||||||
|
}
|
||||||
|
else if(!confirmed)
|
||||||
|
{
|
||||||
|
foreground = COLOR_UNCONFIRMED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreground = option.palette.color(QPalette::Text);
|
||||||
|
}
|
||||||
|
painter->setPen(foreground);
|
||||||
|
QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true);
|
||||||
|
if(!confirmed)
|
||||||
|
{
|
||||||
|
amountText = QString("[") + amountText + QString("]");
|
||||||
|
}
|
||||||
|
painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
|
||||||
|
|
||||||
|
painter->setPen(option.palette.color(QPalette::Text));
|
||||||
|
painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return QSize(DECORATION_SIZE, DECORATION_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int unit;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
OverviewPage::OverviewPage(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::OverviewPage),
|
||||||
|
currentBalance(-1),
|
||||||
|
currentUnconfirmedBalance(-1),
|
||||||
|
txdelegate(new TxViewDelegate())
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Balance: <balance>
|
||||||
|
ui->labelBalance->setFont(QFont("Monospace", -1, QFont::Bold));
|
||||||
|
ui->labelBalance->setToolTip(tr("Your current balance"));
|
||||||
|
ui->labelBalance->setTextInteractionFlags(Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
|
||||||
|
|
||||||
|
// Unconfirmed balance: <balance>
|
||||||
|
ui->labelUnconfirmed->setFont(QFont("Monospace", -1, QFont::Bold));
|
||||||
|
ui->labelUnconfirmed->setToolTip(tr("Total of transactions that have yet to be confirmed, and do not yet count toward the current balance"));
|
||||||
|
ui->labelUnconfirmed->setTextInteractionFlags(Qt::TextSelectableByMouse|Qt::TextSelectableByKeyboard);
|
||||||
|
|
||||||
|
ui->labelNumTransactions->setToolTip(tr("Total number of transactions in wallet"));
|
||||||
|
|
||||||
|
// Recent transactions
|
||||||
|
ui->listTransactions->setStyleSheet("background:transparent");
|
||||||
|
ui->listTransactions->setItemDelegate(txdelegate);
|
||||||
|
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
|
||||||
|
ui->listTransactions->setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
|
||||||
|
|
||||||
|
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SIGNAL(transactionClicked(QModelIndex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
OverviewPage::~OverviewPage()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance)
|
||||||
|
{
|
||||||
|
int unit = model->getOptionsModel()->getDisplayUnit();
|
||||||
|
currentBalance = balance;
|
||||||
|
currentUnconfirmedBalance = unconfirmedBalance;
|
||||||
|
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
|
||||||
|
ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit(unit, unconfirmedBalance));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewPage::setNumTransactions(int count)
|
||||||
|
{
|
||||||
|
ui->labelNumTransactions->setText(QLocale::system().toString(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewPage::setModel(WalletModel *model)
|
||||||
|
{
|
||||||
|
this->model = model;
|
||||||
|
|
||||||
|
// Set up transaction list
|
||||||
|
TransactionFilterProxy *filter = new TransactionFilterProxy();
|
||||||
|
filter->setSourceModel(model->getTransactionTableModel());
|
||||||
|
filter->setLimit(NUM_ITEMS);
|
||||||
|
filter->setDynamicSortFilter(true);
|
||||||
|
filter->setSortRole(Qt::EditRole);
|
||||||
|
filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
|
||||||
|
|
||||||
|
ui->listTransactions->setModel(filter);
|
||||||
|
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
|
||||||
|
|
||||||
|
// Keep up to date with wallet
|
||||||
|
setBalance(model->getBalance(), model->getUnconfirmedBalance());
|
||||||
|
connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64)));
|
||||||
|
|
||||||
|
setNumTransactions(model->getNumTransactions());
|
||||||
|
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
|
||||||
|
|
||||||
|
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewPage::displayUnitChanged()
|
||||||
|
{
|
||||||
|
if(currentBalance != -1)
|
||||||
|
setBalance(currentBalance, currentUnconfirmedBalance);
|
||||||
|
|
||||||
|
txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
|
||||||
|
ui->listTransactions->update();
|
||||||
|
}
|
45
src/qt/overviewpage.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef OVERVIEWPAGE_H
|
||||||
|
#define OVERVIEWPAGE_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QModelIndex;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class OverviewPage;
|
||||||
|
}
|
||||||
|
class WalletModel;
|
||||||
|
class TxViewDelegate;
|
||||||
|
|
||||||
|
class OverviewPage : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OverviewPage(QWidget *parent = 0);
|
||||||
|
~OverviewPage();
|
||||||
|
|
||||||
|
void setModel(WalletModel *model);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setBalance(qint64 balance, qint64 unconfirmedBalance);
|
||||||
|
void setNumTransactions(int count);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void transactionClicked(const QModelIndex &index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::OverviewPage *ui;
|
||||||
|
WalletModel *model;
|
||||||
|
qint64 currentBalance;
|
||||||
|
qint64 currentUnconfirmedBalance;
|
||||||
|
|
||||||
|
TxViewDelegate *txdelegate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void displayUnitChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OVERVIEWPAGE_H
|
45
src/qt/qvalidatedlineedit.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "qvalidatedlineedit.h"
|
||||||
|
|
||||||
|
#include "guiconstants.h"
|
||||||
|
|
||||||
|
QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
|
||||||
|
QLineEdit(parent), valid(true)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValidatedLineEdit::setValid(bool valid)
|
||||||
|
{
|
||||||
|
if(valid == this->valid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(valid)
|
||||||
|
{
|
||||||
|
setStyleSheet("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setStyleSheet(STYLE_INVALID);
|
||||||
|
}
|
||||||
|
this->valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValidatedLineEdit::focusInEvent(QFocusEvent *evt)
|
||||||
|
{
|
||||||
|
// Clear invalid flag on focus
|
||||||
|
setValid(true);
|
||||||
|
QLineEdit::focusInEvent(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValidatedLineEdit::markValid()
|
||||||
|
{
|
||||||
|
setValid(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValidatedLineEdit::clear()
|
||||||
|
{
|
||||||
|
setValid(true);
|
||||||
|
QLineEdit::clear();
|
||||||
|
}
|
28
src/qt/qvalidatedlineedit.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef QVALIDATEDLINEEDIT_H
|
||||||
|
#define QVALIDATEDLINEEDIT_H
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
// Line edit that can be marked as "invalid". When marked as invalid,
|
||||||
|
// it will get a red background until it is focused.
|
||||||
|
class QValidatedLineEdit : public QLineEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit QValidatedLineEdit(QWidget *parent = 0);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void focusInEvent(QFocusEvent *evt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setValid(bool valid);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void markValid();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QVALIDATEDLINEEDIT_H
|
27
src/qt/qvaluecombobox.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "qvaluecombobox.h"
|
||||||
|
|
||||||
|
QValueComboBox::QValueComboBox(QWidget *parent) :
|
||||||
|
QComboBox(parent), role(Qt::UserRole)
|
||||||
|
{
|
||||||
|
connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(handleSelectionChanged(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int QValueComboBox::value() const
|
||||||
|
{
|
||||||
|
return itemData(currentIndex(), role).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValueComboBox::setValue(int value)
|
||||||
|
{
|
||||||
|
setCurrentIndex(findData(value, role));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValueComboBox::setRole(int role)
|
||||||
|
{
|
||||||
|
this->role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QValueComboBox::handleSelectionChanged(int idx)
|
||||||
|
{
|
||||||
|
emit valueChanged();
|
||||||
|
}
|
33
src/qt/qvaluecombobox.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef QVALUECOMBOBOX_H
|
||||||
|
#define QVALUECOMBOBOX_H
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
// QComboBox that can be used with QDataWidgetMapper to select
|
||||||
|
// ordinal values from a model.
|
||||||
|
class QValueComboBox : public QComboBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true);
|
||||||
|
public:
|
||||||
|
explicit QValueComboBox(QWidget *parent = 0);
|
||||||
|
|
||||||
|
int value() const;
|
||||||
|
void setValue(int value);
|
||||||
|
|
||||||
|
// Model role to use as value
|
||||||
|
void setRole(int role);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void valueChanged();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
private:
|
||||||
|
int role;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleSelectionChanged(int idx);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QVALUECOMBOBOX_H
|
1
src/qt/res/bitcoin-qt.rc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico"
|
BIN
src/qt/res/icons/add.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/qt/res/icons/address-book.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/qt/res/icons/bitcoin.icns
Normal file
BIN
src/qt/res/icons/bitcoin.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
src/qt/res/icons/bitcoin.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
src/qt/res/icons/bitcoin_testnet.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
src/qt/res/icons/clock1.png
Normal file
After Width: | Height: | Size: 946 B |
BIN
src/qt/res/icons/clock2.png
Normal file
After Width: | Height: | Size: 944 B |
BIN
src/qt/res/icons/clock3.png
Normal file
After Width: | Height: | Size: 946 B |
BIN
src/qt/res/icons/clock4.png
Normal file
After Width: | Height: | Size: 962 B |
BIN
src/qt/res/icons/clock5.png
Normal file
After Width: | Height: | Size: 956 B |
BIN
src/qt/res/icons/configure.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
src/qt/res/icons/connect0_16.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
src/qt/res/icons/connect1_16.png
Normal file
After Width: | Height: | Size: 612 B |
BIN
src/qt/res/icons/connect2_16.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
src/qt/res/icons/connect3_16.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
src/qt/res/icons/connect4_16.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
src/qt/res/icons/edit.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/qt/res/icons/editcopy.png
Normal file
After Width: | Height: | Size: 879 B |
BIN
src/qt/res/icons/editpaste.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/qt/res/icons/export.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/qt/res/icons/history.png
Normal file
After Width: | Height: | Size: 746 B |
BIN
src/qt/res/icons/key.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/qt/res/icons/lock_closed.png
Normal file
After Width: | Height: | Size: 1.2 KiB |