|
|
|
// Copyright (c) 2011-2014 The Bitcoin developers
|
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#include "bitcoingui.h"
|
|
|
|
|
|
|
|
#include "bitcoinunits.h"
|
|
|
|
#include "clientmodel.h"
|
|
|
|
#include "guiconstants.h"
|
|
|
|
#include "guiutil.h"
|
|
|
|
#include "notificator.h"
|
|
|
|
#include "openuridialog.h"
|
|
|
|
#include "optionsdialog.h"
|
|
|
|
#include "optionsmodel.h"
|
|
|
|
#include "rpcconsole.h"
|
|
|
|
#include "utilitydialog.h"
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
#include "walletframe.h"
|
|
|
|
#include "walletmodel.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
#include "macdockiconhandler.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "init.h"
|
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
10 years ago
|
|
|
#include "util.h"
|
|
|
|
#include "ui_interface.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <QAction>
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QDesktopWidget>
|
|
|
|
#include <QDragEnterEvent>
|
|
|
|
#include <QIcon>
|
|
|
|
#include <QListWidget>
|
|
|
|
#include <QMenuBar>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QMimeData>
|
|
|
|
#include <QProgressBar>
|
|
|
|
#include <QProgressDialog>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QStackedWidget>
|
|
|
|
#include <QStatusBar>
|
|
|
|
#include <QStyle>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QToolBar>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
|
|
#if QT_VERSION < 0x050000
|
|
|
|
#include <QUrl>
|
|
|
|
#include <QTextDocument>
|
|
|
|
#else
|
|
|
|
#include <QUrlQuery>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
|
|
|
|
|
|
|
|
BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
|
|
|
|
QMainWindow(parent),
|
|
|
|
clientModel(0),
|
|
|
|
walletFrame(0),
|
|
|
|
unitDisplayControl(0),
|
|
|
|
labelEncryptionIcon(0),
|
|
|
|
labelConnectionsIcon(0),
|
|
|
|
labelBlocksIcon(0),
|
|
|
|
progressBarLabel(0),
|
|
|
|
progressBar(0),
|
|
|
|
progressDialog(0),
|
|
|
|
appMenuBar(0),
|
|
|
|
overviewAction(0),
|
|
|
|
historyAction(0),
|
|
|
|
quitAction(0),
|
|
|
|
sendCoinsAction(0),
|
|
|
|
usedSendingAddressesAction(0),
|
|
|
|
usedReceivingAddressesAction(0),
|
|
|
|
signMessageAction(0),
|
|
|
|
verifyMessageAction(0),
|
|
|
|
aboutAction(0),
|
|
|
|
receiveCoinsAction(0),
|
|
|
|
optionsAction(0),
|
|
|
|
toggleHideAction(0),
|
|
|
|
encryptWalletAction(0),
|
|
|
|
backupWalletAction(0),
|
|
|
|
changePassphraseAction(0),
|
|
|
|
aboutQtAction(0),
|
|
|
|
openRPCConsoleAction(0),
|
|
|
|
openAction(0),
|
|
|
|
showHelpMessageAction(0),
|
|
|
|
trayIcon(0),
|
|
|
|
trayIconMenu(0),
|
|
|
|
notificator(0),
|
|
|
|
rpcConsole(0),
|
|
|
|
prevBlocks(0),
|
|
|
|
spinnerFrame(0)
|
|
|
|
{
|
|
|
|
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
|
|
|
|
|
|
|
|
QString windowTitle = tr("Bitcoin Core") + " - ";
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
/* if compiled with wallet support, -disablewallet can still disable the wallet */
|
|
|
|
bool enableWallet = !GetBoolArg("-disablewallet", false);
|
|
|
|
#else
|
|
|
|
bool enableWallet = false;
|
|
|
|
#endif
|
|
|
|
if(enableWallet)
|
|
|
|
{
|
|
|
|
windowTitle += tr("Wallet");
|
|
|
|
} else {
|
|
|
|
windowTitle += tr("Node");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fIsTestnet)
|
|
|
|
{
|
|
|
|
#ifndef Q_OS_MAC
|
|
|
|
QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
|
|
|
|
setWindowIcon(QIcon(":icons/bitcoin"));
|
|
|
|
#else
|
|
|
|
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
windowTitle += " " + tr("[testnet]");
|
|
|
|
#ifndef Q_OS_MAC
|
|
|
|
QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet"));
|
|
|
|
setWindowIcon(QIcon(":icons/bitcoin_testnet"));
|
|
|
|
#else
|
|
|
|
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet"));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
setWindowTitle(windowTitle);
|
|
|
|
|
|
|
|
#if defined(Q_OS_MAC) && QT_VERSION < 0x050000
|
|
|
|
// This property is not implemented in Qt 5. Setting it has no effect.
|
|
|
|
// A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras.
|
|
|
|
setUnifiedTitleAndToolBarOnMac(true);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rpcConsole = new RPCConsole(enableWallet ? this : 0);
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
if(enableWallet)
|
|
|
|
{
|
|
|
|
/** Create wallet frame and make it the central widget */
|
|
|
|
walletFrame = new WalletFrame(this);
|
|
|
|
setCentralWidget(walletFrame);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/* When compiled without wallet or -disablewallet is provided,
|
|
|
|
* the central widget is the rpc console.
|
|
|
|
*/
|
|
|
|
setCentralWidget(rpcConsole);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accept D&D of URIs
|
|
|
|
setAcceptDrops(true);
|
|
|
|
|
|
|
|
// Create actions for the toolbar, menu bar and tray/dock icon
|
|
|
|
// Needs walletFrame to be initialized
|
|
|
|
createActions(fIsTestnet);
|
|
|
|
|
|
|
|
// Create application menu bar
|
|
|
|
createMenuBar();
|
|
|
|
|
|
|
|
// Create the toolbars
|
|
|
|
createToolBars();
|
|
|
|
|
|
|
|
// Create system tray icon and notification
|
|
|
|
createTrayIcon(fIsTestnet);
|
|
|
|
|
|
|
|
// Create status bar
|
|
|
|
statusBar();
|
|
|
|
|
|
|
|
// Status bar notification icons
|
|
|
|
QFrame *frameBlocks = new QFrame();
|
|
|
|
frameBlocks->setContentsMargins(0,0,0,0);
|
|
|
|
frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
|
|
|
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
|
|
|
|
frameBlocksLayout->setContentsMargins(3,0,3,0);
|
|
|
|
frameBlocksLayout->setSpacing(3);
|
|
|
|
unitDisplayControl = new UnitDisplayStatusBarControl();
|
|
|
|
labelEncryptionIcon = new QLabel();
|
|
|
|
labelConnectionsIcon = new QLabel();
|
|
|
|
labelBlocksIcon = new QLabel();
|
|
|
|
if(enableWallet)
|
|
|
|
{
|
|
|
|
frameBlocksLayout->addStretch();
|
|
|
|
frameBlocksLayout->addWidget(unitDisplayControl);
|
|
|
|
frameBlocksLayout->addStretch();
|
|
|
|
frameBlocksLayout->addWidget(labelEncryptionIcon);
|
|
|
|
}
|
|
|
|
frameBlocksLayout->addStretch();
|
|
|
|
frameBlocksLayout->addWidget(labelConnectionsIcon);
|
|
|
|
frameBlocksLayout->addStretch();
|
|
|
|
frameBlocksLayout->addWidget(labelBlocksIcon);
|
|
|
|
frameBlocksLayout->addStretch();
|
|
|
|
|
|
|
|
// Progress bar and label for blocks download
|
|
|
|
progressBarLabel = new QLabel();
|
|
|
|
progressBarLabel->setVisible(false);
|
|
|
|
progressBar = new QProgressBar();
|
|
|
|
progressBar->setAlignment(Qt::AlignCenter);
|
|
|
|
progressBar->setVisible(false);
|
|
|
|
|
|
|
|
// Override style sheet for progress bar for styles that have a segmented progress bar,
|
|
|
|
// as they make the text unreadable (workaround for issue #1071)
|
|
|
|
// See https://qt-project.org/doc/qt-4.8/gallery.html
|
|
|
|
QString curStyle = QApplication::style()->metaObject()->className();
|
|
|
|
if(curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle")
|
|
|
|
{
|
|
|
|
progressBar->setStyleSheet("QProgressBar { background-color: #e8e8e8; border: 1px solid grey; border-radius: 7px; padding: 1px; text-align: center; } QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: 7px; margin: 0px; }");
|
|
|
|
}
|
|
|
|
|
|
|
|
statusBar()->addWidget(progressBarLabel);
|
|
|
|
statusBar()->addWidget(progressBar);
|
|
|
|
statusBar()->addPermanentWidget(frameBlocks);
|
|
|
|
|
|
|
|
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
|
|
|
|
|
|
|
|
// prevents an open debug window from becoming stuck/unusable on client shutdown
|
|
|
|
connect(quitAction, SIGNAL(triggered()), rpcConsole, SLOT(hide()));
|
|
|
|
|
|
|
|
// Install event filter to be able to catch status tip events (QEvent::StatusTip)
|
|
|
|
this->installEventFilter(this);
|
|
|
|
|
|
|
|
// Initially wallet actions should be disabled
|
|
|
|
setWalletActionsEnabled(false);
|
|
|
|
|
|
|
|
// Subscribe to notifications from core
|
|
|
|
subscribeToCoreSignals();
|
|
|
|
}
|
|
|
|
|
|
|
|
BitcoinGUI::~BitcoinGUI()
|
|
|
|
{
|
|
|
|
// Unsubscribe from notifications from core
|
|
|
|
unsubscribeFromCoreSignals();
|
|
|
|
|
|
|
|
GUIUtil::saveWindowGeometry("nWindow", this);
|
|
|
|
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
|
|
|
|
trayIcon->hide();
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
delete appMenuBar;
|
|
|
|
MacDockIconHandler::instance()->setMainWindow(NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::createActions(bool fIsTestnet)
|
|
|
|
{
|
|
|
|
QActionGroup *tabGroup = new QActionGroup(this);
|
|
|
|
|
|
|
|
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
|
|
|
|
overviewAction->setStatusTip(tr("Show general overview of wallet"));
|
|
|
|
overviewAction->setToolTip(overviewAction->statusTip());
|
|
|
|
overviewAction->setCheckable(true);
|
|
|
|
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
|
|
|
|
tabGroup->addAction(overviewAction);
|
|
|
|
|
|
|
|
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send"), this);
|
|
|
|
sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
|
|
|
|
sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
|
|
|
|
sendCoinsAction->setCheckable(true);
|
|
|
|
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
|
|
|
|
tabGroup->addAction(sendCoinsAction);
|
|
|
|
|
|
|
|
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
|
|
|
|
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
|
|
|
|
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
|
|
|
|
receiveCoinsAction->setCheckable(true);
|
|
|
|
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
|
|
|
|
tabGroup->addAction(receiveCoinsAction);
|
|
|
|
|
|
|
|
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
|
|
|
|
historyAction->setStatusTip(tr("Browse transaction history"));
|
|
|
|
historyAction->setToolTip(historyAction->statusTip());
|
|
|
|
historyAction->setCheckable(true);
|
|
|
|
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
|
|
|
|
tabGroup->addAction(historyAction);
|
|
|
|
|
|
|
|
// These showNormalIfMinimized are needed because Send Coins and Receive Coins
|
|
|
|
// can be triggered from the tray menu, and need to show the GUI to be useful.
|
|
|
|
connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
|
|
|
|
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
|
|
|
|
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
|
|
|
|
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
|
|
|
|
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
|
|
|
|
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
|
|
|
|
connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
|
|
|
|
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
|
|
|
|
|
|
|
|
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
|
|
|
|
quitAction->setStatusTip(tr("Quit application"));
|
|
|
|
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
|
|
|
|
quitAction->setMenuRole(QAction::QuitRole);
|
|
|
|
if (!fIsTestnet)
|
|
|
|
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin Core"), this);
|
|
|
|
else
|
|
|
|
aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin Core"), this);
|
|
|
|
aboutAction->setStatusTip(tr("Show information about Bitcoin Core"));
|
|
|
|
aboutAction->setMenuRole(QAction::AboutRole);
|
|
|
|
#if QT_VERSION < 0x050000
|
|
|
|
aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
|
|
|
|
#else
|
|
|
|
aboutQtAction = new QAction(QIcon(":/qt-project.org/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
|
|
|
|
#endif
|
|
|
|
aboutQtAction->setStatusTip(tr("Show information about Qt"));
|
|
|
|
aboutQtAction->setMenuRole(QAction::AboutQtRole);
|
|
|
|
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
|
|
|
|
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
|
|
|
|
optionsAction->setMenuRole(QAction::PreferencesRole);
|
|
|
|
if (!fIsTestnet)
|
|
|
|
toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
|
|
|
|
else
|
|
|
|
toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this);
|
|
|
|
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
|
|
|
|
|
|
|
|
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
|
|
|
|
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
|
|
|
|
encryptWalletAction->setCheckable(true);
|
|
|
|
backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
|
|
|
|
backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
|
|
|
|
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
|
|
|
|
changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
|
|
|
|
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
|
|
|
|
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
|
|
|
|
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
|
|
|
|
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
|
|
|
|
|
|
|
|
openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
|
|
|
|
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
|
|
|
|
|
|
|
|
usedSendingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
|
|
|
|
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
|
|
|
|
usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
|
|
|
|
usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
|
|
|
|
|
|
|
|
openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this);
|
|
|
|
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
|
|
|
|
|
|
|
|
showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this);
|
|
|
|
showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options"));
|
|
|
|
|
|
|
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
|
|
|
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
|
|
|
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
|
|
|
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
|
|
|
connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
|
|
|
|
connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked()));
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
connect(encryptWalletAction, SIGNAL(triggered(bool)), walletFrame, SLOT(encryptWallet(bool)));
|
|
|
|
connect(backupWalletAction, SIGNAL(triggered()), walletFrame, SLOT(backupWallet()));
|
|
|
|
connect(changePassphraseAction, SIGNAL(triggered()), walletFrame, SLOT(changePassphrase()));
|
|
|
|
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
|
|
|
|
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
|
|
|
|
connect(usedSendingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedSendingAddresses()));
|
|
|
|
connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses()));
|
|
|
|
connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked()));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::createMenuBar()
|
|
|
|
{
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
// Create a decoupled menu bar on Mac which stays even if the window is closed
|
|
|
|
appMenuBar = new QMenuBar();
|
|
|
|
#else
|
|
|
|
// Get the main window's menu bar on other platforms
|
|
|
|
appMenuBar = menuBar();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Configure the menus
|
|
|
|
QMenu *file = appMenuBar->addMenu(tr("&File"));
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
file->addAction(openAction);
|
|
|
|
file->addAction(backupWalletAction);
|
|
|
|
file->addAction(signMessageAction);
|
|
|
|
file->addAction(verifyMessageAction);
|
|
|
|
file->addSeparator();
|
|
|
|
file->addAction(usedSendingAddressesAction);
|
|
|
|
file->addAction(usedReceivingAddressesAction);
|
|
|
|
file->addSeparator();
|
|
|
|
}
|
|
|
|
file->addAction(quitAction);
|
|
|
|
|
|
|
|
QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
settings->addAction(encryptWalletAction);
|
|
|
|
settings->addAction(changePassphraseAction);
|
|
|
|
settings->addSeparator();
|
|
|
|
}
|
|
|
|
settings->addAction(optionsAction);
|
|
|
|
|
|
|
|
QMenu *help = appMenuBar->addMenu(tr("&Help"));
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
help->addAction(openRPCConsoleAction);
|
|
|
|
}
|
|
|
|
help->addAction(showHelpMessageAction);
|
|
|
|
help->addSeparator();
|
|
|
|
help->addAction(aboutAction);
|
|
|
|
help->addAction(aboutQtAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::createToolBars()
|
|
|
|
{
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
|
|
|
|
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
|
|
|
toolbar->addAction(overviewAction);
|
|
|
|
toolbar->addAction(sendCoinsAction);
|
|
|
|
toolbar->addAction(receiveCoinsAction);
|
|
|
|
toolbar->addAction(historyAction);
|
|
|
|
overviewAction->setChecked(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::setClientModel(ClientModel *clientModel)
|
|
|
|
{
|
|
|
|
this->clientModel = clientModel;
|
|
|
|
if(clientModel)
|
|
|
|
{
|
|
|
|
// Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
|
|
|
|
// while the client has not yet fully loaded
|
|
|
|
createTrayIconMenu();
|
|
|
|
|
|
|
|
// 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)));
|
|
|
|
|
|
|
|
// Receive and report messages from client model
|
|
|
|
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
|
|
|
|
|
|
|
|
// Show progress dialog
|
|
|
|
connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
|
|
|
|
|
|
|
|
rpcConsole->setClientModel(clientModel);
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
if(walletFrame)
|
|
|
|
{
|
|
|
|
walletFrame->setClientModel(clientModel);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
|
|
|
|
} else {
|
|
|
|
// Disable possibility to show main window via action
|
|
|
|
toggleHideAction->setEnabled(false);
|
|
|
|
// Disable context menu on tray icon
|
|
|
|
trayIconMenu->clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel)
|
|
|
|
{
|
|
|
|
if(!walletFrame)
|
|
|
|
return false;
|
|
|
|
setWalletActionsEnabled(true);
|
|
|
|
return walletFrame->addWallet(name, walletModel);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BitcoinGUI::setCurrentWallet(const QString& name)
|
|
|
|
{
|
|
|
|
if(!walletFrame)
|
|
|
|
return false;
|
|
|
|
return walletFrame->setCurrentWallet(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::removeAllWallets()
|
|
|
|
{
|
|
|
|
if(!walletFrame)
|
|
|
|
return;
|
|
|
|
setWalletActionsEnabled(false);
|
|
|
|
walletFrame->removeAllWallets();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void BitcoinGUI::setWalletActionsEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
overviewAction->setEnabled(enabled);
|
|
|
|
sendCoinsAction->setEnabled(enabled);
|
|
|
|
receiveCoinsAction->setEnabled(enabled);
|
|
|
|
historyAction->setEnabled(enabled);
|
|
|
|
encryptWalletAction->setEnabled(enabled);
|
|
|
|
backupWalletAction->setEnabled(enabled);
|
|
|
|
changePassphraseAction->setEnabled(enabled);
|
|
|
|
signMessageAction->setEnabled(enabled);
|
|
|
|
verifyMessageAction->setEnabled(enabled);
|
|
|
|
usedSendingAddressesAction->setEnabled(enabled);
|
|
|
|
usedReceivingAddressesAction->setEnabled(enabled);
|
|
|
|
openAction->setEnabled(enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::createTrayIcon(bool fIsTestnet)
|
|
|
|
{
|
|
|
|
#ifndef Q_OS_MAC
|
|
|
|
trayIcon = new QSystemTrayIcon(this);
|
|
|
|
|
|
|
|
if (!fIsTestnet)
|
|
|
|
{
|
|
|
|
trayIcon->setToolTip(tr("Bitcoin Core client"));
|
|
|
|
trayIcon->setIcon(QIcon(":/icons/bitcoin"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]"));
|
|
|
|
trayIcon->setIcon(QIcon(":/icons/bitcoin_testnet"));
|
|
|
|
}
|
|
|
|
|
|
|
|
trayIcon->show();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::createTrayIconMenu()
|
|
|
|
{
|
|
|
|
#ifndef Q_OS_MAC
|
|
|
|
// return if trayIcon is unset (only on non-Mac OSes)
|
|
|
|
if (!trayIcon)
|
|
|
|
return;
|
|
|
|
|
|
|
|
trayIconMenu = new QMenu(this);
|
|
|
|
trayIcon->setContextMenu(trayIconMenu);
|
|
|
|
|
|
|
|
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
|
|
|
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
|
|
|
|
#else
|
|
|
|
// Note: On Mac, the dock icon is used to provide the tray's functionality.
|
|
|
|
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
|
|
|
|
dockIconHandler->setMainWindow((QMainWindow *)this);
|
|
|
|
trayIconMenu = dockIconHandler->dockMenu();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Configuration of the tray icon (or dock icon) icon menu
|
|
|
|
trayIconMenu->addAction(toggleHideAction);
|
|
|
|
trayIconMenu->addSeparator();
|
|
|
|
trayIconMenu->addAction(sendCoinsAction);
|
|
|
|
trayIconMenu->addAction(receiveCoinsAction);
|
|
|
|
trayIconMenu->addSeparator();
|
|
|
|
trayIconMenu->addAction(signMessageAction);
|
|
|
|
trayIconMenu->addAction(verifyMessageAction);
|
|
|
|
trayIconMenu->addSeparator();
|
|
|
|
trayIconMenu->addAction(optionsAction);
|
|
|
|
trayIconMenu->addAction(openRPCConsoleAction);
|
|
|
|
#ifndef Q_OS_MAC // This is built-in on Mac
|
|
|
|
trayIconMenu->addSeparator();
|
|
|
|
trayIconMenu->addAction(quitAction);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef Q_OS_MAC
|
|
|
|
void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
|
|
|
{
|
|
|
|
if(reason == QSystemTrayIcon::Trigger)
|
|
|
|
{
|
|
|
|
// Click on system tray icon triggers show/hide of the main window
|
|
|
|
toggleHidden();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void BitcoinGUI::optionsClicked()
|
|
|
|
{
|
|
|
|
if(!clientModel || !clientModel->getOptionsModel())
|
|
|
|
return;
|
|
|
|
|
|
|
|
OptionsDialog dlg(this);
|
|
|
|
dlg.setModel(clientModel->getOptionsModel());
|
|
|
|
dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::aboutClicked()
|
|
|
|
{
|
|
|
|
if(!clientModel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
HelpMessageDialog dlg(this, true);
|
|
|
|
dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::showHelpMessageClicked()
|
|
|
|
{
|
|
|
|
HelpMessageDialog *help = new HelpMessageDialog(this, false);
|
|
|
|
help->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
help->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
void BitcoinGUI::openClicked()
|
|
|
|
{
|
|
|
|
OpenURIDialog dlg(this);
|
|
|
|
if(dlg.exec())
|
|
|
|
{
|
|
|
|
emit receivedURI(dlg.getURI());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoOverviewPage()
|
|
|
|
{
|
|
|
|
overviewAction->setChecked(true);
|
|
|
|
if (walletFrame) walletFrame->gotoOverviewPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoHistoryPage()
|
|
|
|
{
|
|
|
|
historyAction->setChecked(true);
|
|
|
|
if (walletFrame) walletFrame->gotoHistoryPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoReceiveCoinsPage()
|
|
|
|
{
|
|
|
|
receiveCoinsAction->setChecked(true);
|
|
|
|
if (walletFrame) walletFrame->gotoReceiveCoinsPage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoSendCoinsPage(QString addr)
|
|
|
|
{
|
|
|
|
sendCoinsAction->setChecked(true);
|
|
|
|
if (walletFrame) walletFrame->gotoSendCoinsPage(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoSignMessageTab(QString addr)
|
|
|
|
{
|
|
|
|
if (walletFrame) walletFrame->gotoSignMessageTab(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::gotoVerifyMessageTab(QString addr)
|
|
|
|
{
|
|
|
|
if (walletFrame) walletFrame->gotoVerifyMessageTab(addr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
// Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
|
|
|
|
statusBar()->clearMessage();
|
|
|
|
|
|
|
|
// Acquire current block source
|
|
|
|
enum BlockSource blockSource = clientModel->getBlockSource();
|
|
|
|
switch (blockSource) {
|
|
|
|
case BLOCK_SOURCE_NETWORK:
|
|
|
|
progressBarLabel->setText(tr("Synchronizing with network..."));
|
|
|
|
break;
|
|
|
|
case BLOCK_SOURCE_DISK:
|
|
|
|
progressBarLabel->setText(tr("Importing blocks from disk..."));
|
|
|
|
break;
|
|
|
|
case BLOCK_SOURCE_REINDEX:
|
|
|
|
progressBarLabel->setText(tr("Reindexing blocks on disk..."));
|
|
|
|
break;
|
|
|
|
case BLOCK_SOURCE_NONE:
|
|
|
|
// Case: not Importing, not Reindexing and no network connection
|
|
|
|
progressBarLabel->setText(tr("No block source available..."));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString tooltip;
|
|
|
|
|
|
|
|
QDateTime lastBlockDate = clientModel->getLastBlockDate();
|
|
|
|
QDateTime currentDate = QDateTime::currentDateTime();
|
|
|
|
int secs = lastBlockDate.secsTo(currentDate);
|
|
|
|
|
|
|
|
tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
|
|
|
|
|
|
|
|
// Set icon state: spinning if catching up, tick otherwise
|
|
|
|
if(secs < 90*60)
|
|
|
|
{
|
|
|
|
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
|
|
|
|
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
if(walletFrame)
|
|
|
|
walletFrame->showOutOfSyncWarning(false);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
progressBarLabel->setVisible(false);
|
|
|
|
progressBar->setVisible(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Represent time from last generated block in human readable text
|
|
|
|
QString timeBehindText;
|
|
|
|
const int HOUR_IN_SECONDS = 60*60;
|
|
|
|
const int DAY_IN_SECONDS = 24*60*60;
|
|
|
|
const int WEEK_IN_SECONDS = 7*24*60*60;
|
|
|
|
const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar
|
|
|
|
if(secs < 2*DAY_IN_SECONDS)
|
|
|
|
{
|
|
|
|
timeBehindText = tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
|
|
|
|
}
|
|
|
|
else if(secs < 2*WEEK_IN_SECONDS)
|
|
|
|
{
|
|
|
|
timeBehindText = tr("%n day(s)","",secs/DAY_IN_SECONDS);
|
|
|
|
}
|
|
|
|
else if(secs < YEAR_IN_SECONDS)
|
|
|
|
{
|
|
|
|
timeBehindText = tr("%n week(s)","",secs/WEEK_IN_SECONDS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int years = secs / YEAR_IN_SECONDS;
|
|
|
|
int remainder = secs % YEAR_IN_SECONDS;
|
|
|
|
timeBehindText = tr("%1 and %2").arg(tr("%n year(s)", "", years)).arg(tr("%n week(s)","", remainder/WEEK_IN_SECONDS));
|
|
|
|
}
|
|
|
|
|
|
|
|
progressBarLabel->setVisible(true);
|
|
|
|
progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
|
|
|
|
progressBar->setMaximum(1000000000);
|
|
|
|
progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
|
|
|
|
progressBar->setVisible(true);
|
|
|
|
|
|
|
|
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
|
|
|
|
if(count != prevBlocks)
|
|
|
|
{
|
|
|
|
labelBlocksIcon->setPixmap(QIcon(QString(
|
|
|
|
":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
|
|
|
|
.pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
|
|
|
|
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
|
|
|
|
}
|
|
|
|
prevBlocks = count;
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
if(walletFrame)
|
|
|
|
walletFrame->showOutOfSyncWarning(true);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
tooltip += QString("<br>");
|
|
|
|
tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
|
|
|
|
tooltip += QString("<br>");
|
|
|
|
tooltip += tr("Transactions after this will not yet be visible.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't word-wrap this (fixed-width) tooltip
|
|
|
|
tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
|
|
|
|
|
|
|
|
labelBlocksIcon->setToolTip(tooltip);
|
|
|
|
progressBarLabel->setToolTip(tooltip);
|
|
|
|
progressBar->setToolTip(tooltip);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
|
|
|
|
{
|
|
|
|
QString strTitle = tr("Bitcoin"); // default title
|
|
|
|
// Default to information icon
|
|
|
|
int nMBoxIcon = QMessageBox::Information;
|
|
|
|
int nNotifyIcon = Notificator::Information;
|
|
|
|
|
|
|
|
QString msgType;
|
|
|
|
|
|
|
|
// Prefer supplied title over style based title
|
|
|
|
if (!title.isEmpty()) {
|
|
|
|
msgType = title;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
switch (style) {
|
|
|
|
case CClientUIInterface::MSG_ERROR:
|
|
|
|
msgType = tr("Error");
|
|
|
|
break;
|
|
|
|
case CClientUIInterface::MSG_WARNING:
|
|
|
|
msgType = tr("Warning");
|
|
|
|
break;
|
|
|
|
case CClientUIInterface::MSG_INFORMATION:
|
|
|
|
msgType = tr("Information");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Append title to "Bitcoin - "
|
|
|
|
if (!msgType.isEmpty())
|
|
|
|
strTitle += " - " + msgType;
|
|
|
|
|
|
|
|
// Check for error/warning icon
|
|
|
|
if (style & CClientUIInterface::ICON_ERROR) {
|
|
|
|
nMBoxIcon = QMessageBox::Critical;
|
|
|
|
nNotifyIcon = Notificator::Critical;
|
|
|
|
}
|
|
|
|
else if (style & CClientUIInterface::ICON_WARNING) {
|
|
|
|
nMBoxIcon = QMessageBox::Warning;
|
|
|
|
nNotifyIcon = Notificator::Warning;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display message
|
|
|
|
if (style & CClientUIInterface::MODAL) {
|
|
|
|
// Check for buttons, use OK as default, if none was supplied
|
|
|
|
QMessageBox::StandardButton buttons;
|
|
|
|
if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
|
|
|
|
buttons = QMessageBox::Ok;
|
|
|
|
|
|
|
|
showNormalIfMinimized();
|
|
|
|
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons, this);
|
|
|
|
int r = mBox.exec();
|
|
|
|
if (ret != NULL)
|
|
|
|
*ret = r == QMessageBox::Ok;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::changeEvent(QEvent *e)
|
|
|
|
{
|
|
|
|
QMainWindow::changeEvent(e);
|
|
|
|
#ifndef Q_OS_MAC // Ignored on Mac
|
|
|
|
if(e->type() == QEvent::WindowStateChange)
|
|
|
|
{
|
|
|
|
if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray())
|
|
|
|
{
|
|
|
|
QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e);
|
|
|
|
if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized())
|
|
|
|
{
|
|
|
|
QTimer::singleShot(0, this, SLOT(hide()));
|
|
|
|
e->ignore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::closeEvent(QCloseEvent *event)
|
|
|
|
{
|
|
|
|
if(clientModel)
|
|
|
|
{
|
|
|
|
#ifndef Q_OS_MAC // Ignored on Mac
|
|
|
|
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
|
|
|
|
!clientModel->getOptionsModel()->getMinimizeOnClose())
|
|
|
|
{
|
|
|
|
QApplication::quit();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
QMainWindow::closeEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
void BitcoinGUI::incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address)
|
|
|
|
{
|
|
|
|
// On new transaction, make an info balloon
|
|
|
|
message((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(unit, amount, true))
|
|
|
|
.arg(type)
|
|
|
|
.arg(address), CClientUIInterface::MSG_INFORMATION);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
|
|
|
|
{
|
|
|
|
// Accept only URIs
|
|
|
|
if(event->mimeData()->hasUrls())
|
|
|
|
event->acceptProposedAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::dropEvent(QDropEvent *event)
|
|
|
|
{
|
|
|
|
if(event->mimeData()->hasUrls())
|
|
|
|
{
|
|
|
|
foreach(const QUrl &uri, event->mimeData()->urls())
|
|
|
|
{
|
|
|
|
emit receivedURI(uri.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
event->acceptProposedAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
|
|
|
|
{
|
|
|
|
// Catch status tip events
|
|
|
|
if (event->type() == QEvent::StatusTip)
|
|
|
|
{
|
|
|
|
// Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
|
|
|
|
if (progressBarLabel->isVisible() || progressBar->isVisible())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return QMainWindow::eventFilter(object, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
|
|
|
|
{
|
|
|
|
// URI has to be valid
|
|
|
|
if (walletFrame && walletFrame->handlePaymentRequest(recipient))
|
|
|
|
{
|
|
|
|
showNormalIfMinimized();
|
|
|
|
gotoSendCoinsPage();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
|
|
|
|
{
|
|
|
|
if(!clientModel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// activateWindow() (sometimes) helps with keyboard focus on Windows
|
|
|
|
if (isHidden())
|
|
|
|
{
|
|
|
|
show();
|
|
|
|
activateWindow();
|
|
|
|
}
|
|
|
|
else if (isMinimized())
|
|
|
|
{
|
|
|
|
showNormal();
|
|
|
|
activateWindow();
|
|
|
|
}
|
|
|
|
else if (GUIUtil::isObscured(this))
|
|
|
|
{
|
|
|
|
raise();
|
|
|
|
activateWindow();
|
|
|
|
}
|
|
|
|
else if(fToggleHidden)
|
|
|
|
hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::toggleHidden()
|
|
|
|
{
|
|
|
|
showNormalIfMinimized(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::detectShutdown()
|
|
|
|
{
|
|
|
|
if (ShutdownRequested())
|
|
|
|
{
|
|
|
|
if(rpcConsole)
|
|
|
|
rpcConsole->hide();
|
|
|
|
qApp->quit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::showProgress(const QString &title, int nProgress)
|
|
|
|
{
|
|
|
|
if (nProgress == 0)
|
|
|
|
{
|
|
|
|
progressDialog = new QProgressDialog(title, "", 0, 100);
|
|
|
|
progressDialog->setWindowModality(Qt::ApplicationModal);
|
|
|
|
progressDialog->setMinimumDuration(0);
|
|
|
|
progressDialog->setCancelButton(0);
|
|
|
|
progressDialog->setAutoClose(false);
|
|
|
|
progressDialog->setValue(0);
|
|
|
|
}
|
|
|
|
else if (nProgress == 100)
|
|
|
|
{
|
|
|
|
if (progressDialog)
|
|
|
|
{
|
|
|
|
progressDialog->close();
|
|
|
|
progressDialog->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (progressDialog)
|
|
|
|
progressDialog->setValue(nProgress);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
|
|
|
|
{
|
|
|
|
bool modal = (style & CClientUIInterface::MODAL);
|
|
|
|
bool ret = false;
|
|
|
|
// In case of modal message, use blocking connection to wait for user to click a button
|
|
|
|
QMetaObject::invokeMethod(gui, "message",
|
|
|
|
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
|
|
|
|
Q_ARG(QString, QString::fromStdString(caption)),
|
|
|
|
Q_ARG(QString, QString::fromStdString(message)),
|
|
|
|
Q_ARG(unsigned int, style),
|
|
|
|
Q_ARG(bool*, &ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::subscribeToCoreSignals()
|
|
|
|
{
|
|
|
|
// Connect signals to client
|
|
|
|
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitcoinGUI::unsubscribeFromCoreSignals()
|
|
|
|
{
|
|
|
|
// Disconnect signals from client
|
|
|
|
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
|
|
|
|
}
|
|
|
|
|
|
|
|
UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
|
|
|
|
optionsModel(0),
|
|
|
|
menu(0)
|
|
|
|
{
|
|
|
|
createContextMenu();
|
|
|
|
setToolTip(tr("Unit to show amounts in. Click to select another unit."));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** So that it responds to button clicks */
|
|
|
|
void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
onDisplayUnitsClicked(event->pos());
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
|
|
|
|
void UnitDisplayStatusBarControl::createContextMenu()
|
|
|
|
{
|
|
|
|
menu = new QMenu();
|
|
|
|
foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
|
|
|
|
{
|
|
|
|
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
|
|
|
|
menuAction->setData(QVariant(u));
|
|
|
|
menu->addAction(menuAction);
|
|
|
|
}
|
|
|
|
connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Lets the control know about the Options Model (and its signals) */
|
|
|
|
void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
|
|
|
|
{
|
|
|
|
if (optionsModel)
|
|
|
|
{
|
|
|
|
this->optionsModel = optionsModel;
|
|
|
|
|
|
|
|
// be aware of a display unit change reported by the OptionsModel object.
|
|
|
|
connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
|
|
|
|
|
|
|
|
// initialize the display units label with the current value in the model.
|
|
|
|
updateDisplayUnit(optionsModel->getDisplayUnit());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
|
|
|
|
void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
|
|
|
|
{
|
|
|
|
setPixmap(QIcon(":/icons/unit_" + BitcoinUnits::id(newUnits)).pixmap(31,STATUSBAR_ICONSIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Shows context menu with Display Unit options by the mouse coordinates */
|
|
|
|
void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint& point)
|
|
|
|
{
|
|
|
|
QPoint globalPos = mapToGlobal(point);
|
|
|
|
menu->exec(globalPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Tells underlying optionsModel to update its current display unit. */
|
|
|
|
void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
|
|
|
|
{
|
|
|
|
if (action)
|
|
|
|
{
|
|
|
|
optionsModel->setDisplayUnit(action->data());
|
|
|
|
}
|
|
|
|
}
|