@ -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" |
@ -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} |
@ -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) |
||||||
|
|
||||||
|
|
@ -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 |
@ -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() |
@ -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() |
||||||
|
|
||||||
|
|
||||||
|
|
@ -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} |
||||||
|
|
@ -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(); |
||||||
|
} |
@ -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
|
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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
|
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -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
|
@ -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); |
||||||
|
} |
@ -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
|
@ -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; |
||||||
|
} |
@ -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> |
@ -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; |
||||||
|
} |
@ -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
|
@ -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); |
||||||
|
} |
@ -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
|
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
@ -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"), |
||||||
|
}; |
@ -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(); |
||||||
|
} |
@ -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
|
@ -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()); |
||||||
|
} |
@ -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
|
@ -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; |
||||||
|
} |
||||||
|
|
@ -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
|
@ -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; |
||||||
|
} |
@ -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
|
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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
|
@ -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; |
||||||
|
} |
@ -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
|
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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
|
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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
|
@ -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); |
||||||
|
} |
@ -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
|
@ -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; |
||||||
|
} |
@ -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
|
@ -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(); |
||||||
|
} |
@ -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
|
@ -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(); |
||||||
|
} |
@ -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
|
@ -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(); |
||||||
|
} |
@ -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
|
@ -0,0 +1 @@ |
|||||||
|
IDI_ICON1 ICON DISCARDABLE "icons/bitcoin.ico" |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 946 B |
After Width: | Height: | Size: 944 B |
After Width: | Height: | Size: 946 B |
After Width: | Height: | Size: 962 B |
After Width: | Height: | Size: 956 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 702 B |
After Width: | Height: | Size: 612 B |
After Width: | Height: | Size: 623 B |
After Width: | Height: | Size: 625 B |
After Width: | Height: | Size: 611 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 879 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 746 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |