/* * 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(); } }