Browse Source

Minimal architectural changes necessary to support multiple wallets in bitcoin-qt

- This commit is a minimal restructuring necessary to support multiple wallets in the UI. Please see multiwallet-qt.txt for details.
0.8
Eric Lombrozo 12 years ago
parent
commit
67155d9299
  1. 6
      bitcoin-qt.pro
  2. 53
      multiwallet-qt.txt
  3. 5
      src/qt/bitcoin.cpp
  4. 268
      src/qt/bitcoingui.cpp
  5. 38
      src/qt/bitcoingui.h
  6. 129
      src/qt/walletframe.cpp
  7. 73
      src/qt/walletframe.h
  8. 155
      src/qt/walletstack.cpp
  9. 102
      src/qt/walletstack.h
  10. 354
      src/qt/walletview.cpp
  11. 132
      src/qt/walletview.h

6
bitcoin-qt.pro

@ -186,6 +186,9 @@ HEADERS += src/qt/bitcoingui.h \
src/qt/transactionfilterproxy.h \ src/qt/transactionfilterproxy.h \
src/qt/transactionview.h \ src/qt/transactionview.h \
src/qt/walletmodel.h \ src/qt/walletmodel.h \
src/qt/walletview.h \
src/qt/walletstack.h \
src/qt/walletframe.h \
src/bitcoinrpc.h \ src/bitcoinrpc.h \
src/qt/overviewpage.h \ src/qt/overviewpage.h \
src/qt/csvmodelwriter.h \ src/qt/csvmodelwriter.h \
@ -250,6 +253,9 @@ SOURCES += src/qt/bitcoin.cpp \
src/qt/transactionfilterproxy.cpp \ src/qt/transactionfilterproxy.cpp \
src/qt/transactionview.cpp \ src/qt/transactionview.cpp \
src/qt/walletmodel.cpp \ src/qt/walletmodel.cpp \
src/qt/walletview.cpp \
src/qt/walletstack.cpp \
src/qt/walletframe.cpp \
src/bitcoinrpc.cpp \ src/bitcoinrpc.cpp \
src/rpcdump.cpp \ src/rpcdump.cpp \
src/rpcnet.cpp \ src/rpcnet.cpp \

53
multiwallet-qt.txt

@ -0,0 +1,53 @@
Multiwallet Qt Development and Integration Strategy
===================================================
In order to support loading of multiple wallets in bitcoin-qt, a few changes in the UI architecture will be needed.
Fortunately, only four of the files in the existing project are affected by this change.
Three new classes have been implemented in three new .h/.cpp file pairs, with much of the functionality that was previously
implemented in the BitcoinGUI class moved over to these new classes.
The two existing files most affected, by far, are bitcoingui.h and bitcoingui.cpp, as the BitcoinGUI class will require
some major retrofitting.
Only requiring some minor changes is bitcoin.cpp.
Finally, three new headers and source files will have to be added to bitcoin-qt.pro.
Changes to class BitcoinGUI
---------------------------
The principal change to the BitcoinGUI class concerns the QStackedWidget instance called centralWidget.
This widget owns five page views: overviewPage, transactionsPage, addressBookPage, receiveCoinsPage, and sendCoinsPage.
A new class called *WalletView* inheriting from QStackedWidget has been written to handle all renderings and updates of
these page views. In addition to owning these five page views, a WalletView also has a pointer to a WalletModel instance.
This allows the construction of multiple WalletView objects, each rendering a distinct wallet.
A second class called *WalletStack*, also inheriting from QStackedWidget, has been written to handle switching focus between
different loaded wallets. In its current implementation, as a QStackedWidget, only one wallet can be viewed at a time -
but this can be changed later.
A third class called *WalletFrame* inheriting from QFrame has been written as a container for embedding all wallet-related
controls into BitcoinGUI. At present it just contains a WalletStack instance and does little more than passing on messages
from BitcoinGUI to the WalletStack, which in turn passes them to the individual WalletViews. It is a WalletFrame instance
that takes the place of what used to be centralWidget in BitcoinGUI. The purpose of this class is to allow future
refinements of the wallet controls with minimal need for further modifications to BitcoinGUI, thus greatly simplifying
merges while reducing the risk of breaking top-level stuff.
Changes to bitcoin.cpp
----------------------
bitcoin.cpp is the entry point into bitcoin-qt, and as such, will require some minor modifications to provide hooks for
multiple wallet support. Most importantly will be the way it instantiates WalletModels and passes them to the
singleton BitcoinGUI instance called window. Formerly, BitcoinGUI kept a pointer to a single instance of a WalletModel.
The initial change required is very simple: rather than calling window.setWalletModel(&walletModel); we perform the
following two steps:
window.addWallet("~Default", &walletModel);
window.setCurrentWallet("~Default");
The string parameter is just an arbitrary name given to the default wallet. It's been prepended with a tilde to avoid name
collisions in the future with additional wallets.
The shutdown call window.setWalletModel(0) has also been removed. In its place is now:
window.removeAllWallets();

5
src/qt/bitcoin.cpp

@ -232,7 +232,8 @@ int main(int argc, char *argv[])
WalletModel walletModel(pwalletMain, &optionsModel); WalletModel walletModel(pwalletMain, &optionsModel);
window.setClientModel(&clientModel); window.setClientModel(&clientModel);
window.setWalletModel(&walletModel); window.addWallet("~Default", &walletModel);
window.setCurrentWallet("~Default");
// If -min option passed, start window minimized. // If -min option passed, start window minimized.
if(GetBoolArg("-min")) if(GetBoolArg("-min"))
@ -253,7 +254,7 @@ int main(int argc, char *argv[])
window.hide(); window.hide();
window.setClientModel(0); window.setClientModel(0);
window.setWalletModel(0); window.removeAllWallets();
guiref = 0; guiref = 0;
} }
// Shutdown the core and its threads, but don't exit Bitcoin-Qt here // Shutdown the core and its threads, but don't exit Bitcoin-Qt here

268
src/qt/bitcoingui.cpp

@ -10,26 +10,20 @@
#include "bitcoingui.h" #include "bitcoingui.h"
#include "transactiontablemodel.h" #include "transactiontablemodel.h"
#include "addressbookpage.h"
#include "sendcoinsdialog.h"
#include "signverifymessagedialog.h"
#include "optionsdialog.h" #include "optionsdialog.h"
#include "aboutdialog.h" #include "aboutdialog.h"
#include "clientmodel.h" #include "clientmodel.h"
#include "walletmodel.h" #include "walletmodel.h"
#include "editaddressdialog.h" #include "walletframe.h"
#include "optionsmodel.h" #include "optionsmodel.h"
#include "transactiondescdialog.h" #include "transactiondescdialog.h"
#include "addresstablemodel.h"
#include "transactionview.h"
#include "overviewpage.h"
#include "bitcoinunits.h" #include "bitcoinunits.h"
#include "guiconstants.h" #include "guiconstants.h"
#include "askpassphrasedialog.h"
#include "notificator.h" #include "notificator.h"
#include "guiutil.h" #include "guiutil.h"
#include "rpcconsole.h" #include "rpcconsole.h"
#include "ui_interface.h" #include "ui_interface.h"
#include "wallet.h"
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
#include "macdockiconhandler.h" #include "macdockiconhandler.h"
@ -54,13 +48,15 @@
#include <QUrl> #include <QUrl>
#include <QMimeData> #include <QMimeData>
#include <QStyle> #include <QStyle>
#include <QListWidget>
#include <iostream> #include <iostream>
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
BitcoinGUI::BitcoinGUI(QWidget *parent): BitcoinGUI::BitcoinGUI(QWidget *parent):
QMainWindow(parent), QMainWindow(parent),
clientModel(0), clientModel(0),
walletModel(0),
encryptWalletAction(0), encryptWalletAction(0),
changePassphraseAction(0), changePassphraseAction(0),
aboutQtAction(0), aboutQtAction(0),
@ -93,30 +89,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Create system tray icon and notification // Create system tray icon and notification
createTrayIcon(); createTrayIcon();
// Create tabs // Create wallet frame and make it the central widget
overviewPage = new OverviewPage(); walletFrame = new WalletFrame(this);
setCentralWidget(walletFrame);
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);
setCentralWidget(centralWidget);
// Create status bar // Create status bar
statusBar(); statusBar();
@ -162,27 +137,11 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
syncIconMovie = new QMovie(":/movies/update_spinner", "mng", this); 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); rpcConsole = new RPCConsole(this);
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show())); connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
// Clicking on "Send Coins" in the address book sends you to the send coins tab
connect(addressBookPage, SIGNAL(sendCoins(QString)), this, SLOT(gotoSendCoinsPage(QString)));
// Clicking on "Verify Message" in the address book opens the verify message tab in the Sign/Verify Message dialog
connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString)));
// Clicking on "Sign Message" in the receive coins page opens the sign message tab in the Sign/Verify Message dialog
connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
// Install event filter to be able to catch status tip events (QEvent::StatusTip) // Install event filter to be able to catch status tip events (QEvent::StatusTip)
this->installEventFilter(this); this->installEventFilter(this);
gotoOverviewPage();
} }
BitcoinGUI::~BitcoinGUI() BitcoinGUI::~BitcoinGUI()
@ -377,39 +336,23 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// Receive and report messages from network/worker thread // Receive and report messages from network/worker thread
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
overviewPage->setClientModel(clientModel); walletFrame->setClientModel(clientModel);
rpcConsole->setClientModel(clientModel);
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
} }
} }
void BitcoinGUI::setWalletModel(WalletModel *walletModel) bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel)
{
this->walletModel = walletModel;
if(walletModel)
{ {
// Receive and report messages from wallet thread return walletFrame->addWallet(name, walletModel);
connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); }
// Put transaction list in tabs
transactionView->setModel(walletModel);
overviewPage->setWalletModel(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 bool BitcoinGUI::setCurrentWallet(const QString& name)
connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); {
return walletFrame->setCurrentWallet(name);
} }
void BitcoinGUI::removeAllWallets()
{
walletFrame->removeAllWallets();
} }
void BitcoinGUI::createTrayIcon() void BitcoinGUI::createTrayIcon()
@ -484,6 +427,41 @@ void BitcoinGUI::aboutClicked()
dlg.exec(); dlg.exec();
} }
void BitcoinGUI::gotoOverviewPage()
{
if (walletFrame) walletFrame->gotoOverviewPage();
}
void BitcoinGUI::gotoHistoryPage()
{
if (walletFrame) walletFrame->gotoHistoryPage();
}
void BitcoinGUI::gotoAddressBookPage()
{
if (walletFrame) walletFrame->gotoAddressBookPage();
}
void BitcoinGUI::gotoReceiveCoinsPage()
{
if (walletFrame) walletFrame->gotoReceiveCoinsPage();
}
void BitcoinGUI::gotoSendCoinsPage()
{
if (walletFrame) walletFrame->gotoSendCoinsPage();
}
void BitcoinGUI::gotoSignMessageTab(QString addr)
{
if (walletFrame) walletFrame->gotoSignMessageTab(addr);
}
void BitcoinGUI::gotoVerifyMessageTab(QString addr)
{
if (walletFrame) walletFrame->gotoSignMessageTab(addr);
}
void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumConnections(int count)
{ {
QString icon; QString icon;
@ -548,7 +526,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
tooltip = tr("Up to date") + QString(".<br>") + tooltip; tooltip = tr("Up to date") + QString(".<br>") + tooltip;
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
overviewPage->showOutOfSyncWarning(false); walletFrame->showOutOfSyncWarning(false);
progressBarLabel->setVisible(false); progressBarLabel->setVisible(false);
progressBar->setVisible(false); progressBar->setVisible(false);
@ -583,7 +561,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
syncIconMovie->jumpToNextFrame(); syncIconMovie->jumpToNextFrame();
prevBlocks = count; prevBlocks = count;
overviewPage->showOutOfSyncWarning(true); walletFrame->showOutOfSyncWarning(true);
tooltip += QString("<br>"); tooltip += QString("<br>");
tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText); tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
@ -692,23 +670,8 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
*payFee = (retval == QMessageBox::Yes); *payFee = (retval == QMessageBox::Yes);
} }
void BitcoinGUI::incomingTransaction(const QModelIndex& parent, int start, int /*end*/) void BitcoinGUI::incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address)
{ {
// Prevent balloon-spam when initial block download is in progress
if(!walletModel || !clientModel || clientModel->inInitialBlockDownload())
return;
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
QString date = ttm->index(start, TransactionTableModel::Date, parent)
.data().toString();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
.data(Qt::EditRole).toULongLong();
QString type = ttm->index(start, TransactionTableModel::Type, parent)
.data().toString();
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
.data().toString();
// On new transaction, make an info balloon // On new transaction, make an info balloon
message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"), message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
tr("Date: %1\n" tr("Date: %1\n"
@ -716,80 +679,11 @@ void BitcoinGUI::incomingTransaction(const QModelIndex& parent, int start, int /
"Type: %3\n" "Type: %3\n"
"Address: %4\n") "Address: %4\n")
.arg(date) .arg(date)
.arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) .arg(BitcoinUnits::formatWithUnit(unit, amount, true))
.arg(type) .arg(type)
.arg(address), CClientUIInterface::MSG_INFORMATION); .arg(address), CClientUIInterface::MSG_INFORMATION);
} }
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(QString addr)
{
sendCoinsAction->setChecked(true);
centralWidget->setCurrentWidget(sendCoinsPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
if(!addr.isEmpty())
sendCoinsPage->setAddress(addr);
}
void BitcoinGUI::gotoSignMessageTab(QString addr)
{
// call show() in showTab_SM()
signVerifyMessageDialog->showTab_SM(true);
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_SM(addr);
}
void BitcoinGUI::gotoVerifyMessageTab(QString addr)
{
// call show() in showTab_VM()
signVerifyMessageDialog->showTab_VM(true);
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_VM(addr);
}
void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
{ {
// Accept only URIs // Accept only URIs
@ -805,13 +699,13 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
QList<QUrl> uris = event->mimeData()->urls(); QList<QUrl> uris = event->mimeData()->urls();
foreach(const QUrl &uri, uris) foreach(const QUrl &uri, uris)
{ {
if (sendCoinsPage->handleURI(uri.toString())) if (walletFrame->handleURI(uri.toString()))
nValidUrisFound++; nValidUrisFound++;
} }
// if valid URIs were found // if valid URIs were found
if (nValidUrisFound) if (nValidUrisFound)
gotoSendCoinsPage(); walletFrame->gotoSendCoinsPage();
else else
message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
CClientUIInterface::ICON_WARNING); CClientUIInterface::ICON_WARNING);
@ -835,12 +729,7 @@ bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
void BitcoinGUI::handleURI(QString strURI) void BitcoinGUI::handleURI(QString strURI)
{ {
// URI has to be valid // URI has to be valid
if (sendCoinsPage->handleURI(strURI)) if (!walletFrame->handleURI(strURI))
{
showNormalIfMinimized();
gotoSendCoinsPage();
}
else
message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."), message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
CClientUIInterface::ICON_WARNING); CClientUIInterface::ICON_WARNING);
} }
@ -876,49 +765,22 @@ void BitcoinGUI::setEncryptionStatus(int status)
void BitcoinGUI::encryptWallet(bool status) void BitcoinGUI::encryptWallet(bool status)
{ {
if(!walletModel) walletFrame->encryptWallet(status);
return;
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
AskPassphraseDialog::Decrypt, this);
dlg.setModel(walletModel);
dlg.exec();
setEncryptionStatus(walletModel->getEncryptionStatus());
} }
void BitcoinGUI::backupWallet() void BitcoinGUI::backupWallet()
{ {
QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); walletFrame->backupWallet();
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
if(!filename.isEmpty()) {
if(!walletModel->backupWallet(filename)) {
message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."),
CClientUIInterface::MSG_ERROR);
}
else
message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."),
CClientUIInterface::MSG_INFORMATION);
}
} }
void BitcoinGUI::changePassphrase() void BitcoinGUI::changePassphrase()
{ {
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); walletFrame->changePassphrase();
dlg.setModel(walletModel);
dlg.exec();
} }
void BitcoinGUI::unlockWallet() void BitcoinGUI::unlockWallet()
{ {
if(!walletModel) walletFrame->unlockWallet();
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) void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)

38
src/qt/bitcoingui.h

@ -3,10 +3,14 @@
#include <QMainWindow> #include <QMainWindow>
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#include <QMap>
class TransactionTableModel; class TransactionTableModel;
class WalletFrame;
class WalletView;
class ClientModel; class ClientModel;
class WalletModel; class WalletModel;
class WalletStack;
class TransactionView; class TransactionView;
class OverviewPage; class OverviewPage;
class AddressBookPage; class AddressBookPage;
@ -15,11 +19,16 @@ class SignVerifyMessageDialog;
class Notificator; class Notificator;
class RPCConsole; class RPCConsole;
class CWallet;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QLabel; class QLabel;
class QModelIndex; class QModelIndex;
class QProgressBar; class QProgressBar;
class QStackedWidget; class QStackedWidget;
class QUrl;
class QListWidget;
class QPushButton;
QT_END_NAMESPACE QT_END_NAMESPACE
/** /**
@ -31,6 +40,8 @@ class BitcoinGUI : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
static const QString DEFAULT_WALLET;
explicit BitcoinGUI(QWidget *parent = 0); explicit BitcoinGUI(QWidget *parent = 0);
~BitcoinGUI(); ~BitcoinGUI();
@ -42,7 +53,11 @@ public:
The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending
functionality. functionality.
*/ */
void setWalletModel(WalletModel *walletModel);
bool addWallet(const QString& name, WalletModel *walletModel);
bool setCurrentWallet(const QString& name);
void removeAllWallets();
protected: protected:
void changeEvent(QEvent *e); void changeEvent(QEvent *e);
@ -53,16 +68,7 @@ protected:
private: private:
ClientModel *clientModel; ClientModel *clientModel;
WalletModel *walletModel; WalletFrame *walletFrame;
QStackedWidget *centralWidget;
OverviewPage *overviewPage;
QWidget *transactionsPage;
AddressBookPage *addressBookPage;
AddressBookPage *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
SignVerifyMessageDialog *signVerifyMessageDialog;
QLabel *labelEncryptionIcon; QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon; QLabel *labelConnectionsIcon;
@ -139,6 +145,9 @@ public slots:
void askFee(qint64 nFeeRequired, bool *payFee); void askFee(qint64 nFeeRequired, bool *payFee);
void handleURI(QString strURI); void handleURI(QString strURI);
/** Show incoming transaction notification for new transactions. */
void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address);
private slots: private slots:
/** Switch to overview (home) page */ /** Switch to overview (home) page */
void gotoOverviewPage(); void gotoOverviewPage();
@ -149,7 +158,7 @@ private slots:
/** Switch to receive coins page */ /** Switch to receive coins page */
void gotoReceiveCoinsPage(); void gotoReceiveCoinsPage();
/** Switch to send coins page */ /** Switch to send coins page */
void gotoSendCoinsPage(QString addr = ""); void gotoSendCoinsPage();
/** Show Sign/Verify Message dialog and switch to sign message tab */ /** Show Sign/Verify Message dialog and switch to sign message tab */
void gotoSignMessageTab(QString addr = ""); void gotoSignMessageTab(QString addr = "");
@ -164,11 +173,6 @@ private slots:
/** Handle tray icon clicked */ /** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason); void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
#endif #endif
/** Show incoming transaction notification for new transactions.
The new items are those between start and end inclusive, under the given parent item.
*/
void incomingTransaction(const QModelIndex& parent, int start, int /*end*/);
/** Encrypt the wallet */ /** Encrypt the wallet */
void encryptWallet(bool status); void encryptWallet(bool status);
/** Backup the wallet */ /** Backup the wallet */

129
src/qt/walletframe.cpp

@ -0,0 +1,129 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#include "walletframe.h"
#include "bitcoingui.h"
#include "walletstack.h"
#include <QVBoxLayout>
#include <QMessageBox>
#include <stdio.h>
WalletFrame::WalletFrame(BitcoinGUI *_gui) :
QFrame(_gui),
gui(_gui),
clientModel(0)
{
// Leave HBox hook for adding a list view later
QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
walletStack = new WalletStack(this);
walletStack->setBitcoinGUI(gui);
walletFrameLayout->addWidget(walletStack);
}
WalletFrame::~WalletFrame()
{
}
void WalletFrame::setClientModel(ClientModel *clientModel)
{
this->clientModel = clientModel;
walletStack->setClientModel(clientModel);
}
bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
{
return walletStack->addWallet(name, walletModel);
}
bool WalletFrame::setCurrentWallet(const QString& name)
{
// TODO: Check if valid name
walletStack->setCurrentWallet(name);
return true;
}
void WalletFrame::removeAllWallets()
{
walletStack->removeAllWallets();
}
bool WalletFrame::handleURI(const QString &uri)
{
return walletStack->handleURI(uri);
}
void WalletFrame::showOutOfSyncWarning(bool fShow)
{
if (!walletStack) {
QMessageBox box;
box.setText("walletStack is null");
box.exec();
return;
}
walletStack->showOutOfSyncWarning(fShow);
}
void WalletFrame::gotoOverviewPage()
{
walletStack->gotoOverviewPage();
}
void WalletFrame::gotoHistoryPage()
{
walletStack->gotoHistoryPage();
}
void WalletFrame::gotoAddressBookPage()
{
walletStack->gotoAddressBookPage();
}
void WalletFrame::gotoReceiveCoinsPage()
{
walletStack->gotoReceiveCoinsPage();
}
void WalletFrame::gotoSendCoinsPage()
{
walletStack->gotoSendCoinsPage();
}
void WalletFrame::gotoSignMessageTab(QString addr)
{
walletStack->gotoSignMessageTab(addr);
}
void WalletFrame::gotoVerifyMessageTab(QString addr)
{
walletStack->gotoSignMessageTab(addr);
}
void WalletFrame::encryptWallet(bool status)
{
walletStack->encryptWallet(status);
}
void WalletFrame::backupWallet()
{
walletStack->backupWallet();
}
void WalletFrame::changePassphrase()
{
walletStack->changePassphrase();
}
void WalletFrame::unlockWallet()
{
walletStack->unlockWallet();
}
void WalletFrame::setEncryptionStatus()
{
walletStack->setEncryptionStatus();
}

73
src/qt/walletframe.h

@ -0,0 +1,73 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#ifndef WALLETFRAME_H
#define WALLETFRAME_H
#include <QFrame>
class BitcoinGUI;
class ClientModel;
class WalletModel;
class WalletStack;
class WalletFrame : public QFrame
{
Q_OBJECT
public:
explicit WalletFrame(BitcoinGUI *_gui);
~WalletFrame();
void setClientModel(ClientModel *clientModel);
bool addWallet(const QString& name, WalletModel *walletModel);
bool setCurrentWallet(const QString& name);
void removeAllWallets();
bool handleURI(const QString &uri);
void showOutOfSyncWarning(bool fShow);
private:
BitcoinGUI *gui;
ClientModel *clientModel;
WalletStack *walletStack;
public slots:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
/** Switch to address book page */
void gotoAddressBookPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
void gotoSendCoinsPage();
/** Show Sign/Verify Message dialog and switch to sign message tab */
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
void backupWallet();
/** Change encrypted wallet passphrase */
void changePassphrase();
/** Ask for passphrase to unlock wallet temporarily */
void unlockWallet();
/** Set the encryption status as shown in the UI.
@param[in] status current encryption status
@see WalletModel::EncryptionStatus
*/
void setEncryptionStatus();
};
#endif // WALLETFRAME_H

155
src/qt/walletstack.cpp

@ -0,0 +1,155 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#include "walletstack.h"
#include "walletview.h"
#include "bitcoingui.h"
#include <QMap>
#include <QMessageBox>
WalletStack::WalletStack(QWidget *parent) :
QStackedWidget(parent),
clientModel(0),
bOutOfSync(true)
{
}
WalletStack::~WalletStack()
{
}
bool WalletStack::addWallet(const QString& name, WalletModel *walletModel)
{
if (!gui || !clientModel || mapWalletViews.count(name) > 0)
return false;
WalletView *walletView = new WalletView(this, gui);
walletView->setBitcoinGUI(gui);
walletView->setClientModel(clientModel);
walletView->setWalletModel(walletModel);
walletView->showOutOfSyncWarning(bOutOfSync);
addWidget(walletView);
mapWalletViews[name] = walletView;
return true;
}
bool WalletStack::removeWallet(const QString& name)
{
if (mapWalletViews.count(name) == 0) return false;
WalletView *walletView = mapWalletViews.take(name);
removeWidget(walletView);
return true;
}
void WalletStack::removeAllWallets()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
removeWidget(i.value());
mapWalletViews.clear();
}
bool WalletStack::handleURI(const QString &uri)
{
WalletView *walletView = (WalletView*)currentWidget();
if (!walletView) return false;
return walletView->handleURI(uri);
}
void WalletStack::showOutOfSyncWarning(bool fShow)
{
bOutOfSync = fShow;
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->showOutOfSyncWarning(fShow);
}
void WalletStack::gotoOverviewPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoOverviewPage();
}
void WalletStack::gotoHistoryPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoHistoryPage();
}
void WalletStack::gotoAddressBookPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoAddressBookPage();
}
void WalletStack::gotoReceiveCoinsPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoReceiveCoinsPage();
}
void WalletStack::gotoSendCoinsPage()
{
QMap<QString, WalletView*>::const_iterator i;
for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
i.value()->gotoSendCoinsPage();
}
void WalletStack::gotoSignMessageTab(QString addr)
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->gotoSignMessageTab(addr);
}
void WalletStack::gotoVerifyMessageTab(QString addr)
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->gotoVerifyMessageTab(addr);
}
void WalletStack::encryptWallet(bool status)
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->encryptWallet(status);
}
void WalletStack::backupWallet()
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->backupWallet();
}
void WalletStack::changePassphrase()
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->changePassphrase();
}
void WalletStack::unlockWallet()
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->unlockWallet();
}
void WalletStack::setEncryptionStatus()
{
WalletView *walletView = (WalletView*)currentWidget();
if (walletView) walletView->setEncryptionStatus();
}
void WalletStack::setCurrentWallet(const QString& name)
{
if (mapWalletViews.count(name) == 0) return;
WalletView *walletView = mapWalletViews.value(name);
setCurrentWidget(walletView);
walletView->setEncryptionStatus();
}

102
src/qt/walletstack.h

@ -0,0 +1,102 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#ifndef WALLETSTACK_H
#define WALLETSTACK_H
#include <QStackedWidget>
#include <QMap>
#include <boost/shared_ptr.hpp>
class BitcoinGUI;
class TransactionTableModel;
class ClientModel;
class WalletModel;
class WalletView;
class TransactionView;
class OverviewPage;
class AddressBookPage;
class SendCoinsDialog;
class SignVerifyMessageDialog;
class Notificator;
class RPCConsole;
class CWalletManager;
QT_BEGIN_NAMESPACE
class QLabel;
class QModelIndex;
QT_END_NAMESPACE
/*
WalletStack class. This class is a container for WalletView instances. It takes the place of centralWidget.
It was added to support multiple wallet functionality. It communicates with both the client and the
wallet models to give the user an up-to-date view of the current core state. It manages all the wallet views
it contains and updates them accordingly.
*/
class WalletStack : public QStackedWidget
{
Q_OBJECT
public:
explicit WalletStack(QWidget *parent = 0);
~WalletStack();
void setBitcoinGUI(BitcoinGUI *gui) { this->gui = gui; }
void setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; }
bool addWallet(const QString& name, WalletModel *walletModel);
bool removeWallet(const QString& name);
void removeAllWallets();
bool handleURI(const QString &uri);
void showOutOfSyncWarning(bool fShow);
private:
BitcoinGUI *gui;
ClientModel *clientModel;
QMap<QString, WalletView*> mapWalletViews;
bool bOutOfSync;
public slots:
void setCurrentWallet(const QString& name);
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
/** Switch to address book page */
void gotoAddressBookPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
void gotoSendCoinsPage();
/** Show Sign/Verify Message dialog and switch to sign message tab */
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
void backupWallet();
/** Change encrypted wallet passphrase */
void changePassphrase();
/** Ask for passphrase to unlock wallet temporarily */
void unlockWallet();
/** Set the encryption status as shown in the UI.
@param[in] status current encryption status
@see WalletModel::EncryptionStatus
*/
void setEncryptionStatus();
};
#endif // WALLETSTACK_H

354
src/qt/walletview.cpp

@ -0,0 +1,354 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#include "walletview.h"
#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 "guiutil.h"
#include "ui_interface.h"
#include <QVBoxLayout>
#include <QActionGroup>
#include <QAction>
#include <QLabel>
#include <QDesktopServices>
#include <QFileDialog>
WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui):
QStackedWidget(parent),
gui(_gui),
clientModel(0),
walletModel(0),
encryptWalletAction(0),
changePassphraseAction(0)
{
// Create actions for the toolbar, menu bar and tray/dock icon
createActions();
// 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(gui);
signVerifyMessageDialog = new SignVerifyMessageDialog(gui);
addWidget(overviewPage);
addWidget(transactionsPage);
addWidget(addressBookPage);
addWidget(receiveCoinsPage);
addWidget(sendCoinsPage);
// 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()));
// 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();
}
WalletView::~WalletView()
{
}
void WalletView::createActions()
{
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 coins"), 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 coins"), this);
receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments"));
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);
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels"));
addressBookAction->setToolTip(addressBookAction->statusTip());
addressBookAction->setCheckable(true);
addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
tabGroup->addAction(addressBookAction);
connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
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"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
exportAction->setStatusTip(tr("Export the data in the current tab to a file"));
exportAction->setToolTip(exportAction->statusTip());
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab()));
connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab()));
}
void WalletView::setBitcoinGUI(BitcoinGUI *gui)
{
this->gui = gui;
}
void WalletView::setClientModel(ClientModel *clientModel)
{
this->clientModel = clientModel;
if(clientModel)
{
overviewPage->setClientModel(clientModel);
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
}
}
void WalletView::setWalletModel(WalletModel *walletModel)
{
this->walletModel = walletModel;
if(walletModel)
{
// Receive and report messages from wallet thread
connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int)));
// Put transaction list in tabs
transactionView->setModel(walletModel);
overviewPage->setWalletModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
signVerifyMessageDialog->setModel(walletModel);
setEncryptionStatus();
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), gui, 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 WalletView::incomingTransaction(const QModelIndex& parent, int start, int /*end*/)
{
// Prevent balloon-spam when initial block download is in progress
if(!walletModel || !clientModel || clientModel->inInitialBlockDownload())
return;
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
QString date = ttm->index(start, TransactionTableModel::Date, parent)
.data().toString();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
.data(Qt::EditRole).toULongLong();
QString type = ttm->index(start, TransactionTableModel::Type, parent)
.data().toString();
QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
.data().toString();
gui->incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address);
}
void WalletView::gotoOverviewPage()
{
overviewAction->setChecked(true);
setCurrentWidget(overviewPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void WalletView::gotoHistoryPage()
{
historyAction->setChecked(true);
setCurrentWidget(transactionsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked()));
}
void WalletView::gotoAddressBookPage()
{
addressBookAction->setChecked(true);
setCurrentWidget(addressBookPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked()));
}
void WalletView::gotoReceiveCoinsPage()
{
receiveCoinsAction->setChecked(true);
setCurrentWidget(receiveCoinsPage);
exportAction->setEnabled(true);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked()));
}
void WalletView::gotoSendCoinsPage()
{
sendCoinsAction->setChecked(true);
setCurrentWidget(sendCoinsPage);
exportAction->setEnabled(false);
disconnect(exportAction, SIGNAL(triggered()), 0, 0);
}
void WalletView::gotoSignMessageTab(QString addr)
{
// call show() in showTab_SM()
signVerifyMessageDialog->showTab_SM(true);
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_SM(addr);
}
void WalletView::gotoVerifyMessageTab(QString addr)
{
// call show() in showTab_VM()
signVerifyMessageDialog->showTab_VM(true);
if(!addr.isEmpty())
signVerifyMessageDialog->setAddress_VM(addr);
}
bool WalletView::handleURI(const QString& strURI)
{
// URI has to be valid
if (sendCoinsPage->handleURI(strURI))
{
gotoSendCoinsPage();
return true;
}
else
return false;
}
void WalletView::showOutOfSyncWarning(bool fShow)
{
overviewPage->showOutOfSyncWarning(fShow);
}
void WalletView::setEncryptionStatus()
{
gui->setEncryptionStatus(walletModel->getEncryptionStatus());
}
void WalletView::encryptWallet(bool status)
{
if(!walletModel)
return;
AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt:
AskPassphraseDialog::Decrypt, this);
dlg.setModel(walletModel);
dlg.exec();
setEncryptionStatus();
}
void WalletView::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)) {
gui->message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."),
CClientUIInterface::MSG_ERROR);
}
else
gui->message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."),
CClientUIInterface::MSG_INFORMATION);
}
}
void WalletView::changePassphrase()
{
AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
dlg.setModel(walletModel);
dlg.exec();
}
void WalletView::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();
}
}

132
src/qt/walletview.h

@ -0,0 +1,132 @@
/*
* Qt4 bitcoin GUI.
*
* W.J. van der Laan 2011-2012
* The Bitcoin Developers 2011-2013
*/
#ifndef WALLETVIEW_H
#define WALLETVIEW_H
#include <QStackedWidget>
class BitcoinGUI;
class TransactionTableModel;
class ClientModel;
class WalletModel;
class TransactionView;
class OverviewPage;
class AddressBookPage;
class SendCoinsDialog;
class SignVerifyMessageDialog;
class Notificator;
class RPCConsole;
QT_BEGIN_NAMESPACE
class QLabel;
class QModelIndex;
QT_END_NAMESPACE
/*
WalletView class. This class represents the view to a single wallet.
It was added to support multiple wallet functionality. Each wallet gets its own WalletView instance.
It communicates with both the client and the wallet models to give the user an up-to-date view of the
current core state.
*/
class WalletView : public QStackedWidget
{
Q_OBJECT
public:
explicit WalletView(QWidget *parent, BitcoinGUI *_gui);
~WalletView();
void setBitcoinGUI(BitcoinGUI *gui);
/** Set the client model.
The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic.
*/
void setClientModel(ClientModel *clientModel);
/** Set the wallet model.
The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending
functionality.
*/
void setWalletModel(WalletModel *walletModel);
bool handleURI(const QString &uri);
void showOutOfSyncWarning(bool fShow);
private:
BitcoinGUI *gui;
ClientModel *clientModel;
WalletModel *walletModel;
OverviewPage *overviewPage;
QWidget *transactionsPage;
AddressBookPage *addressBookPage;
AddressBookPage *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
SignVerifyMessageDialog *signVerifyMessageDialog;
QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
QAction *overviewAction;
QAction *historyAction;
QAction *quitAction;
QAction *sendCoinsAction;
QAction *addressBookAction;
QAction *signMessageAction;
QAction *verifyMessageAction;
QAction *aboutAction;
QAction *receiveCoinsAction;
QAction *optionsAction;
QAction *toggleHideAction;
QAction *exportAction;
QAction *encryptWalletAction;
QAction *backupWalletAction;
QAction *changePassphraseAction;
QAction *aboutQtAction;
QAction *openRPCConsoleAction;
TransactionView *transactionView;
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and sub-menus. */
public slots:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
void gotoHistoryPage();
/** Switch to address book page */
void gotoAddressBookPage();
/** Switch to receive coins page */
void gotoReceiveCoinsPage();
/** Switch to send coins page */
void gotoSendCoinsPage();
/** Show Sign/Verify Message dialog and switch to sign message tab */
void gotoSignMessageTab(QString addr = "");
/** Show Sign/Verify Message dialog and switch to verify message tab */
void gotoVerifyMessageTab(QString addr = "");
/** Show incoming transaction notification for new transactions.
The new items are those between start and end inclusive, under the given parent item.
*/
void incomingTransaction(const QModelIndex& parent, int start, int /*end*/);
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
void backupWallet();
/** Change encrypted wallet passphrase */
void changePassphrase();
/** Ask for passphrase to unlock wallet temporarily */
void unlockWallet();
void setEncryptionStatus();
};
#endif // WALLETVIEW_H
Loading…
Cancel
Save