@ -0,0 +1,185 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 |