4 * W.J. van der Laan 2011
6 #include "bitcoingui.h"
7 #include "transactiontablemodel.h"
8 #include "addressbookdialog.h"
9 #include "sendcoinsdialog.h"
10 #include "optionsdialog.h"
11 #include "aboutdialog.h"
12 #include "clientmodel.h"
13 #include "walletmodel.h"
15 #include "editaddressdialog.h"
16 #include "optionsmodel.h"
17 #include "transactiondescdialog.h"
18 #include "addresstablemodel.h"
19 #include "transactionview.h"
20 #include "overviewpage.h"
22 #include <QApplication>
23 #include <QMainWindow>
28 #include <QVBoxLayout>
33 #include <QPushButton>
35 #include <QMessageBox>
36 #include <QProgressBar>
37 #include <QStackedWidget>
43 BitcoinGUI::BitcoinGUI(QWidget *parent):
50 setWindowTitle(tr("Bitcoin Wallet"));
51 setWindowIcon(QIcon(":icons/bitcoin"));
56 QMenu *file = menuBar()->addMenu("&File");
57 file->addAction(sendCoins);
58 file->addAction(receiveCoins);
60 file->addAction(quit);
62 QMenu *settings = menuBar()->addMenu("&Settings");
63 settings->addAction(options);
65 QMenu *help = menuBar()->addMenu("&Help");
66 help->addAction(about);
69 QToolBar *toolbar = addToolBar("Main toolbar");
70 toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
71 toolbar->addAction(overviewAction);
72 toolbar->addAction(historyAction);
73 toolbar->addSeparator();
74 toolbar->addAction(sendCoins);
75 toolbar->addAction(receiveCoins);
76 toolbar->addAction(addressbook);
78 QToolBar *toolbar2 = addToolBar("Transactions toolbar");
79 toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
80 toolbar2->addAction(exportAction);
83 overviewPage = new OverviewPage();
84 QVBoxLayout *vbox = new QVBoxLayout();
86 transactionView = new TransactionView(this);
87 connect(transactionView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(transactionDetails(const QModelIndex&)));
88 vbox->addWidget(transactionView);
90 transactionsPage = new QWidget(this);
91 transactionsPage->setLayout(vbox);
93 centralWidget = new QStackedWidget(this);
94 centralWidget->addWidget(overviewPage);
95 centralWidget->addWidget(transactionsPage);
96 setCentralWidget(centralWidget);
101 labelConnections = new QLabel();
102 labelConnections->setFrameStyle(QFrame::Panel | QFrame::Sunken);
103 labelConnections->setMinimumWidth(150);
104 labelConnections->setToolTip(tr("Number of connections to other clients"));
106 labelBlocks = new QLabel();
107 labelBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
108 labelBlocks->setMinimumWidth(130);
109 labelBlocks->setToolTip(tr("Number of blocks in the block chain"));
111 // Progress bar for blocks download
112 progressBarLabel = new QLabel(tr("Synchronizing with network..."));
113 progressBarLabel->setVisible(false);
114 progressBar = new QProgressBar();
115 progressBar->setToolTip(tr("Block chain synchronization in progress"));
116 progressBar->setVisible(false);
118 statusBar()->addWidget(progressBarLabel);
119 statusBar()->addWidget(progressBar);
120 statusBar()->addPermanentWidget(labelConnections);
121 statusBar()->addPermanentWidget(labelBlocks);
128 void BitcoinGUI::createActions()
130 QActionGroup *tabGroup = new QActionGroup(this);
131 overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
132 overviewAction->setCheckable(true);
133 tabGroup->addAction(overviewAction);
134 historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
135 historyAction->setCheckable(true);
136 tabGroup->addAction(historyAction);
138 connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewTab()));
139 connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryTab()));
141 quit = new QAction(QIcon(":/icons/quit"), tr("&Exit"), this);
142 quit->setToolTip(tr("Quit application"));
143 sendCoins = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
144 sendCoins->setToolTip(tr("Send coins to a bitcoin address"));
145 addressbook = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
146 addressbook->setToolTip(tr("Edit the list of stored addresses and labels"));
147 about = new QAction(QIcon(":/icons/bitcoin"), tr("&About"), this);
148 about->setToolTip(tr("Show information about Bitcoin"));
149 receiveCoins = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
150 receiveCoins->setToolTip(tr("Show the list of addresses for receiving payments"));
151 options = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
152 options->setToolTip(tr("Modify configuration options for bitcoin"));
153 openBitcoin = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
154 openBitcoin->setToolTip(tr("Show the Bitcoin window"));
155 exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
156 exportAction->setToolTip(tr("Export data in current view to a file"));
158 connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
159 connect(sendCoins, SIGNAL(triggered()), this, SLOT(sendCoinsClicked()));
160 connect(addressbook, SIGNAL(triggered()), this, SLOT(addressbookClicked()));
161 connect(receiveCoins, SIGNAL(triggered()), this, SLOT(receiveCoinsClicked()));
162 connect(options, SIGNAL(triggered()), this, SLOT(optionsClicked()));
163 connect(about, SIGNAL(triggered()), this, SLOT(aboutClicked()));
164 connect(openBitcoin, SIGNAL(triggered()), this, SLOT(show()));
165 connect(exportAction, SIGNAL(triggered()), this, SLOT(exportClicked()));
168 void BitcoinGUI::setClientModel(ClientModel *clientModel)
170 this->clientModel = clientModel;
172 if(clientModel->isTestNet())
174 QString title_testnet = tr("Bitcoin Wallet [testnet]");
175 setWindowTitle(title_testnet);
176 setWindowIcon(QIcon(":icons/bitcoin_testnet"));
179 trayIcon->setToolTip(title_testnet);
180 trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
184 // Keep up to date with client
185 setNumConnections(clientModel->getNumConnections());
186 connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
188 setNumBlocks(clientModel->getNumBlocks());
189 connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
191 // Report errors from network/worker thread
192 connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
195 void BitcoinGUI::setWalletModel(WalletModel *walletModel)
197 this->walletModel = walletModel;
199 // Keep up to date with wallet
200 setBalance(walletModel->getBalance());
201 connect(walletModel, SIGNAL(balanceChanged(qint64)), this, SLOT(setBalance(qint64)));
203 setNumTransactions(walletModel->getNumTransactions());
204 connect(walletModel, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
206 // Report errors from wallet thread
207 connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
209 // Put transaction list in tabs
210 transactionView->setModel(walletModel->getTransactionTableModel());
212 // Balloon popup for new transaction
213 connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
214 this, SLOT(incomingTransaction(const QModelIndex &, int, int)));
217 void BitcoinGUI::createTrayIcon()
219 QMenu *trayIconMenu = new QMenu(this);
220 trayIconMenu->addAction(openBitcoin);
221 trayIconMenu->addAction(sendCoins);
222 trayIconMenu->addAction(options);
223 trayIconMenu->addSeparator();
224 trayIconMenu->addAction(quit);
226 trayIcon = new QSystemTrayIcon(this);
227 trayIcon->setContextMenu(trayIconMenu);
228 trayIcon->setToolTip("Bitcoin client");
229 trayIcon->setIcon(QIcon(":/icons/toolbar"));
230 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
231 this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
235 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
237 if(reason == QSystemTrayIcon::DoubleClick)
239 // Doubleclick on system tray icon triggers "open bitcoin"
240 openBitcoin->trigger();
244 void BitcoinGUI::sendCoinsClicked()
247 dlg.setModel(walletModel);
251 void BitcoinGUI::addressbookClicked()
253 AddressBookDialog dlg(AddressBookDialog::ForEditing);
254 dlg.setModel(walletModel->getAddressTableModel());
255 dlg.setTab(AddressBookDialog::SendingTab);
259 void BitcoinGUI::receiveCoinsClicked()
261 AddressBookDialog dlg(AddressBookDialog::ForEditing);
262 dlg.setModel(walletModel->getAddressTableModel());
263 dlg.setTab(AddressBookDialog::ReceivingTab);
267 void BitcoinGUI::optionsClicked()
270 dlg.setModel(clientModel->getOptionsModel());
274 void BitcoinGUI::aboutClicked()
277 dlg.setModel(clientModel);
281 void BitcoinGUI::setBalance(qint64 balance)
283 overviewPage->setBalance(balance);
286 void BitcoinGUI::setNumConnections(int count)
291 case 0: icon = ":/icons/connect_0"; break;
292 case 1: case 2: case 3: icon = ":/icons/connect_1"; break;
293 case 4: case 5: case 6: icon = ":/icons/connect_2"; break;
294 case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
295 default: icon = ":/icons/connect_4"; break;
297 labelConnections->setTextFormat(Qt::RichText);
298 labelConnections->setText("<img src=\""+icon+"\"> " + tr("%n connection(s)", "", count));
301 void BitcoinGUI::setNumBlocks(int count)
303 int total = clientModel->getTotalBlocksEstimate();
306 progressBarLabel->setVisible(true);
307 progressBar->setVisible(true);
308 progressBar->setMaximum(total);
309 progressBar->setValue(count);
313 progressBarLabel->setVisible(false);
314 progressBar->setVisible(false);
317 labelBlocks->setText(tr("%n block(s)", "", count));
320 void BitcoinGUI::setNumTransactions(int count)
322 overviewPage->setNumTransactions(count);
325 void BitcoinGUI::error(const QString &title, const QString &message)
327 // Report errors from network/worker thread
328 if(trayIcon->supportsMessages())
330 // Show as "balloon" message if possible
331 trayIcon->showMessage(title, message, QSystemTrayIcon::Critical);
335 // Fall back to old fashioned popup dialog if not
336 QMessageBox::critical(this, title,
338 QMessageBox::Ok, QMessageBox::Ok);
342 void BitcoinGUI::changeEvent(QEvent *e)
344 if (e->type() == QEvent::WindowStateChange)
346 if(clientModel->getOptionsModel()->getMinimizeToTray())
359 QMainWindow::changeEvent(e);
362 void BitcoinGUI::closeEvent(QCloseEvent *event)
364 if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
365 !clientModel->getOptionsModel()->getMinimizeOnClose())
369 QMainWindow::closeEvent(event);
372 void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
375 tr("This transaction is over the size limit. You can still send it for a fee of %1, "
376 "which goes to the nodes that process your transaction and helps to support the network. "
377 "Do you want to pay the fee?").arg(GUIUtil::formatMoney(nFeeRequired));
378 QMessageBox::StandardButton retval = QMessageBox::question(
379 this, tr("Sending..."), strMessage,
380 QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
381 *payFee = (retval == QMessageBox::Yes);
384 void BitcoinGUI::transactionDetails(const QModelIndex& idx)
386 // A transaction is doubleclicked
387 TransactionDescDialog dlg(idx);
391 void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
393 TransactionTableModel *ttm = walletModel->getTransactionTableModel();
394 qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
395 .data(Qt::EditRole).toULongLong();
396 if(amount>0 && !clientModel->inInitialBlockDownload())
398 // On incoming transaction, make an info balloon
399 // Unless the initial block download is in progress, to prevent balloon-spam
400 QString date = ttm->index(start, TransactionTableModel::Date, parent)
402 QString type = ttm->index(start, TransactionTableModel::Type, parent)
404 QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
407 trayIcon->showMessage(tr("Incoming transaction"),
408 tr("Date: ") + date + "\n" +
409 tr("Amount: ") + GUIUtil::formatMoney(amount, true) + "\n" +
410 tr("Type: ") + type + "\n" +
411 tr("Address: ") + address + "\n",
412 QSystemTrayIcon::Information);
416 void BitcoinGUI::gotoOverviewTab()
418 overviewAction->setChecked(true);
419 centralWidget->setCurrentWidget(overviewPage);
420 exportAction->setEnabled(false);
423 void BitcoinGUI::gotoHistoryTab()
425 historyAction->setChecked(true);
426 centralWidget->setCurrentWidget(transactionsPage);
427 exportAction->setEnabled(true);
430 void BitcoinGUI::exportClicked()
432 // Redirect to the right view, as soon as export for other views
433 // (such as address book) is implemented.
434 transactionView->exportClicked();