From 67155d9299ef75cc73272a259dbfbf72632c3020 Mon Sep 17 00:00:00 2001 From: Eric Lombrozo Date: Fri, 22 Mar 2013 10:32:49 -0700 Subject: [PATCH] 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. --- bitcoin-qt.pro | 6 + multiwallet-qt.txt | 53 ++++++ src/qt/bitcoin.cpp | 5 +- src/qt/bitcoingui.cpp | 278 ++++++++------------------------ src/qt/bitcoingui.h | 40 ++--- src/qt/walletframe.cpp | 129 +++++++++++++++ src/qt/walletframe.h | 73 +++++++++ src/qt/walletstack.cpp | 155 ++++++++++++++++++ src/qt/walletstack.h | 102 ++++++++++++ src/qt/walletview.cpp | 354 +++++++++++++++++++++++++++++++++++++++++ src/qt/walletview.h | 132 +++++++++++++++ 11 files changed, 1099 insertions(+), 228 deletions(-) create mode 100644 multiwallet-qt.txt create mode 100644 src/qt/walletframe.cpp create mode 100644 src/qt/walletframe.h create mode 100644 src/qt/walletstack.cpp create mode 100644 src/qt/walletstack.h create mode 100644 src/qt/walletview.cpp create mode 100644 src/qt/walletview.h diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index bf41314052a..d518cf3b169 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -186,6 +186,9 @@ HEADERS += src/qt/bitcoingui.h \ src/qt/transactionfilterproxy.h \ src/qt/transactionview.h \ src/qt/walletmodel.h \ + src/qt/walletview.h \ + src/qt/walletstack.h \ + src/qt/walletframe.h \ src/bitcoinrpc.h \ src/qt/overviewpage.h \ src/qt/csvmodelwriter.h \ @@ -250,6 +253,9 @@ SOURCES += src/qt/bitcoin.cpp \ src/qt/transactionfilterproxy.cpp \ src/qt/transactionview.cpp \ src/qt/walletmodel.cpp \ + src/qt/walletview.cpp \ + src/qt/walletstack.cpp \ + src/qt/walletframe.cpp \ src/bitcoinrpc.cpp \ src/rpcdump.cpp \ src/rpcnet.cpp \ diff --git a/multiwallet-qt.txt b/multiwallet-qt.txt new file mode 100644 index 00000000000..8394080db01 --- /dev/null +++ b/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(); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e3d51be54a3..346128c0c45 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -232,7 +232,8 @@ int main(int argc, char *argv[]) WalletModel walletModel(pwalletMain, &optionsModel); window.setClientModel(&clientModel); - window.setWalletModel(&walletModel); + window.addWallet("~Default", &walletModel); + window.setCurrentWallet("~Default"); // If -min option passed, start window minimized. if(GetBoolArg("-min")) @@ -253,7 +254,7 @@ int main(int argc, char *argv[]) window.hide(); window.setClientModel(0); - window.setWalletModel(0); + window.removeAllWallets(); guiref = 0; } // Shutdown the core and its threads, but don't exit Bitcoin-Qt here diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0d951718bbf..6b6b86eacae 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -10,26 +10,20 @@ #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 "walletframe.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" #include "ui_interface.h" +#include "wallet.h" #ifdef Q_OS_MAC #include "macdockiconhandler.h" @@ -54,13 +48,15 @@ #include #include #include +#include #include +const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; + BitcoinGUI::BitcoinGUI(QWidget *parent): QMainWindow(parent), clientModel(0), - walletModel(0), encryptWalletAction(0), changePassphraseAction(0), aboutQtAction(0), @@ -93,31 +89,10 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Create system tray icon and notification 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); - setCentralWidget(centralWidget); - + // Create wallet frame and make it the central widget + walletFrame = new WalletFrame(this); + setCentralWidget(walletFrame); + // Create status bar statusBar(); @@ -162,27 +137,11 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): 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 "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) this->installEventFilter(this); - - gotoOverviewPage(); } BitcoinGUI::~BitcoinGUI() @@ -243,7 +202,7 @@ void BitcoinGUI::createActions() connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); - + quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); @@ -377,39 +336,23 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // Receive and report messages from network/worker thread connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); - overviewPage->setClientModel(clientModel); - rpcConsole->setClientModel(clientModel); - addressBookPage->setOptionsModel(clientModel->getOptionsModel()); - receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); + walletFrame->setClientModel(clientModel); } } -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 - 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 - connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); - } + return walletFrame->addWallet(name, walletModel); +} + +bool BitcoinGUI::setCurrentWallet(const QString& name) +{ + return walletFrame->setCurrentWallet(name); +} + +void BitcoinGUI::removeAllWallets() +{ + walletFrame->removeAllWallets(); } void BitcoinGUI::createTrayIcon() @@ -484,6 +427,41 @@ void BitcoinGUI::aboutClicked() 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) { QString icon; @@ -548,7 +526,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) tooltip = tr("Up to date") + QString(".
") + tooltip; labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); - overviewPage->showOutOfSyncWarning(false); + walletFrame->showOutOfSyncWarning(false); progressBarLabel->setVisible(false); progressBar->setVisible(false); @@ -583,7 +561,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) syncIconMovie->jumpToNextFrame(); prevBlocks = count; - overviewPage->showOutOfSyncWarning(true); + walletFrame->showOutOfSyncWarning(true); tooltip += QString("
"); tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText); @@ -692,104 +670,20 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) *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"), tr("Date: %1\n" "Amount: %2\n" "Type: %3\n" "Address: %4\n") .arg(date) - .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true)) + .arg(BitcoinUnits::formatWithUnit(unit, amount, true)) .arg(type) .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) { // Accept only URIs @@ -805,13 +699,13 @@ void BitcoinGUI::dropEvent(QDropEvent *event) QList uris = event->mimeData()->urls(); foreach(const QUrl &uri, uris) { - if (sendCoinsPage->handleURI(uri.toString())) + if (walletFrame->handleURI(uri.toString())) nValidUrisFound++; } // if valid URIs were found if (nValidUrisFound) - gotoSendCoinsPage(); + walletFrame->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."), CClientUIInterface::ICON_WARNING); @@ -835,12 +729,7 @@ bool BitcoinGUI::eventFilter(QObject *object, QEvent *event) void BitcoinGUI::handleURI(QString strURI) { // URI has to be valid - if (sendCoinsPage->handleURI(strURI)) - { - showNormalIfMinimized(); - gotoSendCoinsPage(); - } - else + if (!walletFrame->handleURI(strURI)) 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); } @@ -876,49 +765,22 @@ void BitcoinGUI::setEncryptionStatus(int status) void BitcoinGUI::encryptWallet(bool status) { - if(!walletModel) - return; - AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt: - AskPassphraseDialog::Decrypt, this); - dlg.setModel(walletModel); - dlg.exec(); - - setEncryptionStatus(walletModel->getEncryptionStatus()); + walletFrame->encryptWallet(status); } 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)) { - 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); - } + walletFrame->backupWallet(); } void BitcoinGUI::changePassphrase() { - AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); - dlg.setModel(walletModel); - dlg.exec(); + walletFrame->changePassphrase(); } 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(); - } + walletFrame->unlockWallet(); } void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 1b3e313fc28..f9c550035aa 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -3,10 +3,14 @@ #include #include +#include class TransactionTableModel; +class WalletFrame; +class WalletView; class ClientModel; class WalletModel; +class WalletStack; class TransactionView; class OverviewPage; class AddressBookPage; @@ -15,11 +19,16 @@ class SignVerifyMessageDialog; class Notificator; class RPCConsole; +class CWallet; + QT_BEGIN_NAMESPACE class QLabel; class QModelIndex; class QProgressBar; class QStackedWidget; +class QUrl; +class QListWidget; +class QPushButton; QT_END_NAMESPACE /** @@ -31,6 +40,8 @@ class BitcoinGUI : public QMainWindow Q_OBJECT public: + static const QString DEFAULT_WALLET; + explicit BitcoinGUI(QWidget *parent = 0); ~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 functionality. */ - void setWalletModel(WalletModel *walletModel); + + bool addWallet(const QString& name, WalletModel *walletModel); + bool setCurrentWallet(const QString& name); + + void removeAllWallets(); protected: void changeEvent(QEvent *e); @@ -53,16 +68,7 @@ protected: private: ClientModel *clientModel; - WalletModel *walletModel; - - QStackedWidget *centralWidget; - - OverviewPage *overviewPage; - QWidget *transactionsPage; - AddressBookPage *addressBookPage; - AddressBookPage *receiveCoinsPage; - SendCoinsDialog *sendCoinsPage; - SignVerifyMessageDialog *signVerifyMessageDialog; + WalletFrame *walletFrame; QLabel *labelEncryptionIcon; QLabel *labelConnectionsIcon; @@ -88,7 +94,7 @@ private: QAction *changePassphraseAction; QAction *aboutQtAction; QAction *openRPCConsoleAction; - + QSystemTrayIcon *trayIcon; Notificator *notificator; TransactionView *transactionView; @@ -139,6 +145,9 @@ public slots: void askFee(qint64 nFeeRequired, bool *payFee); 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: /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -149,7 +158,7 @@ private slots: /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ - void gotoSendCoinsPage(QString addr = ""); + void gotoSendCoinsPage(); /** Show Sign/Verify Message dialog and switch to sign message tab */ void gotoSignMessageTab(QString addr = ""); @@ -164,11 +173,6 @@ private slots: /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); #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 */ void encryptWallet(bool status); /** Backup the wallet */ diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp new file mode 100644 index 00000000000..a53aa654669 --- /dev/null +++ b/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 +#include + +#include + +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(); +} diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h new file mode 100644 index 00000000000..5b4baf72556 --- /dev/null +++ b/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 + +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 \ No newline at end of file diff --git a/src/qt/walletstack.cpp b/src/qt/walletstack.cpp new file mode 100644 index 00000000000..271d1c79248 --- /dev/null +++ b/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 +#include + +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::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::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->showOutOfSyncWarning(fShow); +} + +void WalletStack::gotoOverviewPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoOverviewPage(); +} + +void WalletStack::gotoHistoryPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoHistoryPage(); +} + +void WalletStack::gotoAddressBookPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoAddressBookPage(); +} + +void WalletStack::gotoReceiveCoinsPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoReceiveCoinsPage(); +} + +void WalletStack::gotoSendCoinsPage() +{ + QMap::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(); +} diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h new file mode 100644 index 00000000000..f3485816e95 --- /dev/null +++ b/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 +#include +#include + +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 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 diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp new file mode 100644 index 00000000000..7dd36234c96 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +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(); + } +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h new file mode 100644 index 00000000000..38eb0227af4 --- /dev/null +++ b/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 + +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