9a2305a1b3
Stop the shutdown timer from exiting the main loop when shutdown is already in progress. Fixes seeming hanging window after typing 'stop' in debug console. Also hide the debug console during shutdown as it is useless without a core to connect to.
889 lines
31 KiB
C++
889 lines
31 KiB
C++
// Copyright (c) 2011-2013 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 "aboutdialog.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 "walletframe.h"
|
|
#include "walletmodel.h"
|
|
|
|
#ifdef Q_OS_MAC
|
|
#include "macdockiconhandler.h"
|
|
#endif
|
|
|
|
#include "init.h"
|
|
#include "ui_interface.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include <QApplication>
|
|
#include <QDateTime>
|
|
#include <QDesktopWidget>
|
|
#include <QDragEnterEvent>
|
|
#include <QIcon>
|
|
#include <QLabel>
|
|
#include <QListWidget>
|
|
#include <QMenu>
|
|
#include <QMenuBar>
|
|
#include <QMessageBox>
|
|
#include <QMimeData>
|
|
#include <QMovie>
|
|
#include <QProgressBar>
|
|
#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),
|
|
encryptWalletAction(0),
|
|
changePassphraseAction(0),
|
|
aboutQtAction(0),
|
|
trayIcon(0),
|
|
notificator(0),
|
|
rpcConsole(0),
|
|
prevBlocks(0)
|
|
{
|
|
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
|
|
|
|
if (!fIsTestnet)
|
|
{
|
|
setWindowTitle(tr("Bitcoin Core") + " - " + tr("Wallet"));
|
|
#ifndef Q_OS_MAC
|
|
QApplication::setWindowIcon(QIcon(":icons/bitcoin"));
|
|
setWindowIcon(QIcon(":icons/bitcoin"));
|
|
#else
|
|
MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
setWindowTitle(tr("Bitcoin Core") + " - " + tr("Wallet") + " " + 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
|
|
}
|
|
|
|
#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
|
|
|
|
// Create wallet frame and make it the central widget
|
|
walletFrame = new WalletFrame(this);
|
|
setCentralWidget(walletFrame);
|
|
|
|
// 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->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 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);
|
|
|
|
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this);
|
|
|
|
rpcConsole = new RPCConsole(this);
|
|
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
|
|
// prevents an oben 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"));
|
|
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("&Used sending addresses..."), this);
|
|
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
|
|
usedReceivingAddressesAction = new QAction(QIcon(":/icons/address-book"), tr("Used &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"));
|
|
|
|
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(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()));
|
|
}
|
|
|
|
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"));
|
|
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"));
|
|
settings->addAction(encryptWalletAction);
|
|
settings->addAction(changePassphraseAction);
|
|
settings->addSeparator();
|
|
settings->addAction(optionsAction);
|
|
|
|
QMenu *help = appMenuBar->addMenu(tr("&Help"));
|
|
help->addAction(openRPCConsoleAction);
|
|
help->addSeparator();
|
|
help->addAction(aboutAction);
|
|
help->addAction(aboutQtAction);
|
|
}
|
|
|
|
void BitcoinGUI::createToolBars()
|
|
{
|
|
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(), clientModel->getNumBlocksOfPeers());
|
|
connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
|
|
|
|
// Receive and report messages from client model
|
|
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
|
|
|
|
rpcConsole->setClientModel(clientModel);
|
|
walletFrame->setClientModel(clientModel);
|
|
}
|
|
}
|
|
|
|
bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel)
|
|
{
|
|
setWalletActionsEnabled(true);
|
|
return walletFrame->addWallet(name, walletModel);
|
|
}
|
|
|
|
bool BitcoinGUI::setCurrentWallet(const QString& name)
|
|
{
|
|
return walletFrame->setCurrentWallet(name);
|
|
}
|
|
|
|
void BitcoinGUI::removeAllWallets()
|
|
{
|
|
setWalletActionsEnabled(false);
|
|
walletFrame->removeAllWallets();
|
|
}
|
|
|
|
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 client"));
|
|
trayIcon->setIcon(QIcon(":/icons/toolbar"));
|
|
}
|
|
else
|
|
{
|
|
trayIcon->setToolTip(tr("Bitcoin client") + " " + tr("[testnet]"));
|
|
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
|
|
}
|
|
|
|
trayIcon->show();
|
|
#endif
|
|
|
|
notificator = new Notificator(QApplication::applicationName(), trayIcon, this);
|
|
}
|
|
|
|
void BitcoinGUI::createTrayIconMenu()
|
|
{
|
|
QMenu *trayIconMenu;
|
|
#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
|
|
toggleHideAction->trigger();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void BitcoinGUI::optionsClicked()
|
|
{
|
|
if(!clientModel || !clientModel->getOptionsModel())
|
|
return;
|
|
|
|
OptionsDialog dlg(this);
|
|
dlg.setModel(clientModel->getOptionsModel());
|
|
dlg.exec();
|
|
}
|
|
|
|
void BitcoinGUI::aboutClicked()
|
|
{
|
|
if(!clientModel)
|
|
return;
|
|
|
|
AboutDialog dlg(this);
|
|
dlg.setModel(clientModel);
|
|
dlg.exec();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 nTotalBlocks)
|
|
{
|
|
// 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);
|
|
|
|
if(count < nTotalBlocks)
|
|
{
|
|
tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks);
|
|
}
|
|
else
|
|
{
|
|
tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
|
|
}
|
|
|
|
// Set icon state: spinning if catching up, tick otherwise
|
|
if(secs < 90*60 && count >= nTotalBlocks)
|
|
{
|
|
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
|
|
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
|
|
|
|
walletFrame->showOutOfSyncWarning(false);
|
|
|
|
progressBarLabel->setVisible(false);
|
|
progressBar->setVisible(false);
|
|
}
|
|
else
|
|
{
|
|
// Represent time from last generated block in human readable text
|
|
QString timeBehindText;
|
|
if(secs < 48*60*60)
|
|
{
|
|
timeBehindText = tr("%n hour(s)","",secs/(60*60));
|
|
}
|
|
else if(secs < 14*24*60*60)
|
|
{
|
|
timeBehindText = tr("%n day(s)","",secs/(24*60*60));
|
|
}
|
|
else
|
|
{
|
|
timeBehindText = tr("%n week(s)","",secs/(7*24*60*60));
|
|
}
|
|
|
|
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;
|
|
labelBlocksIcon->setMovie(syncIconMovie);
|
|
if(count != prevBlocks)
|
|
syncIconMovie->jumpToNextFrame();
|
|
prevBlocks = count;
|
|
|
|
walletFrame->showOutOfSyncWarning(true);
|
|
|
|
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;
|
|
|
|
// Ensure we get users attention, but only if main window is visible
|
|
// as we don't want to pop up the main window for messages that happen before
|
|
// initialization is finished.
|
|
if(!(style & CClientUIInterface::NOSHOWGUI))
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
|
|
{
|
|
// URI has to be valid
|
|
if (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;
|
|
}
|
|
}
|
|
|
|
void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
|
|
{
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|