/*
* Qt4 bitcoin GUI .
*
* W . J . van der Laan 2011 - 2012
* The Bitcoin Developers 2011 - 2012
*/
# include "bitcoingui.h"
# include "transactiontablemodel.h"
# include "addressbookpage.h"
# include "sendcoinsdialog.h"
# include "signverifymessagedialog.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 "guiutil.h"
# include "rpcconsole.h"
# ifdef Q_WS_MAC
# include "macdockiconhandler.h"
# endif
# 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 <QFileDialog>
# include <QDesktopServices>
# include <QTimer>
# include <QDragEnterEvent>
# include <QUrl>
# include <iostream>
BitcoinGUI : : BitcoinGUI ( QWidget * parent ) :
QMainWindow ( parent ) ,
clientModel ( 0 ) ,
walletModel ( 0 ) ,
encryptWalletAction ( 0 ) ,
changePassphraseAction ( 0 ) ,
aboutQtAction ( 0 ) ,
trayIcon ( 0 ) ,
notificator ( 0 ) ,
rpcConsole ( 0 )
{
resize ( 850 , 550 ) ;
setWindowTitle ( tr ( " Bitcoin " ) + " - " + tr ( " Wallet " ) ) ;
# ifndef Q_WS_MAC
qApp - > setWindowIcon ( QIcon ( " :icons/bitcoin " ) ) ;
setWindowIcon ( QIcon ( " :icons/bitcoin " ) ) ;
# else
setUnifiedTitleAndToolBarOnMac ( true ) ;
QApplication : : setAttribute ( Qt : : AA_DontShowIconsInMenus ) ;
# endif
// Accept D&D of URIs
setAcceptDrops ( true ) ;
// Create actions for the toolbar, menu bar and tray/dock icon
createActions ( ) ;
// Create application menu bar
createMenuBar ( ) ;
// Create the toolbars
createToolBars ( ) ;
// Create the tray icon (or setup the dock icon)
createTrayIcon ( ) ;
// 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 ) ;
signVerifyMessageDialog = new SignVerifyMessageDialog ( this ) ;
centralWidget = new QStackedWidget ( this ) ;
centralWidget - > addWidget ( overviewPage ) ;
centralWidget - > addWidget ( transactionsPage ) ;
centralWidget - > addWidget ( addressBookPage ) ;
centralWidget - > addWidget ( receiveCoinsPage ) ;
centralWidget - > addWidget ( sendCoinsPage ) ;
# ifdef FIRST_CLASS_MESSAGING
centralWidget - > addWidget ( signVerifyMessageDialog ) ;
# endif
setCentralWidget ( centralWidget ) ;
// 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 ) ;
statusBar ( ) - > addWidget ( progressBarLabel ) ;
statusBar ( ) - > addWidget ( progressBar ) ;
statusBar ( ) - > addPermanentWidget ( frameBlocks ) ;
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 ( ) ) ) ;
connect ( overviewPage , SIGNAL ( transactionClicked ( QModelIndex ) ) , transactionView , SLOT ( focusTransaction ( QModelIndex ) ) ) ;
// Double-clicking on a transaction on the transaction history page shows details
connect ( transactionView , SIGNAL ( doubleClicked ( QModelIndex ) ) , transactionView , SLOT ( showDetails ( ) ) ) ;
rpcConsole = new RPCConsole ( this ) ;
connect ( openRPCConsoleAction , SIGNAL ( triggered ( ) ) , rpcConsole , SLOT ( show ( ) ) ) ;
// Clicking on "Verify Message" in the address book sends you to the verify message tab
connect ( addressBookPage , SIGNAL ( verifyMessage ( QString ) ) , this , SLOT ( gotoVerifyMessageTab ( QString ) ) ) ;
// Clicking on "Sign Message" in the receive coins page sends you to the sign message tab
connect ( receiveCoinsPage , SIGNAL ( signMessage ( QString ) ) , this , SLOT ( gotoSignMessageTab ( QString ) ) ) ;
gotoOverviewPage ( ) ;
}
BitcoinGUI : : ~ BitcoinGUI ( )
{
if ( trayIcon ) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon - > hide ( ) ;
# ifdef Q_WS_MAC
delete appMenuBar ;
# endif
}
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 ) ;
overviewAction - > setShortcut ( QKeySequence ( Qt : : ALT + Qt : : Key_1 ) ) ;
tabGroup - > addAction ( overviewAction ) ;
historyAction = new QAction ( QIcon ( " :/icons/history " ) , tr ( " &Transactions " ) , this ) ;
historyAction - > setToolTip ( tr ( " Browse transaction history " ) ) ;
historyAction - > setCheckable ( true ) ;
historyAction - > setShortcut ( QKeySequence ( Qt : : ALT + Qt : : Key_4 ) ) ;
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 ) ;
addressBookAction - > setShortcut ( QKeySequence ( Qt : : ALT + Qt : : Key_5 ) ) ;
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 ) ;
receiveCoinsAction - > setShortcut ( QKeySequence ( Qt : : ALT + Qt : : Key_3 ) ) ;
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 ) ;
sendCoinsAction - > setShortcut ( QKeySequence ( Qt : : ALT + Qt : : Key_2 ) ) ;
tabGroup - > addAction ( sendCoinsAction ) ;
signMessageAction = new QAction ( QIcon ( " :/icons/edit " ) , tr ( " Sign &message... " ) , this ) ;
signMessageAction - > setToolTip ( tr ( " Sign a message to prove you own a Bitcoin address " ) ) ;
tabGroup - > addAction ( signMessageAction ) ;
verifyMessageAction = new QAction ( QIcon ( " :/icons/transaction_0 " ) , tr ( " &Verify message... " ) , this ) ;
verifyMessageAction - > setToolTip ( tr ( " Verify a message to ensure it was signed with a specified Bitcoin address " ) ) ;
tabGroup - > addAction ( verifyMessageAction ) ;
# ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction = new QAction ( QIcon ( " :/icons/edit " ) , tr ( " S&ignatures " ) , this ) ;
firstClassMessagingAction - > setToolTip ( signMessageAction - > toolTip ( ) + QString ( " . / " ) + verifyMessageAction - > toolTip ( ) + QString ( " . " ) ) ;
firstClassMessagingAction - > setCheckable ( true ) ;
tabGroup - > addAction ( firstClassMessagingAction ) ;
# endif
connect ( overviewAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( overviewAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoOverviewPage ( ) ) ) ;
connect ( historyAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( historyAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoHistoryPage ( ) ) ) ;
connect ( addressBookAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( addressBookAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoAddressBookPage ( ) ) ) ;
connect ( receiveCoinsAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( receiveCoinsAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoReceiveCoinsPage ( ) ) ) ;
connect ( sendCoinsAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( sendCoinsAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoSendCoinsPage ( ) ) ) ;
connect ( signMessageAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( signMessageAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoSignMessageTab ( ) ) ) ;
connect ( verifyMessageAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
connect ( verifyMessageAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoVerifyMessageTab ( ) ) ) ;
# ifdef FIRST_CLASS_MESSAGING
connect ( firstClassMessagingAction , SIGNAL ( triggered ( ) ) , this , SLOT ( showNormalIfMinimized ( ) ) ) ;
// Always start with the sign message tab for FIRST_CLASS_MESSAGING
connect ( firstClassMessagingAction , SIGNAL ( triggered ( ) ) , this , SLOT ( gotoSignMessageTab ( ) ) ) ;
# endif
quitAction = new QAction ( QIcon ( " :/icons/quit " ) , tr ( " E&xit " ) , this ) ;
quitAction - > setToolTip ( tr ( " Quit application " ) ) ;
quitAction - > setShortcut ( QKeySequence ( Qt : : CTRL + Qt : : Key_Q ) ) ;
quitAction - > setMenuRole ( QAction : : QuitRole ) ;
aboutAction = new QAction ( QIcon ( " :/icons/bitcoin " ) , tr ( " &About Bitcoin " ) , this ) ;
aboutAction - > setToolTip ( tr ( " Show information about Bitcoin " ) ) ;
aboutAction - > setMenuRole ( QAction : : AboutRole ) ;
aboutQtAction = new QAction ( tr ( " About &Qt " ) , this ) ;
aboutQtAction - > setToolTip ( tr ( " Show information about Qt " ) ) ;
aboutQtAction - > setMenuRole ( QAction : : AboutQtRole ) ;
optionsAction = new QAction ( QIcon ( " :/icons/options " ) , tr ( " &Options... " ) , this ) ;
optionsAction - > setToolTip ( tr ( " Modify configuration options for Bitcoin " ) ) ;
optionsAction - > setMenuRole ( QAction : : PreferencesRole ) ;
toggleHideAction = new QAction ( QIcon ( " :/icons/bitcoin " ) , tr ( " Show/Hide &Bitcoin " ) , this ) ;
toggleHideAction - > setToolTip ( tr ( " Show or hide the Bitcoin window " ) ) ;
exportAction = new QAction ( QIcon ( " :/icons/export " ) , tr ( " &Export... " ) , this ) ;
exportAction - > setToolTip ( tr ( " Export the data in the current tab to a file " ) ) ;
encryptWalletAction = new QAction ( QIcon ( " :/icons/lock_closed " ) , tr ( " &Encrypt Wallet... " ) , this ) ;
encryptWalletAction - > setToolTip ( tr ( " Encrypt or decrypt wallet " ) ) ;
encryptWalletAction - > setCheckable ( true ) ;
backupWalletAction = new QAction ( QIcon ( " :/icons/filesave " ) , tr ( " &Backup Wallet... " ) , this ) ;
backupWalletAction - > setToolTip ( tr ( " Backup wallet to another location " ) ) ;
changePassphraseAction = new QAction ( QIcon ( " :/icons/key " ) , tr ( " &Change Passphrase... " ) , this ) ;
changePassphraseAction - > setToolTip ( tr ( " Change the passphrase used for wallet encryption " ) ) ;
openRPCConsoleAction = new QAction ( QIcon ( " :/icons/debugwindow " ) , tr ( " &Debug window " ) , this ) ;
openRPCConsoleAction - > setToolTip ( tr ( " Open debugging and diagnostic console " ) ) ;
connect ( quitAction , SIGNAL ( triggered ( ) ) , qApp , SLOT ( quit ( ) ) ) ;
connect ( optionsAction , SIGNAL ( triggered ( ) ) , this , SLOT ( optionsClicked ( ) ) ) ;
connect ( aboutAction , SIGNAL ( triggered ( ) ) , this , SLOT ( aboutClicked ( ) ) ) ;
connect ( aboutQtAction , SIGNAL ( triggered ( ) ) , qApp , SLOT ( aboutQt ( ) ) ) ;
connect ( toggleHideAction , SIGNAL ( triggered ( ) ) , this , SLOT ( toggleHidden ( ) ) ) ;
connect ( encryptWalletAction , SIGNAL ( triggered ( bool ) ) , this , SLOT ( encryptWallet ( bool ) ) ) ;
connect ( backupWalletAction , SIGNAL ( triggered ( ) ) , this , SLOT ( backupWallet ( ) ) ) ;
connect ( changePassphraseAction , SIGNAL ( triggered ( ) ) , this , SLOT ( changePassphrase ( ) ) ) ;
}
void BitcoinGUI : : createMenuBar ( )
{
# ifdef Q_WS_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 ( backupWalletAction ) ;
file - > addAction ( exportAction ) ;
# ifndef FIRST_CLASS_MESSAGING
file - > addAction ( signMessageAction ) ;
file - > addAction ( verifyMessageAction ) ;
# endif
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 ) ;
toolbar - > addAction ( addressBookAction ) ;
# ifdef FIRST_CLASS_MESSAGING
toolbar - > addAction ( firstClassMessagingAction ) ;
# endif
QToolBar * toolbar2 = addToolBar ( tr ( " Actions toolbar " ) ) ;
toolbar2 - > setToolButtonStyle ( Qt : : ToolButtonTextBesideIcon ) ;
toolbar2 - > addAction ( exportAction ) ;
}
void BitcoinGUI : : setClientModel ( ClientModel * clientModel )
{
this - > clientModel = clientModel ;
if ( clientModel )
{
// Replace some strings and icons, when using the testnet
if ( clientModel - > isTestNet ( ) )
{
setWindowTitle ( windowTitle ( ) + QString ( " " ) + tr ( " [testnet] " ) ) ;
# ifndef Q_WS_MAC
qApp - > setWindowIcon ( QIcon ( " :icons/bitcoin_testnet " ) ) ;
setWindowIcon ( QIcon ( " :icons/bitcoin_testnet " ) ) ;
# else
MacDockIconHandler : : instance ( ) - > setIcon ( QIcon ( " :icons/bitcoin_testnet " ) ) ;
# endif
if ( trayIcon )
{
trayIcon - > setToolTip ( tr ( " Bitcoin client " ) + QString ( " " ) + tr ( " [testnet] " ) ) ;
trayIcon - > setIcon ( QIcon ( " :/icons/toolbar_testnet " ) ) ;
toggleHideAction - > setIcon ( QIcon ( " :/icons/toolbar_testnet " ) ) ;
}
aboutAction - > 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 ( ) , clientModel - > getNumBlocksOfPeers ( ) ) ;
connect ( clientModel , SIGNAL ( numBlocksChanged ( int , int ) ) , this , SLOT ( setNumBlocks ( int , int ) ) ) ;
// Report errors from network/worker thread
connect ( clientModel , SIGNAL ( error ( QString , QString , bool ) ) , this , SLOT ( error ( QString , QString , bool ) ) ) ;
rpcConsole - > setClientModel ( clientModel ) ;
addressBookPage - > setOptionsModel ( clientModel - > getOptionsModel ( ) ) ;
receiveCoinsPage - > setOptionsModel ( clientModel - > getOptionsModel ( ) ) ;
}
}
void BitcoinGUI : : setWalletModel ( WalletModel * walletModel )
{
this - > walletModel = walletModel ;
if ( walletModel )
{
// Report errors from wallet thread
connect ( walletModel , SIGNAL ( error ( QString , QString , bool ) ) , this , SLOT ( error ( QString , QString , bool ) ) ) ;
// Put transaction list in tabs
transactionView - > setModel ( walletModel ) ;
overviewPage - > setModel ( walletModel ) ;
addressBookPage - > setModel ( walletModel - > getAddressTableModel ( ) ) ;
receiveCoinsPage - > setModel ( walletModel - > getAddressTableModel ( ) ) ;
sendCoinsPage - > setModel ( walletModel ) ;
signVerifyMessageDialog - > setModel ( walletModel ) ;
setEncryptionStatus ( walletModel - > getEncryptionStatus ( ) ) ;
connect ( walletModel , SIGNAL ( encryptionStatusChanged ( int ) ) , this , SLOT ( setEncryptionStatus ( int ) ) ) ;
// Balloon pop-up 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 ;
# ifndef Q_WS_MAC
trayIcon = new QSystemTrayIcon ( this ) ;
trayIconMenu = new QMenu ( this ) ;
trayIcon - > setContextMenu ( trayIconMenu ) ;
trayIcon - > setToolTip ( tr ( " Bitcoin client " ) ) ;
trayIcon - > setIcon ( QIcon ( " :/icons/toolbar " ) ) ;
connect ( trayIcon , SIGNAL ( activated ( QSystemTrayIcon : : ActivationReason ) ) ,
this , SLOT ( trayIconActivated ( QSystemTrayIcon : : ActivationReason ) ) ) ;
trayIcon - > show ( ) ;
# else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler * dockIconHandler = MacDockIconHandler : : instance ( ) ;
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 ) ;
# ifndef FIRST_CLASS_MESSAGING
trayIconMenu - > addSeparator ( ) ;
# endif
trayIconMenu - > addAction ( signMessageAction ) ;
trayIconMenu - > addAction ( verifyMessageAction ) ;
trayIconMenu - > addSeparator ( ) ;
trayIconMenu - > addAction ( optionsAction ) ;
trayIconMenu - > addAction ( openRPCConsoleAction ) ;
# ifndef Q_WS_MAC // This is built-in on Mac
trayIconMenu - > addSeparator ( ) ;
trayIconMenu - > addAction ( quitAction ) ;
# endif
notificator = new Notificator ( qApp - > applicationName ( ) , trayIcon ) ;
}
# ifndef Q_WS_MAC
void BitcoinGUI : : trayIconActivated ( QSystemTrayIcon : : ActivationReason reason )
{
if ( reason = = QSystemTrayIcon : : Trigger )
{
// Click on system tray icon triggers "show/hide Bitcoin"
toggleHideAction - > trigger ( ) ;
}
}
# endif
void BitcoinGUI : : optionsClicked ( )
{
if ( ! clientModel | | ! clientModel - > getOptionsModel ( ) )
return ;
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 nTotalBlocks )
{
// don't show / hide progressBar and its label if we have no connection(s) to the network
if ( ! clientModel | | clientModel - > getNumConnections ( ) = = 0 )
{
progressBarLabel - > setVisible ( false ) ;
progressBar - > setVisible ( false ) ;
return ;
}
QString strStatusBarWarnings = clientModel - > getStatusBarWarnings ( ) ;
QString tooltip ;
if ( count < nTotalBlocks )
{
int nRemainingBlocks = nTotalBlocks - count ;
float nPercentageDone = count / ( nTotalBlocks * 0.01f ) ;
if ( strStatusBarWarnings . isEmpty ( ) )
{
progressBarLabel - > setText ( tr ( " Synchronizing with network... " ) ) ;
progressBarLabel - > setVisible ( true ) ;
progressBar - > setFormat ( tr ( " ~%n block(s) remaining " , " " , nRemainingBlocks ) ) ;
progressBar - > setMaximum ( nTotalBlocks ) ;
progressBar - > setValue ( count ) ;
progressBar - > setVisible ( true ) ;
}
tooltip = tr ( " Downloaded %1 of %2 blocks of transaction history (%3% done). " ) . arg ( count ) . arg ( nTotalBlocks ) . arg ( nPercentageDone , 0 , ' f ' , 2 ) ;
}
else
{
if ( strStatusBarWarnings . isEmpty ( ) )
progressBarLabel - > setVisible ( false ) ;
progressBar - > setVisible ( false ) ;
tooltip = tr ( " Downloaded %1 blocks of transaction history. " ) . arg ( count ) ;
}
// Override progressBarLabel text and hide progressBar, when we have warnings to display
if ( ! strStatusBarWarnings . isEmpty ( ) )
{
progressBarLabel - > setText ( strStatusBarWarnings ) ;
progressBarLabel - > setVisible ( true ) ;
progressBar - > setVisible ( false ) ;
}
QDateTime lastBlockDate = clientModel - > getLastBlockDate ( ) ;
int secs = lastBlockDate . secsTo ( QDateTime : : currentDateTime ( ) ) ;
QString text ;
// Represent time from last generated block in human readable text
if ( secs < = 0 )
{
// Fully up to date. Leave text empty.
}
else 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 < 90 * 60 & & count > = nTotalBlocks )
{
tooltip = tr ( " Up to date " ) + QString ( " .<br> " ) + tooltip ;
labelBlocksIcon - > setPixmap ( QIcon ( " :/icons/synced " ) . pixmap ( STATUSBAR_ICONSIZE , STATUSBAR_ICONSIZE ) ) ;
overviewPage - > showOutOfSyncWarning ( false ) ;
}
else
{
tooltip = tr ( " Catching up... " ) + QString ( " <br> " ) + tooltip ;
labelBlocksIcon - > setMovie ( syncIconMovie ) ;
syncIconMovie - > start ( ) ;
overviewPage - > showOutOfSyncWarning ( true ) ;
}
if ( ! text . isEmpty ( ) )
{
tooltip + = QString ( " <br> " ) ;
tooltip + = tr ( " Last received block was generated %1. " ) . arg ( text ) ;
}
// 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 : : error ( const QString & title , const QString & message , bool modal )
{
// Report errors from network/worker thread
if ( modal )
{
QMessageBox : : critical ( this , title , message , QMessageBox : : Ok , QMessageBox : : Ok ) ;
} else {
notificator - > notify ( Notificator : : Critical , title , message ) ;
}
}
void BitcoinGUI : : changeEvent ( QEvent * e )
{
QMainWindow : : changeEvent ( e ) ;
# ifndef Q_WS_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_WS_MAC // Ignored on Mac
if ( ! clientModel - > getOptionsModel ( ) - > getMinimizeToTray ( ) & &
! clientModel - > getOptionsModel ( ) - > getMinimizeOnClose ( ) )
{
qApp - > quit ( ) ;
}
# endif
}
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 ( " Confirm transaction fee " ) , strMessage ,
QMessageBox : : Yes | QMessageBox : : Cancel , QMessageBox : : Yes ) ;
* payFee = ( retval = = QMessageBox : : Yes ) ;
}
void BitcoinGUI : : incomingTransaction ( const QModelIndex & parent , int start , int end )
{
if ( ! walletModel | | ! clientModel )
return ;
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 ) ;
centralWidget - > setCurrentWidget ( sendCoinsPage ) ;
exportAction - > setEnabled ( false ) ;
disconnect ( exportAction , SIGNAL ( triggered ( ) ) , 0 , 0 ) ;
}
void BitcoinGUI : : gotoSignMessageTab ( QString addr )
{
# ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction - > setChecked ( true ) ;
centralWidget - > setCurrentWidget ( signVerifyMessageDialog ) ;
exportAction - > setEnabled ( false ) ;
disconnect ( exportAction , SIGNAL ( triggered ( ) ) , 0 , 0 ) ;
signVerifyMessageDialog - > showTab_SM ( false ) ;
# else
// call show() in showTab_SM()
signVerifyMessageDialog - > showTab_SM ( true ) ;
# endif
if ( ! addr . isEmpty ( ) )
signVerifyMessageDialog - > setAddress_SM ( addr ) ;
}
void BitcoinGUI : : gotoVerifyMessageTab ( QString addr )
{
# ifdef FIRST_CLASS_MESSAGING
firstClassMessagingAction - > setChecked ( true ) ;
centralWidget - > setCurrentWidget ( signVerifyMessageDialog ) ;
exportAction - > setEnabled ( false ) ;
disconnect ( exportAction , SIGNAL ( triggered ( ) ) , 0 , 0 ) ;
signVerifyMessageDialog - > showTab_VM ( false ) ;
# else
// call show() in showTab_VM()
signVerifyMessageDialog - > showTab_VM ( true ) ;
# endif
if ( ! addr . isEmpty ( ) )
signVerifyMessageDialog - > setAddress_VM ( addr ) ;
}
void BitcoinGUI : : dragEnterEvent ( QDragEnterEvent * event )
{
// Accept only URIs
if ( event - > mimeData ( ) - > hasUrls ( ) )
event - > acceptProposedAction ( ) ;
}
void BitcoinGUI : : dropEvent ( QDropEvent * event )
{
if ( event - > mimeData ( ) - > hasUrls ( ) )
{
int nValidUrisFound = 0 ;
QList < QUrl > uris = event - > mimeData ( ) - > urls ( ) ;
foreach ( const QUrl & uri , uris )
{
if ( sendCoinsPage - > handleURI ( uri . toString ( ) ) )
nValidUrisFound + + ;
}
// if valid URIs were found
if ( nValidUrisFound )
gotoSendCoinsPage ( ) ;
else
notificator - > notify ( Notificator : : Warning , tr ( " URI handling " ) , tr ( " URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. " ) ) ;
}
event - > acceptProposedAction ( ) ;
}
void BitcoinGUI : : handleURI ( QString strURI )
{
// URI has to be valid
if ( sendCoinsPage - > handleURI ( strURI ) )
{
showNormalIfMinimized ( ) ;
gotoSendCoinsPage ( ) ;
}
else
notificator - > notify ( Notificator : : Warning , tr ( " URI handling " ) , tr ( " URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. " ) ) ;
}
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 )
{
if ( ! walletModel )
return ;
AskPassphraseDialog dlg ( status ? AskPassphraseDialog : : Encrypt :
AskPassphraseDialog : : Decrypt , this ) ;
dlg . setModel ( walletModel ) ;
dlg . exec ( ) ;
setEncryptionStatus ( walletModel - > getEncryptionStatus ( ) ) ;
}
void BitcoinGUI : : backupWallet ( )
{
QString saveDir = QDesktopServices : : storageLocation ( QDesktopServices : : DocumentsLocation ) ;
QString filename = QFileDialog : : getSaveFileName ( this , tr ( " Backup Wallet " ) , saveDir , tr ( " Wallet Data (*.dat) " ) ) ;
if ( ! filename . isEmpty ( ) ) {
if ( ! walletModel - > backupWallet ( filename ) ) {
QMessageBox : : warning ( this , tr ( " Backup Failed " ) , tr ( " There was an error trying to save the wallet data to the new location. " ) ) ;
}
}
}
void BitcoinGUI : : changePassphrase ( )
{
AskPassphraseDialog dlg ( AskPassphraseDialog : : ChangePass , this ) ;
dlg . setModel ( walletModel ) ;
dlg . exec ( ) ;
}
void BitcoinGUI : : unlockWallet ( )
{
if ( ! walletModel )
return ;
// Unlock wallet when requested by wallet model
if ( walletModel - > getEncryptionStatus ( ) = = WalletModel : : Locked )
{
AskPassphraseDialog dlg ( AskPassphraseDialog : : Unlock , this ) ;
dlg . setModel ( walletModel ) ;
dlg . exec ( ) ;
}
}
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 ) ;
}