X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fqt%2Fbitcoingui.cpp;h=22987267ecfd83e804a3f7417607cde3b3df7f86;hb=ae8adeb90abb334b8e5712124e62461eca77c12f;hp=34da1350cdcec2863b010be124c52ecbd9094f93;hpb=fbaee7a8533b23d846ee16837320f709c4e83d47;p=novacoin.git diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 34da135..2298726 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -5,19 +5,20 @@ */ #include "bitcoingui.h" #include "transactiontablemodel.h" -#include "addressbookdialog.h" +#include "addressbookpage.h" #include "sendcoinsdialog.h" #include "optionsdialog.h" #include "aboutdialog.h" #include "clientmodel.h" #include "walletmodel.h" -#include "guiutil.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 #include @@ -35,8 +36,11 @@ #include #include #include +#include +#include -#include +#include +#include #include @@ -49,64 +53,82 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): resize(850, 550); setWindowTitle(tr("Bitcoin Wallet")); setWindowIcon(QIcon(":icons/bitcoin")); + // Accept D&D of URIs + setAcceptDrops(true); createActions(); // Menus QMenu *file = menuBar()->addMenu("&File"); - file->addAction(sendCoins); - file->addAction(receiveCoins); + file->addAction(sendCoinsAction); + file->addAction(receiveCoinsAction); file->addSeparator(); - file->addAction(quit); + file->addAction(quitAction); QMenu *settings = menuBar()->addMenu("&Settings"); - settings->addAction(options); + settings->addAction(optionsAction); QMenu *help = menuBar()->addMenu("&Help"); - help->addAction(about); + help->addAction(aboutAction); - // Toolbar - QToolBar *toolbar = addToolBar("Main toolbar"); + // Toolbars + QToolBar *toolbar = addToolBar(tr("Tabs toolbar")); toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toolbar->addAction(overviewAction); + toolbar->addAction(sendCoinsAction); + toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); - toolbar->addSeparator(); - toolbar->addAction(sendCoins); - toolbar->addAction(receiveCoins); - toolbar->addAction(addressbook); + toolbar->addAction(addressBookAction); - QToolBar *toolbar2 = addToolBar("Transactions toolbar"); + QToolBar *toolbar2 = addToolBar(tr("Actions toolbar")); toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); toolbar2->addAction(exportAction); - // Overview page + // Create tabs overviewPage = new OverviewPage(); - QVBoxLayout *vbox = new QVBoxLayout(); + transactionsPage = new QWidget(this); + QVBoxLayout *vbox = new QVBoxLayout(); transactionView = new TransactionView(this); - connect(transactionView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(transactionDetails(const QModelIndex&))); vbox->addWidget(transactionView); - - transactionsPage = new QWidget(this); transactionsPage->setLayout(vbox); + addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); + + receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); + + sendCoinsPage = new SendCoinsDialog(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 statusBar(); - labelConnections = new QLabel(); - labelConnections->setFrameStyle(QFrame::Panel | QFrame::Sunken); - labelConnections->setMinimumWidth(150); - labelConnections->setToolTip(tr("Number of connections to other clients")); - - labelBlocks = new QLabel(); - labelBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken); - labelBlocks->setMinimumWidth(130); - labelBlocks->setToolTip(tr("Number of blocks in the block chain")); + // Status bar notification icons + QFrame *frameBlocks = new QFrame(); + //frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken); + frameBlocks->setContentsMargins(0,0,0,0); + frameBlocks->setMinimumWidth(56); + frameBlocks->setMaximumWidth(56); + QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks); + frameBlocksLayout->setContentsMargins(3,0,3,0); + frameBlocksLayout->setSpacing(3); + labelEncryptionIcon = new QLabel(); + labelConnectionsIcon = new QLabel(); + labelBlocksIcon = new QLabel(); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelEncryptionIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelConnectionsIcon); + frameBlocksLayout->addStretch(); + frameBlocksLayout->addWidget(labelBlocksIcon); + frameBlocksLayout->addStretch(); // Progress bar for blocks download progressBarLabel = new QLabel(tr("Synchronizing with network...")); @@ -117,52 +139,71 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): statusBar()->addWidget(progressBarLabel); statusBar()->addWidget(progressBar); - statusBar()->addPermanentWidget(labelConnections); - statusBar()->addPermanentWidget(labelBlocks); + statusBar()->addPermanentWidget(frameBlocks); createTrayIcon(); - gotoOverviewTab(); + 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())); + + // Doubleclicking on a transaction on the transaction history page shows details + connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + + gotoOverviewPage(); } void BitcoinGUI::createActions() { QActionGroup *tabGroup = new QActionGroup(this); + overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this); + overviewAction->setToolTip(tr("Show general overview of wallet")); overviewAction->setCheckable(true); tabGroup->addAction(overviewAction); + historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); + historyAction->setToolTip(tr("Browse transaction history")); historyAction->setCheckable(true); tabGroup->addAction(historyAction); - connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewTab())); - connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryTab())); - - quit = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this); - quit->setToolTip(tr("Quit application")); - sendCoins = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); - sendCoins->setToolTip(tr("Send coins to a bitcoin address")); - addressbook = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); - addressbook->setToolTip(tr("Edit the list of stored addresses and labels")); - about = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this); - about->setToolTip(tr("Show information about Bitcoin")); - receiveCoins = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); - receiveCoins->setToolTip(tr("Show the list of addresses for receiving payments")); - options = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); - options->setToolTip(tr("Modify configuration options for bitcoin")); - openBitcoin = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this); - openBitcoin->setToolTip(tr("Show the Bitcoin window")); + addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); + addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels")); + addressBookAction->setCheckable(true); + tabGroup->addAction(addressBookAction); + + receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); + receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments")); + receiveCoinsAction->setCheckable(true); + tabGroup->addAction(receiveCoinsAction); + + sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); + sendCoinsAction->setToolTip(tr("Send coins to a bitcoin address")); + sendCoinsAction->setCheckable(true); + tabGroup->addAction(sendCoinsAction); + + connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); + connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); + connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + + quitAction = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this); + quitAction->setToolTip(tr("Quit application")); + aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this); + aboutAction->setToolTip(tr("Show information about Bitcoin")); + optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); + optionsAction->setToolTip(tr("Modify configuration options for bitcoin")); + openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this); + openBitcoinAction->setToolTip(tr("Show the Bitcoin window")); exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); - exportAction->setToolTip(tr("Export data in current view to a file")); - - connect(quit, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(sendCoins, SIGNAL(triggered()), this, SLOT(sendCoinsClicked())); - connect(addressbook, SIGNAL(triggered()), this, SLOT(addressbookClicked())); - connect(receiveCoins, SIGNAL(triggered()), this, SLOT(receiveCoinsClicked())); - connect(options, SIGNAL(triggered()), this, SLOT(optionsClicked())); - connect(about, SIGNAL(triggered()), this, SLOT(aboutClicked())); - connect(openBitcoin, SIGNAL(triggered()), this, SLOT(show())); - connect(exportAction, SIGNAL(triggered()), this, SLOT(exportClicked())); + exportAction->setToolTip(tr("Export the current view to a file")); + + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); + connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); + connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(show())); } void BitcoinGUI::setClientModel(ClientModel *clientModel) @@ -171,7 +212,7 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) if(clientModel->isTestNet()) { - QString title_testnet = tr("Bitcoin Wallet [testnet]"); + QString title_testnet = windowTitle() + QString(" ") + tr("[testnet]"); setWindowTitle(title_testnet); setWindowIcon(QIcon(":icons/bitcoin_testnet")); if(trayIcon) @@ -196,32 +237,32 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel) { this->walletModel = walletModel; - // Keep up to date with wallet - setBalance(walletModel->getBalance()); - connect(walletModel, SIGNAL(balanceChanged(qint64)), this, SLOT(setBalance(qint64))); - - setNumTransactions(walletModel->getNumTransactions()); - connect(walletModel, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); - // Report errors from wallet thread connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString))); // Put transaction list in tabs - transactionView->setModel(walletModel->getTransactionTableModel()); + transactionView->setModel(walletModel); + + overviewPage->setModel(walletModel); + addressBookPage->setModel(walletModel->getAddressTableModel()); + receiveCoinsPage->setModel(walletModel->getAddressTableModel()); + sendCoinsPage->setModel(walletModel); + + setEncryptionStatus(walletModel->getEncryptionStatus()); + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int))); // Balloon popup for new transaction - connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), - this, SLOT(incomingTransaction(const QModelIndex &, int, int))); + connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(incomingTransaction(QModelIndex,int,int))); } void BitcoinGUI::createTrayIcon() { QMenu *trayIconMenu = new QMenu(this); - trayIconMenu->addAction(openBitcoin); - trayIconMenu->addAction(sendCoins); - trayIconMenu->addAction(options); + trayIconMenu->addAction(openBitcoinAction); + trayIconMenu->addAction(optionsAction); trayIconMenu->addSeparator(); - trayIconMenu->addAction(quit); + trayIconMenu->addAction(quitAction); trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu); @@ -234,36 +275,13 @@ void BitcoinGUI::createTrayIcon() void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { - if(reason == QSystemTrayIcon::DoubleClick) + if(reason == QSystemTrayIcon::Trigger) { // Doubleclick on system tray icon triggers "open bitcoin" - openBitcoin->trigger(); + openBitcoinAction->trigger(); } } -void BitcoinGUI::sendCoinsClicked() -{ - SendCoinsDialog dlg; - dlg.setModel(walletModel); - dlg.exec(); -} - -void BitcoinGUI::addressbookClicked() -{ - AddressBookDialog dlg(AddressBookDialog::ForEditing); - dlg.setModel(walletModel->getAddressTableModel()); - dlg.setTab(AddressBookDialog::SendingTab); - dlg.exec(); -} - -void BitcoinGUI::receiveCoinsClicked() -{ - AddressBookDialog dlg(AddressBookDialog::ForEditing); - dlg.setModel(walletModel->getAddressTableModel()); - dlg.setTab(AddressBookDialog::ReceivingTab); - dlg.exec(); -} - void BitcoinGUI::optionsClicked() { OptionsDialog dlg; @@ -278,11 +296,6 @@ void BitcoinGUI::aboutClicked() dlg.exec(); } -void BitcoinGUI::setBalance(qint64 balance) -{ - overviewPage->setBalance(balance); -} - void BitcoinGUI::setNumConnections(int count) { QString icon; @@ -294,32 +307,72 @@ void BitcoinGUI::setNumConnections(int count) case 7: case 8: case 9: icon = ":/icons/connect_3"; break; default: icon = ":/icons/connect_4"; break; } - labelConnections->setTextFormat(Qt::RichText); - labelConnections->setText(" " + tr("%n connection(s)", "", count)); + labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); } void BitcoinGUI::setNumBlocks(int count) { int total = clientModel->getTotalBlocksEstimate(); + QString tooltip; + if(count < total) { progressBarLabel->setVisible(true); progressBar->setVisible(true); progressBar->setMaximum(total); progressBar->setValue(count); + tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total); } else { progressBarLabel->setVisible(false); progressBar->setVisible(false); + tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count); } - labelBlocks->setText(tr("%n block(s)", "", count)); -} + QDateTime now = QDateTime::currentDateTime(); + QDateTime lastBlockDate = clientModel->getLastBlockDate(); + int secs = lastBlockDate.secsTo(now); + QString text; -void BitcoinGUI::setNumTransactions(int count) -{ - overviewPage->setNumTransactions(count); + // Represent time from last generated block in human readable text + if(secs < 60) + { + text = tr("%n second(s) ago","",secs); + } + else if(secs < 60*60) + { + text = tr("%n minute(s) ago","",secs/60); + } + else if(secs < 24*60*60) + { + text = tr("%n hour(s) ago","",secs/(60*60)); + } + else + { + text = tr("%n day(s) ago","",secs/(60*60*24)); + } + + // Set icon state: spinning if catching up, tick otherwise + if(secs < 30*60) + { + tooltip = tr("Up to date") + QString("\n") + tooltip; + labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + } + else + { + tooltip = tr("Catching up...") + QString("\n") + tooltip; + labelBlocksIcon->setMovie(syncIconMovie); + syncIconMovie->start(); + } + + tooltip += QString("\n"); + tooltip += tr("Last received block was generated %1.").arg(text); + + labelBlocksIcon->setToolTip(tooltip); + progressBarLabel->setToolTip(tooltip); + progressBar->setToolTip(tooltip); } void BitcoinGUI::error(const QString &title, const QString &message) @@ -374,28 +427,24 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee) QString strMessage = tr("This transaction is over the size limit. You can still send it for a fee of %1, " "which goes to the nodes that process your transaction and helps to support the network. " - "Do you want to pay the fee?").arg(GUIUtil::formatMoney(nFeeRequired)); + "Do you want to pay the fee?").arg( + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired)); QMessageBox::StandardButton retval = QMessageBox::question( this, tr("Sending..."), strMessage, QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes); *payFee = (retval == QMessageBox::Yes); } -void BitcoinGUI::transactionDetails(const QModelIndex& idx) -{ - // A transaction is doubleclicked - TransactionDescDialog dlg(idx); - dlg.exec(); -} - void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end) { + if(start == end) + return; TransactionTableModel *ttm = walletModel->getTransactionTableModel(); qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) .data(Qt::EditRole).toULongLong(); - if(amount>0 && !clientModel->inInitialBlockDownload()) + if(!clientModel->inInitialBlockDownload()) { - // On incoming transaction, make an info balloon + // On new transaction, make an info balloon // Unless the initial block download is in progress, to prevent balloon-spam QString date = ttm->index(start, TransactionTableModel::Date, parent) .data().toString(); @@ -404,33 +453,107 @@ void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) .data().toString(); - trayIcon->showMessage(tr("Incoming transaction"), + trayIcon->showMessage((amount)<0 ? tr("Sent transaction") : + tr("Incoming transaction"), tr("Date: ") + date + "\n" + - tr("Amount: ") + GUIUtil::formatMoney(amount, true) + "\n" + + tr("Amount: ") + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true) + "\n" + tr("Type: ") + type + "\n" + tr("Address: ") + address + "\n", QSystemTrayIcon::Information); } } -void BitcoinGUI::gotoOverviewTab() +void BitcoinGUI::gotoOverviewPage() { overviewAction->setChecked(true); centralWidget->setCurrentWidget(overviewPage); + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); } -void BitcoinGUI::gotoHistoryTab() +void BitcoinGUI::gotoHistoryPage() { historyAction->setChecked(true); centralWidget->setCurrentWidget(transactionsPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoAddressBookPage() +{ + addressBookAction->setChecked(true); + centralWidget->setCurrentWidget(addressBookPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoReceiveCoinsPage() +{ + receiveCoinsAction->setChecked(true); + centralWidget->setCurrentWidget(receiveCoinsPage); + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked())); +} + +void BitcoinGUI::gotoSendCoinsPage() +{ + sendCoinsAction->setChecked(true); + if(centralWidget->currentWidget() != sendCoinsPage) + { + // Clear the current contents if we arrived from another tab + sendCoinsPage->clear(); + } + centralWidget->setCurrentWidget(sendCoinsPage); + + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); +} + +void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) +{ + // Accept only URLs + if(event->mimeData()->hasUrls()) + event->acceptProposedAction(); } -void BitcoinGUI::exportClicked() +void BitcoinGUI::dropEvent(QDropEvent *event) { - // Redirect to the right view, as soon as export for other views - // (such as address book) is implemented. - transactionView->exportClicked(); + if(event->mimeData()->hasUrls()) + { + gotoSendCoinsPage(); + QList urls = event->mimeData()->urls(); + foreach(const QUrl &url, urls) + { + sendCoinsPage->handleURL(&url); + } + } + + event->acceptProposedAction(); } +void BitcoinGUI::setEncryptionStatus(int status) +{ + switch(status) + { + case WalletModel::Unencrypted: + labelEncryptionIcon->hide(); + break; + case WalletModel::Unlocked: + labelEncryptionIcon->show(); + labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked")); + break; + case WalletModel::Locked: + labelEncryptionIcon->show(); + labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently locked")); + break; + } +}