diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | bitcoin-qt.pro | 12 | ||||
-rw-r--r-- | multiwallet-qt.txt | 53 | ||||
-rw-r--r-- | src/init.cpp | 9 | ||||
-rw-r--r-- | src/qt/addressbookpage.cpp | 16 | ||||
-rw-r--r-- | src/qt/addressbookpage.h | 3 | ||||
-rw-r--r-- | src/qt/askpassphrasedialog.cpp | 2 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 5 | ||||
-rw-r--r-- | src/qt/bitcoinamountfield.cpp | 5 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 300 | ||||
-rw-r--r-- | src/qt/bitcoingui.h | 42 | ||||
-rw-r--r-- | src/qt/bitcoinstrings.cpp | 10 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 2 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 241 | ||||
-rw-r--r-- | src/qt/res/bitcoin-qt.rc | 2 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 20 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.h | 1 | ||||
-rw-r--r-- | src/qt/sendcoinsentry.cpp | 6 | ||||
-rw-r--r-- | src/qt/sendcoinsentry.h | 1 | ||||
-rw-r--r-- | src/qt/transactionview.cpp | 8 | ||||
-rw-r--r-- | src/qt/transactionview.h | 1 | ||||
-rw-r--r-- | src/qt/walletframe.cpp | 129 | ||||
-rw-r--r-- | src/qt/walletframe.h | 73 | ||||
-rw-r--r-- | src/qt/walletstack.cpp | 155 | ||||
-rw-r--r-- | src/qt/walletstack.h | 102 | ||||
-rw-r--r-- | src/qt/walletview.cpp | 354 | ||||
-rw-r--r-- | src/qt/walletview.h | 132 |
27 files changed, 1335 insertions, 351 deletions
@@ -3,7 +3,7 @@ Bitcoin integration/staging tree http://www.bitcoin.org -Copyright (c) 2009-2012 Bitcoin Developers +Copyright (c) 2009-2013 Bitcoin Developers What is Bitcoin? ---------------- diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 5042adfbdf..d518cf3b16 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -30,10 +30,8 @@ contains(RELEASE, 1) { macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk !win32:!macx { - # Linux: static link + # Linux: static link and extra security (see: https://wiki.debian.org/Hardening) LIBS += -Wl,-Bstatic -Wl,-z,relro -Wl,-z,now - # for extra security (see: https://wiki.debian.org/Hardening) - QMAKE_CXXFLAGS *= -D_FORTIFY_SOURCE=2 } } @@ -44,6 +42,8 @@ contains(RELEASE, 1) { # Exclude on Windows cross compile with MinGW 4.2.x, as it will result in a non-working executable! # This can be enabled for Windows, when we switch to MinGW >= 4.4.x. } +# for extra security (see: https://wiki.debian.org/Hardening): this flag is GCC compiler-specific +QMAKE_CXXFLAGS *= -D_FORTIFY_SOURCE=2 # for extra security on Windows: enable ASLR and DEP via GCC linker flags win32:QMAKE_LFLAGS *= -Wl,--dynamicbase -Wl,--nxcompat # on Windows: enable GCC large address aware linker flag @@ -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 0000000000..8394080db0 --- /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/init.cpp b/src/init.cpp index b61d1b9358..7c72982dd2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -609,13 +609,11 @@ bool AppInit2() // ********************************************************* Step 5: verify wallet database integrity - uiInterface.InitMessage(_("Verifying wallet integrity...")); + uiInterface.InitMessage(_("Verifying wallet...")); if (!bitdb.Open(GetDataDir())) { - string msg = strprintf(_("Error initializing database environment %s!" - " To recover, BACKUP THAT DIRECTORY, then remove" - " everything from it except for wallet.dat."), strDataDir.c_str()); + string msg = strprintf(_("Error initializing wallet database environment %s!"), strDataDir.c_str()); return InitError(msg); } @@ -827,7 +825,7 @@ bool AppInit2() break; } - uiInterface.InitMessage(_("Verifying database...")); + uiInterface.InitMessage(_("Verifying blocks...")); if (!VerifyDB()) { strLoadError = _("Corrupted block database detected"); break; @@ -986,7 +984,6 @@ bool AppInit2() // ********************************************************* Step 9: import blocks // scan for better chains in the block chain database, that are not yet connected in the active best chain - uiInterface.InitMessage(_("Importing blocks from block database...")); CValidationState state; if (!ConnectBestBlock(state)) strErrors << "Failed to connect best block"; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index b53a37fc22..9e35e51bbf 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -65,6 +65,7 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : QAction *copyAddressAction = new QAction(ui->copyToClipboard->text(), this); QAction *copyLabelAction = new QAction(tr("Copy &Label"), this); QAction *editAction = new QAction(tr("&Edit"), this); + QAction *sendCoinsAction = new QAction(tr("Send &Coins"), this); QAction *showQRCodeAction = new QAction(ui->showQRCode->text(), this); QAction *signMessageAction = new QAction(ui->signMessage->text(), this); QAction *verifyMessageAction = new QAction(ui->verifyMessage->text(), this); @@ -78,6 +79,8 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : if(tab == SendingTab) contextMenu->addAction(deleteAction); contextMenu->addSeparator(); + if(tab == SendingTab) + contextMenu->addAction(sendCoinsAction); #ifdef USE_QRCODE contextMenu->addAction(showQRCodeAction); #endif @@ -91,6 +94,7 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction())); connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction())); connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(onSendCoins_clicked())); connect(showQRCodeAction, SIGNAL(triggered()), this, SLOT(on_showQRCode_clicked())); connect(signMessageAction, SIGNAL(triggered()), this, SLOT(on_signMessage_clicked())); connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(on_verifyMessage_clicked())); @@ -206,6 +210,18 @@ void AddressBookPage::on_verifyMessage_clicked() } } +void AddressBookPage::onSendCoins_clicked() +{ + QTableView *table = ui->tableView; + QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); + + foreach (QModelIndex index, indexes) + { + QString address = index.data().toString(); + emit sendCoins(address); + } +} + void AddressBookPage::on_newAddressButton_clicked() { if(!model) diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index c676d1e941..c6653a5e8a 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -68,6 +68,8 @@ private slots: void on_signMessage_clicked(); /** Open the verify message tab in the Sign/Verify Message dialog with currently selected address */ void on_verifyMessage_clicked(); + /** Open send coins dialog for currently selected address (no button) */ + void onSendCoins_clicked(); /** Generate a QR Code from the currently selected address */ void on_showQRCode_clicked(); /** Copy label of currently selected address entry to clipboard (no button) */ @@ -85,6 +87,7 @@ private slots: signals: void signMessage(QString addr); void verifyMessage(QString addr); + void sendCoins(QString addr); }; #endif // ADDRESSBOOKPAGE_H diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index cf35ee2457..f165c11cb1 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -235,7 +235,7 @@ bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event) if (str.length() != 0) { const QChar *psz = str.unicode(); bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0; - if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) { + if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) { fCapsLock = true; ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); } else if (psz->isLetter()) { diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e3d51be54a..346128c0c4 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/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index ddf185c415..4fa2ca508b 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -145,6 +145,11 @@ void BitcoinAmountField::unitChanged(int idx) amount->setDecimals(BitcoinUnits::decimals(currentUnit)); amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals())); + if(currentUnit == BitcoinUnits::uBTC) + amount->setSingleStep(0.01); + else + amount->setSingleStep(0.001); + if(valid) { // If value was valid, re-place it in the widget with the new unit diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 4f97a4815f..eff8e667f6 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,17 @@ #include <QUrl> #include <QMimeData> #include <QStyle> +#include <QSettings> +#include <QDesktopWidget> +#include <QListWidget> #include <iostream> +const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; + BitcoinGUI::BitcoinGUI(QWidget *parent): QMainWindow(parent), clientModel(0), - walletModel(0), encryptWalletAction(0), changePassphraseAction(0), aboutQtAction(0), @@ -69,7 +67,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): rpcConsole(0), prevBlocks(0) { - resize(850, 550); + restoreWindowGeometry(); setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet")); #ifndef Q_OS_MAC qApp->setWindowIcon(QIcon(":icons/bitcoin")); @@ -93,31 +91,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,29 +139,16 @@ 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 "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))); - // Install event filter to be able to catch status tip events (QEvent::StatusTip) this->installEventFilter(this); - - gotoOverviewPage(); } BitcoinGUI::~BitcoinGUI() { + saveWindowGeometry(); if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) trayIcon->hide(); #ifdef Q_OS_MAC @@ -241,7 +205,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)); @@ -375,39 +339,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() @@ -466,6 +414,28 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) } #endif +void BitcoinGUI::saveWindowGeometry() +{ + QSettings settings; + settings.setValue("nWindowPos", pos()); + settings.setValue("nWindowSize", size()); +} + +void BitcoinGUI::restoreWindowGeometry() +{ + QSettings settings; + QPoint pos = settings.value("nWindowPos").toPoint(); + QSize size = settings.value("nWindowSize", QSize(850, 550)).toSize(); + if (!pos.x() && !pos.y()) + { + QRect screen = qApp->desktop()->screenGeometry(); + pos.setX((screen.width()-size.width())/2); + pos.setY((screen.height()-size.height())/2); + } + resize(size); + move(pos); +} + void BitcoinGUI::optionsClicked() { if(!clientModel || !clientModel->getOptionsModel()) @@ -482,6 +452,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; @@ -546,7 +551,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) tooltip = tr("Up to date") + QString(".<br>") + tooltip; labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); - overviewPage->showOutOfSyncWarning(false); + walletFrame->showOutOfSyncWarning(false); progressBarLabel->setVisible(false); progressBar->setVisible(false); @@ -581,7 +586,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks) syncIconMovie->jumpToNextFrame(); prevBlocks = count; - overviewPage->showOutOfSyncWarning(true); + walletFrame->showOutOfSyncWarning(true); tooltip += QString("<br>"); tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText); @@ -690,101 +695,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() -{ - sendCoinsAction->setChecked(true); - centralWidget->setCurrentWidget(sendCoinsPage); - - exportAction->setEnabled(false); - disconnect(exportAction, SIGNAL(triggered()), 0, 0); -} - -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 @@ -800,13 +724,13 @@ void BitcoinGUI::dropEvent(QDropEvent *event) QList<QUrl> 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); @@ -830,12 +754,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); } @@ -871,49 +790,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 b992bfdc69..750e97104c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -3,10 +3,14 @@ #include <QMainWindow> #include <QSystemTrayIcon> +#include <QMap> 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; @@ -108,6 +114,10 @@ private: void createTrayIcon(); /** Create system tray menu (or setup the dock menu) */ void createTrayIconMenu(); + /** Save window size and position */ + void saveWindowGeometry(); + /** Restore window size and position */ + void restoreWindowGeometry(); public slots: /** Set number of connections shown in the UI */ @@ -139,6 +149,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(); @@ -164,11 +177,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/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 2c3d859c82..dc506f0497 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -31,8 +31,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. Bitcoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Corrupted block database detected. Please restart the client with -reindex."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Error initializing database environment %s! To recover, BACKUP THAT " "DIRECTORY, then remove everything from it except for wallet.dat."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -43,6 +41,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: This transaction requires a transaction fee of at least %s because of " "its amount, complexity, or use of recently received funds!"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Execute command when a wallet transaction changes (%s in cmd is replaced by " +"TxID)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Execute command when the best block changes (%s in cmd is replaced by block " "hash)"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -97,7 +98,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write default address"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect through socks proxy"), QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses, and disconnect"), +QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), @@ -105,6 +108,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed!"), @@ -190,7 +194,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"), QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"), QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"), -QT_TRANSLATE_NOOP("bitcoin-core", "Verifying block database integrity..."), +QT_TRANSLATE_NOOP("bitcoin-core", "Verifying database..."), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet integrity..."), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning"), diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 30ad8ef66b..06ccde3782 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -161,7 +161,7 @@ void copyEntryData(QAbstractItemView *view, int column, int role) if(!selection.isEmpty()) { // Copy first item - QApplication::clipboard()->setText(selection.at(0).data(role).toString()); + QApplication::clipboard()->setText(selection.at(0).data(role).toString(),QClipboard::Selection); } } diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 39062d0a2c..e05c018c27 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -414,16 +414,8 @@ This product includes software developed by the OpenSSL Project for use in the O <source>Reindexing blocks on disk...</source> <translation>Reindexing blocks on disk...</translation> </message> - <message numerus="yes"> - <location line="+10"/> - <source>~%n block(s) remaining</source> - <translation> - <numerusform>~%n block remaining</numerusform> - <numerusform>~%n blocks remaining</numerusform> - </translation> - </message> <message> - <location line="-265"/> + <location line="-255"/> <source>&Export...</source> <translation>&Export...</translation> </message> @@ -469,12 +461,12 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <location line="-196"/> - <location line="+538"/> + <location line="+529"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-538"/> + <location line="-529"/> <source>Wallet</source> <translation>Wallet</translation> </message> @@ -553,17 +545,56 @@ This product includes software developed by the OpenSSL Project for use in the O </translation> </message> <message> - <location line="+45"/> - <source>Processed %1 of %2 blocks of transaction history (%3% done).</source> - <translation>Processed %1 of %2 blocks of transaction history (%3% done).</translation> + <location line="+39"/> + <source>Processed %1 of %2 (estimated) blocks of transaction history.</source> + <translation>Processed %1 of %2 (estimated) blocks of transaction history.</translation> </message> <message> - <location line="+7"/> + <location line="+4"/> <source>Processed %1 blocks of transaction history.</source> <translation>Processed %1 blocks of transaction history.</translation> </message> + <message numerus="yes"> + <location line="+20"/> + <source>%n hour(s)</source> + <translation> + <numerusform>%n hour</numerusform> + <numerusform>%n hours</numerusform> + </translation> + </message> + <message numerus="yes"> + <location line="+4"/> + <source>%n day(s)</source> + <translation> + <numerusform>%n day</numerusform> + <numerusform>%n days</numerusform> + </translation> + </message> + <message numerus="yes"> + <location line="+4"/> + <source>%n week(s)</source> + <translation> + <numerusform>%n week</numerusform> + <numerusform>%n weeks</numerusform> + </translation> + </message> <message> - <location line="+70"/> + <location line="+5"/> + <source>%1 behind</source> + <translation>%1 behind</translation> + </message> + <message> + <location line="+14"/> + <source>Last received block was generated %1 ago.</source> + <translation>Last received block was generated %1 ago.</translation> + </message> + <message> + <location line="+2"/> + <source>Transactions after this will not yet be visible.</source> + <translation>Transactions after this will not yet be visible.</translation> + </message> + <message> + <location line="+21"/> <source>Error</source> <translation>Error</translation> </message> @@ -578,7 +609,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Information</translation> </message> <message> - <location line="+66"/> + <location line="+68"/> <source>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?</source> <translation>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?</translation> </message> @@ -592,55 +623,18 @@ This product includes software developed by the OpenSSL Project for use in the O <source>The wallet data was successfully saved to the new location.</source> <translation>The wallet data was successfully saved to the new location.</translation> </message> - <message numerus="yes"> - <location line="-338"/> - <source>%n second(s) ago</source> - <translation> - <numerusform>%n second ago</numerusform> - <numerusform>%n seconds ago</numerusform> - </translation> - </message> - <message numerus="yes"> - <location line="+4"/> - <source>%n minute(s) ago</source> - <translation> - <numerusform>%n minute ago</numerusform> - <numerusform>%n minutes ago</numerusform> - </translation> - </message> - <message numerus="yes"> - <location line="+4"/> - <source>%n hour(s) ago</source> - <translation> - <numerusform>%n hour ago</numerusform> - <numerusform>%n hours ago</numerusform> - </translation> - </message> - <message numerus="yes"> - <location line="+4"/> - <source>%n day(s) ago</source> - <translation> - <numerusform>%n day ago</numerusform> - <numerusform>%n days ago</numerusform> - </translation> - </message> <message> - <location line="+6"/> + <location line="-348"/> <source>Up to date</source> <translation>Up to date</translation> </message> <message> - <location line="+7"/> + <location line="+32"/> <source>Catching up...</source> <translation>Catching up...</translation> </message> <message> - <location line="+10"/> - <source>Last received block was generated %1.</source> - <translation>Last received block was generated %1.</translation> - </message> - <message> - <location line="+97"/> + <location line="+110"/> <source>Confirm transaction fee</source> <translation>Confirm transaction fee</translation> </message> @@ -710,7 +704,7 @@ Address: %4 <translation>There was an error trying to save the wallet data to the new location.</translation> </message> <message> - <location filename="../bitcoin.cpp" line="+110"/> + <location filename="../bitcoin.cpp" line="+108"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</translation> </message> @@ -718,7 +712,7 @@ Address: %4 <context> <name>ClientModel</name> <message> - <location filename="../clientmodel.cpp" line="+89"/> + <location filename="../clientmodel.cpp" line="+96"/> <source>Network Alert</source> <translation>Network Alert</translation> </message> @@ -751,7 +745,7 @@ Address: %4 <translation>The address associated with this address book entry. This can only be modified for sending addresses.</translation> </message> <message> - <location filename="../editaddressdialog.cpp" line="+20"/> + <location filename="../editaddressdialog.cpp" line="+21"/> <source>New receiving address</source> <translation>New receiving address</translation> </message> @@ -794,7 +788,7 @@ Address: %4 <context> <name>GUIUtil::HelpMessageBox</name> <message> - <location filename="../guiutil.cpp" line="+420"/> + <location filename="../guiutil.cpp" line="+422"/> <location line="+12"/> <source>Bitcoin-Qt</source> <translation>Bitcoin-Qt</translation> @@ -1008,7 +1002,7 @@ Address: %4 <translation>&Apply</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+55"/> + <location filename="../optionsdialog.cpp" line="+53"/> <source>default</source> <translation>default</translation> </message> @@ -1116,6 +1110,14 @@ Address: %4 </message> </context> <context> + <name>PaymentServer</name> + <message> + <location filename="../paymentserver.cpp" line="+107"/> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> + </message> +</context> +<context> <name>QRCodeDialog</name> <message> <location filename="../forms/qrcodedialog.ui" line="+14"/> @@ -1454,7 +1456,7 @@ Address: %4 </message> <message> <location line="+60"/> - <location filename="../sendcoinsentry.cpp" line="+25"/> + <location filename="../sendcoinsentry.cpp" line="+26"/> <source>Enter a label for this address to add it to your address book</source> <translation>Enter a label for this address to add it to your address book</translation> </message> @@ -1690,7 +1692,7 @@ Address: %4 <context> <name>TransactionDesc</name> <message> - <location filename="../transactiondesc.cpp" line="+19"/> + <location filename="../transactiondesc.cpp" line="+20"/> <source>Open until %1</source> <translation>Open until %1</translation> </message> @@ -1886,7 +1888,7 @@ Address: %4 <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+226"/> + <location filename="../transactiontablemodel.cpp" line="+225"/> <source>Date</source> <translation>Date</translation> </message> @@ -2010,7 +2012,7 @@ Address: %4 <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+55"/> + <location filename="../transactionview.cpp" line="+52"/> <location line="+16"/> <source>All</source> <translation>All</translation> @@ -2106,7 +2108,7 @@ Address: %4 <translation>Show transaction details</translation> </message> <message> - <location line="+142"/> + <location line="+137"/> <source>Export Transaction Data</source> <translation>Export Transaction Data</translation> </message> @@ -2174,12 +2176,12 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+90"/> + <location filename="../bitcoinstrings.cpp" line="+91"/> <source>Bitcoin version</source> <translation>Bitcoin version</translation> </message> <message> - <location line="+96"/> + <location line="+99"/> <source>Usage:</source> <translation>Usage:</translation> </message> @@ -2219,12 +2221,12 @@ Address: %4 <translation>Generate coins</translation> </message> <message> - <location line="-27"/> + <location line="-28"/> <source>Don't generate coins</source> <translation>Don't generate coins</translation> </message> <message> - <location line="+74"/> + <location line="+75"/> <source>Specify data directory</source> <translation>Specify data directory</translation> </message> @@ -2244,12 +2246,12 @@ Address: %4 <translation>Maintain at most <n> connections to peers (default: 125)</translation> </message> <message> - <location line="-47"/> + <location line="-50"/> <source>Connect to a node to retrieve peer addresses, and disconnect</source> <translation>Connect to a node to retrieve peer addresses, and disconnect</translation> </message> <message> - <location line="+78"/> + <location line="+81"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> @@ -2259,17 +2261,17 @@ Address: %4 <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-130"/> + <location line="-133"/> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation> </message> <message> - <location line="-28"/> + <location line="-29"/> <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> <translation>An error occurred while setting up the RPC port %u for listening on IPv4: %s</translation> </message> <message> - <location line="+26"/> + <location line="+27"/> <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> <translation>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</translation> </message> @@ -2279,7 +2281,7 @@ Address: %4 <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+75"/> + <location line="+78"/> <source>Run in the background as a daemon and accept commands</source> <translation>Run in the background as a daemon and accept commands</translation> </message> @@ -2289,12 +2291,12 @@ Address: %4 <translation>Use the test network</translation> </message> <message> - <location line="-106"/> + <location line="-109"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> <message> - <location line="-76"/> + <location line="-77"/> <source>%s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2330,11 +2332,6 @@ If the file does not exist, create it with owner-readable-only file permissions. </message> <message> <location line="+3"/> - <source>Corrupted block database detected. Please restart the client with -reindex.</source> - <translation>Corrupted block database detected. Please restart the client with -reindex.</translation> - </message> - <message> - <location line="+2"/> <source>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</source> <translation>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</translation> </message> @@ -2349,6 +2346,11 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</translation> </message> <message> + <location line="+3"/> + <source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source> + <translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation> + </message> + <message> <location line="+11"/> <source>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</source> <translation>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</translation> @@ -2405,10 +2407,20 @@ If the file does not exist, create it with owner-readable-only file permissions. </message> <message> <location line="+3"/> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <location line="+1"/> <source>Discover own IP address (default: 1 when listening and no -externalip)</source> <translation>Discover own IP address (default: 1 when listening and no -externalip)</translation> </message> <message> + <location line="+1"/> + <source>Do you want to rebuild the block database now?</source> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> <location line="+3"/> <source>Error initializing block database</source> <translation>Error initializing block database</translation> @@ -2419,7 +2431,12 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Error loading block database</translation> </message> <message> - <location line="+5"/> + <location line="+4"/> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <location line="+2"/> <source>Error: Disk space is low!</source> <translation>Error: Disk space is low!</translation> </message> @@ -2639,7 +2656,12 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Username for JSON-RPC connections</translation> </message> <message> - <location line="+4"/> + <location line="+1"/> + <source>Verifying database...</source> + <translation>Verifying database...</translation> + </message> + <message> + <location line="+3"/> <source>Warning</source> <translation>Warning</translation> </message> @@ -2664,22 +2686,22 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-66"/> + <location line="-69"/> <source>Allow JSON-RPC connections from specified IP address</source> <translation>Allow JSON-RPC connections from specified IP address</translation> </message> <message> - <location line="+75"/> + <location line="+78"/> <source>Send commands to node running on <ip> (default: 127.0.0.1)</source> <translation>Send commands to node running on <ip> (default: 127.0.0.1)</translation> </message> <message> - <location line="-118"/> + <location line="-121"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+140"/> + <location line="+143"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> @@ -2709,12 +2731,12 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="-148"/> + <location line="-152"/> <source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source> <translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation> </message> <message> - <location line="+160"/> + <location line="+164"/> <source>This help message</source> <translation>This help message</translation> </message> @@ -2724,7 +2746,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation> </message> <message> - <location line="-84"/> + <location line="-87"/> <source>Connect through socks proxy</source> <translation>Connect through socks proxy</translation> </message> @@ -2734,12 +2756,12 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+55"/> + <location line="+58"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> <message> - <location line="-36"/> + <location line="-37"/> <source>Error loading wallet.dat: Wallet corrupted</source> <translation>Error loading wallet.dat: Wallet corrupted</translation> </message> @@ -2749,12 +2771,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Error loading wallet.dat: Wallet requires newer version of Bitcoin</translation> </message> <message> - <location line="+86"/> - <source>Verifying block database integrity...</source> - <translation>Verifying block database integrity...</translation> - </message> - <message> - <location line="+1"/> + <location line="+88"/> <source>Verifying wallet integrity...</source> <translation>Verifying wallet integrity...</translation> </message> @@ -2764,12 +2781,12 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Wallet needed to be rewritten: restart Bitcoin to complete</translation> </message> <message> - <location line="-90"/> + <location line="-91"/> <source>Error loading wallet.dat</source> <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+31"/> + <location line="+32"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -2784,7 +2801,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Unknown -socks proxy version requested: %i</translation> </message> <message> - <location line="-89"/> + <location line="-92"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -2794,7 +2811,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+43"/> + <location line="+46"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> @@ -2819,7 +2836,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Loading block index...</translation> </message> <message> - <location line="-57"/> + <location line="-60"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> @@ -2829,7 +2846,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation> </message> <message> - <location line="+66"/> + <location line="+69"/> <source>Find peers using internet relay chat (default: 0)</source> <translation>Find peers using internet relay chat (default: 0)</translation> </message> @@ -2844,7 +2861,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Loading wallet...</translation> </message> <message> - <location line="-52"/> + <location line="-55"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -2859,17 +2876,17 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Cannot write default address</translation> </message> <message> - <location line="+62"/> + <location line="+65"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-56"/> + <location line="-57"/> <source>Done loading</source> <translation>Done loading</translation> </message> <message> - <location line="+79"/> + <location line="+80"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> @@ -2879,7 +2896,7 @@ If the file does not exist, create it with owner-readable-only file permissions. <translation>Error</translation> </message> <message> - <location line="-29"/> + <location line="-32"/> <source>You must set rpcpassword=<password> in the configuration file: %s If the file does not exist, create it with owner-readable-only file permissions.</source> diff --git a/src/qt/res/bitcoin-qt.rc b/src/qt/res/bitcoin-qt.rc index 834001c0c6..5449ff8359 100644 --- a/src/qt/res/bitcoin-qt.rc +++ b/src/qt/res/bitcoin-qt.rc @@ -22,7 +22,7 @@ BEGIN VALUE "FileDescription", "Bitcoin-Qt (OSS GUI client for Bitcoin)" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "bitcoin-qt" - VALUE "LegalCopyright", "2009-2012 The Bitcoin developers" + VALUE "LegalCopyright", "2009-2013 The Bitcoin developers" VALUE "LegalTrademarks1", "Distributed under the MIT/X11 software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php." VALUE "OriginalFilename", "bitcoin-qt.exe" VALUE "ProductName", "Bitcoin-Qt" diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 56392f96dd..2133a5e729 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -245,6 +245,26 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev) return ui->sendButton; } +void SendCoinsDialog::setAddress(const QString &address) +{ + SendCoinsEntry *entry = 0; + // Replace the first entry if it is still unused + if(ui->entries->count() == 1) + { + SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget()); + if(first->isClear()) + { + entry = first; + } + } + if(!entry) + { + entry = addEntry(); + } + + entry->setAddress(address); +} + void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) { if(!fNewRecipientAllowed) diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 8a6e050c11..043dfdcb40 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -29,6 +29,7 @@ public: */ QWidget *setupTabChain(QWidget *prev); + void setAddress(const QString &address); void pasteEntry(const SendCoinsRecipient &rv); bool handleURI(const QString &uri); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 7dbca24084..876b7f808b 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -153,6 +153,12 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) ui->payAmount->setValue(value.amount); } +void SendCoinsEntry::setAddress(const QString &address) +{ + ui->payTo->setText(address); + ui->payAmount->setFocus(); +} + bool SendCoinsEntry::isClear() { return ui->payTo->text().isEmpty(); diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index 0ac14c1472..ec5f3410c1 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -26,6 +26,7 @@ public: bool isClear(); void setValue(const SendCoinsRecipient &value); + void setAddress(const QString &address); /** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://bugreports.qt-project.org/browse/QTBUG-10907). */ diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index e7c384161c..9240b71c71 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -123,6 +123,7 @@ TransactionView::TransactionView(QWidget *parent) : QAction *copyAddressAction = new QAction(tr("Copy address"), this); QAction *copyLabelAction = new QAction(tr("Copy label"), this); QAction *copyAmountAction = new QAction(tr("Copy amount"), this); + QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); @@ -130,6 +131,7 @@ TransactionView::TransactionView(QWidget *parent) : contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); + contextMenu->addAction(copyTxIDAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); @@ -145,6 +147,7 @@ TransactionView::TransactionView(QWidget *parent) : connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); + connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } @@ -309,6 +312,11 @@ void TransactionView::copyAmount() GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole); } +void TransactionView::copyTxID() +{ + GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole); +} + void TransactionView::editLabel() { if(!transactionView->selectionModel() ||!model) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index e61515fdae..bb41a83e32 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -66,6 +66,7 @@ private slots: void editLabel(); void copyLabel(); void copyAmount(); + void copyTxID(); signals: void doubleClicked(const QModelIndex&); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp new file mode 100644 index 0000000000..a53aa65466 --- /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 <QVBoxLayout> +#include <QMessageBox> + +#include <stdio.h> + +WalletFrame::WalletFrame(BitcoinGUI *_gui) : + QFrame(_gui), + gui(_gui), + clientModel(0) +{ + // Leave HBox hook for adding a list view later + QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); + walletStack = new WalletStack(this); + walletStack->setBitcoinGUI(gui); + walletFrameLayout->addWidget(walletStack); +} + +WalletFrame::~WalletFrame() +{ +} + +void WalletFrame::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + walletStack->setClientModel(clientModel); +} + +bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) +{ + return walletStack->addWallet(name, walletModel); +} + +bool WalletFrame::setCurrentWallet(const QString& name) +{ + // TODO: Check if valid name + walletStack->setCurrentWallet(name); + return true; +} + +void WalletFrame::removeAllWallets() +{ + walletStack->removeAllWallets(); +} + +bool WalletFrame::handleURI(const QString &uri) +{ + return walletStack->handleURI(uri); +} + +void WalletFrame::showOutOfSyncWarning(bool fShow) +{ + if (!walletStack) { + QMessageBox box; + box.setText("walletStack is null"); + box.exec(); + return; + } + walletStack->showOutOfSyncWarning(fShow); +} + +void WalletFrame::gotoOverviewPage() +{ + walletStack->gotoOverviewPage(); +} + +void WalletFrame::gotoHistoryPage() +{ + walletStack->gotoHistoryPage(); +} + +void WalletFrame::gotoAddressBookPage() +{ + walletStack->gotoAddressBookPage(); +} + +void WalletFrame::gotoReceiveCoinsPage() +{ + walletStack->gotoReceiveCoinsPage(); +} + +void WalletFrame::gotoSendCoinsPage() +{ + walletStack->gotoSendCoinsPage(); +} + +void WalletFrame::gotoSignMessageTab(QString addr) +{ + walletStack->gotoSignMessageTab(addr); +} + +void WalletFrame::gotoVerifyMessageTab(QString addr) +{ + walletStack->gotoSignMessageTab(addr); +} + +void WalletFrame::encryptWallet(bool status) +{ + walletStack->encryptWallet(status); +} + +void WalletFrame::backupWallet() +{ + walletStack->backupWallet(); +} + +void WalletFrame::changePassphrase() +{ + walletStack->changePassphrase(); +} + +void WalletFrame::unlockWallet() +{ + walletStack->unlockWallet(); +} + +void WalletFrame::setEncryptionStatus() +{ + walletStack->setEncryptionStatus(); +} diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h new file mode 100644 index 0000000000..5b4baf7255 --- /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 <QFrame> + +class BitcoinGUI; +class ClientModel; +class WalletModel; +class WalletStack; + +class WalletFrame : public QFrame +{ + Q_OBJECT +public: + explicit WalletFrame(BitcoinGUI *_gui); + ~WalletFrame(); + + void setClientModel(ClientModel *clientModel); + + bool addWallet(const QString& name, WalletModel *walletModel); + bool setCurrentWallet(const QString& name); + + void removeAllWallets(); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + WalletStack *walletStack; + +public slots: + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + /** Set the encryption status as shown in the UI. + @param[in] status current encryption status + @see WalletModel::EncryptionStatus + */ + void setEncryptionStatus(); +}; + +#endif // WALLETFRAME_H
\ No newline at end of file diff --git a/src/qt/walletstack.cpp b/src/qt/walletstack.cpp new file mode 100644 index 0000000000..271d1c7924 --- /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 <QMap> +#include <QMessageBox> + +WalletStack::WalletStack(QWidget *parent) : + QStackedWidget(parent), + clientModel(0), + bOutOfSync(true) +{ +} + +WalletStack::~WalletStack() +{ +} + +bool WalletStack::addWallet(const QString& name, WalletModel *walletModel) +{ + if (!gui || !clientModel || mapWalletViews.count(name) > 0) + return false; + + WalletView *walletView = new WalletView(this, gui); + walletView->setBitcoinGUI(gui); + walletView->setClientModel(clientModel); + walletView->setWalletModel(walletModel); + walletView->showOutOfSyncWarning(bOutOfSync); + addWidget(walletView); + mapWalletViews[name] = walletView; + return true; +} + +bool WalletStack::removeWallet(const QString& name) +{ + if (mapWalletViews.count(name) == 0) return false; + WalletView *walletView = mapWalletViews.take(name); + removeWidget(walletView); + return true; +} + +void WalletStack::removeAllWallets() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + removeWidget(i.value()); + mapWalletViews.clear(); +} + +bool WalletStack::handleURI(const QString &uri) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (!walletView) return false; + + return walletView->handleURI(uri); +} + +void WalletStack::showOutOfSyncWarning(bool fShow) +{ + bOutOfSync = fShow; + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->showOutOfSyncWarning(fShow); +} + +void WalletStack::gotoOverviewPage() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoOverviewPage(); +} + +void WalletStack::gotoHistoryPage() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoHistoryPage(); +} + +void WalletStack::gotoAddressBookPage() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoAddressBookPage(); +} + +void WalletStack::gotoReceiveCoinsPage() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoReceiveCoinsPage(); +} + +void WalletStack::gotoSendCoinsPage() +{ + QMap<QString, WalletView*>::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoSendCoinsPage(); +} + +void WalletStack::gotoSignMessageTab(QString addr) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->gotoSignMessageTab(addr); +} + +void WalletStack::gotoVerifyMessageTab(QString addr) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->gotoVerifyMessageTab(addr); +} + +void WalletStack::encryptWallet(bool status) +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->encryptWallet(status); +} + +void WalletStack::backupWallet() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->backupWallet(); +} + +void WalletStack::changePassphrase() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->changePassphrase(); +} + +void WalletStack::unlockWallet() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->unlockWallet(); +} + +void WalletStack::setEncryptionStatus() +{ + WalletView *walletView = (WalletView*)currentWidget(); + if (walletView) walletView->setEncryptionStatus(); +} + +void WalletStack::setCurrentWallet(const QString& name) +{ + if (mapWalletViews.count(name) == 0) return; + WalletView *walletView = mapWalletViews.value(name); + setCurrentWidget(walletView); + walletView->setEncryptionStatus(); +} diff --git a/src/qt/walletstack.h b/src/qt/walletstack.h new file mode 100644 index 0000000000..f3485816e9 --- /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 <QStackedWidget> +#include <QMap> +#include <boost/shared_ptr.hpp> + +class BitcoinGUI; +class TransactionTableModel; +class ClientModel; +class WalletModel; +class WalletView; +class TransactionView; +class OverviewPage; +class AddressBookPage; +class SendCoinsDialog; +class SignVerifyMessageDialog; +class Notificator; +class RPCConsole; + +class CWalletManager; + +QT_BEGIN_NAMESPACE +class QLabel; +class QModelIndex; +QT_END_NAMESPACE + +/* + WalletStack class. This class is a container for WalletView instances. It takes the place of centralWidget. + It was added to support multiple wallet functionality. It communicates with both the client and the + wallet models to give the user an up-to-date view of the current core state. It manages all the wallet views + it contains and updates them accordingly. + */ +class WalletStack : public QStackedWidget +{ + Q_OBJECT +public: + explicit WalletStack(QWidget *parent = 0); + ~WalletStack(); + + void setBitcoinGUI(BitcoinGUI *gui) { this->gui = gui; } + + void setClientModel(ClientModel *clientModel) { this->clientModel = clientModel; } + + bool addWallet(const QString& name, WalletModel *walletModel); + bool removeWallet(const QString& name); + + void removeAllWallets(); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + QMap<QString, WalletView*> mapWalletViews; + + bool bOutOfSync; + +public slots: + void setCurrentWallet(const QString& name); + + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + /** Set the encryption status as shown in the UI. + @param[in] status current encryption status + @see WalletModel::EncryptionStatus + */ + void setEncryptionStatus(); +}; + +#endif // WALLETSTACK_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp new file mode 100644 index 0000000000..7dd36234c9 --- /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 <QVBoxLayout> +#include <QActionGroup> +#include <QAction> +#include <QLabel> +#include <QDesktopServices> +#include <QFileDialog> + +WalletView::WalletView(QWidget *parent, BitcoinGUI *_gui): + QStackedWidget(parent), + gui(_gui), + clientModel(0), + walletModel(0), + encryptWalletAction(0), + changePassphraseAction(0) +{ + // Create actions for the toolbar, menu bar and tray/dock icon + createActions(); + + // Create tabs + overviewPage = new OverviewPage(); + + transactionsPage = new QWidget(this); + QVBoxLayout *vbox = new QVBoxLayout(); + transactionView = new TransactionView(this); + vbox->addWidget(transactionView); + transactionsPage->setLayout(vbox); + + addressBookPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab); + + receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab); + + sendCoinsPage = new SendCoinsDialog(gui); + + signVerifyMessageDialog = new SignVerifyMessageDialog(gui); + + addWidget(overviewPage); + addWidget(transactionsPage); + addWidget(addressBookPage); + addWidget(receiveCoinsPage); + addWidget(sendCoinsPage); + + // Clicking on a transaction on the overview page simply sends you to transaction history page + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), this, SLOT(gotoHistoryPage())); + connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); + + // Double-clicking on a transaction on the transaction history page shows details + connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); + + // Clicking on "Verify Message" in the address book sends you to the verify message tab + connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); + // Clicking on "Sign Message" in the receive coins page sends you to the sign message tab + connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); + + gotoOverviewPage(); +} + +WalletView::~WalletView() +{ +} + +void WalletView::createActions() +{ + QActionGroup *tabGroup = new QActionGroup(this); + + overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this); + overviewAction->setStatusTip(tr("Show general overview of wallet")); + overviewAction->setToolTip(overviewAction->statusTip()); + overviewAction->setCheckable(true); + overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1)); + tabGroup->addAction(overviewAction); + + sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this); + sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address")); + sendCoinsAction->setToolTip(sendCoinsAction->statusTip()); + sendCoinsAction->setCheckable(true); + sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); + tabGroup->addAction(sendCoinsAction); + + receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this); + receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments")); + receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); + receiveCoinsAction->setCheckable(true); + receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); + tabGroup->addAction(receiveCoinsAction); + + historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this); + historyAction->setStatusTip(tr("Browse transaction history")); + historyAction->setToolTip(historyAction->statusTip()); + historyAction->setCheckable(true); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); + tabGroup->addAction(historyAction); + + addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this); + addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels")); + addressBookAction->setToolTip(addressBookAction->statusTip()); + addressBookAction->setCheckable(true); + addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); + tabGroup->addAction(addressBookAction); + + connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage())); + connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); + connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); + connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage())); + + encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); + encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet")); + encryptWalletAction->setCheckable(true); + backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this); + backupWalletAction->setStatusTip(tr("Backup wallet to another location")); + changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this); + changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption")); + signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this); + signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them")); + verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this); + verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses")); + + exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this); + exportAction->setStatusTip(tr("Export the data in the current tab to a file")); + exportAction->setToolTip(exportAction->statusTip()); + + connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool))); + connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet())); + connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase())); + connect(signMessageAction, SIGNAL(triggered()), this, SLOT(gotoSignMessageTab())); + connect(verifyMessageAction, SIGNAL(triggered()), this, SLOT(gotoVerifyMessageTab())); +} + +void WalletView::setBitcoinGUI(BitcoinGUI *gui) +{ + this->gui = gui; +} + +void WalletView::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + if(clientModel) + { + overviewPage->setClientModel(clientModel); + addressBookPage->setOptionsModel(clientModel->getOptionsModel()); + receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); + } +} + +void WalletView::setWalletModel(WalletModel *walletModel) +{ + this->walletModel = walletModel; + if(walletModel) + { + // Receive and report messages from wallet thread + connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); + + // Put transaction list in tabs + transactionView->setModel(walletModel); + overviewPage->setWalletModel(walletModel); + addressBookPage->setModel(walletModel->getAddressTableModel()); + receiveCoinsPage->setModel(walletModel->getAddressTableModel()); + sendCoinsPage->setModel(walletModel); + signVerifyMessageDialog->setModel(walletModel); + + setEncryptionStatus(); + connect(walletModel, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + + // Balloon pop-up for new transaction + connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(incomingTransaction(QModelIndex,int,int))); + + // Ask for passphrase if needed + connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + } +} + +void WalletView::incomingTransaction(const QModelIndex& parent, int start, int /*end*/) +{ + // Prevent balloon-spam when initial block download is in progress + if(!walletModel || !clientModel || clientModel->inInitialBlockDownload()) + return; + + TransactionTableModel *ttm = walletModel->getTransactionTableModel(); + + QString date = ttm->index(start, TransactionTableModel::Date, parent) + .data().toString(); + qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent) + .data(Qt::EditRole).toULongLong(); + QString type = ttm->index(start, TransactionTableModel::Type, parent) + .data().toString(); + QString address = ttm->index(start, TransactionTableModel::ToAddress, parent) + .data().toString(); + + gui->incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address); +} + +void WalletView::gotoOverviewPage() +{ + overviewAction->setChecked(true); + setCurrentWidget(overviewPage); + + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); +} + +void WalletView::gotoHistoryPage() +{ + historyAction->setChecked(true); + setCurrentWidget(transactionsPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), transactionView, SLOT(exportClicked())); +} + +void WalletView::gotoAddressBookPage() +{ + addressBookAction->setChecked(true); + setCurrentWidget(addressBookPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), addressBookPage, SLOT(exportClicked())); +} + +void WalletView::gotoReceiveCoinsPage() +{ + receiveCoinsAction->setChecked(true); + setCurrentWidget(receiveCoinsPage); + + exportAction->setEnabled(true); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); + connect(exportAction, SIGNAL(triggered()), receiveCoinsPage, SLOT(exportClicked())); +} + +void WalletView::gotoSendCoinsPage() +{ + sendCoinsAction->setChecked(true); + setCurrentWidget(sendCoinsPage); + + exportAction->setEnabled(false); + disconnect(exportAction, SIGNAL(triggered()), 0, 0); +} + +void WalletView::gotoSignMessageTab(QString addr) +{ + // call show() in showTab_SM() + signVerifyMessageDialog->showTab_SM(true); + + if(!addr.isEmpty()) + signVerifyMessageDialog->setAddress_SM(addr); +} + +void WalletView::gotoVerifyMessageTab(QString addr) +{ + // call show() in showTab_VM() + signVerifyMessageDialog->showTab_VM(true); + + if(!addr.isEmpty()) + signVerifyMessageDialog->setAddress_VM(addr); +} + +bool WalletView::handleURI(const QString& strURI) +{ + // URI has to be valid + if (sendCoinsPage->handleURI(strURI)) + { + gotoSendCoinsPage(); + return true; + } + else + return false; +} + +void WalletView::showOutOfSyncWarning(bool fShow) +{ + overviewPage->showOutOfSyncWarning(fShow); +} + +void WalletView::setEncryptionStatus() +{ + gui->setEncryptionStatus(walletModel->getEncryptionStatus()); +} + +void WalletView::encryptWallet(bool status) +{ + if(!walletModel) + return; + AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt: + AskPassphraseDialog::Decrypt, this); + dlg.setModel(walletModel); + dlg.exec(); + + setEncryptionStatus(); +} + +void WalletView::backupWallet() +{ + QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); + if(!filename.isEmpty()) { + if(!walletModel->backupWallet(filename)) { + gui->message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."), + CClientUIInterface::MSG_ERROR); + } + else + gui->message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."), + CClientUIInterface::MSG_INFORMATION); + } +} + +void WalletView::changePassphrase() +{ + AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this); + dlg.setModel(walletModel); + dlg.exec(); +} + +void WalletView::unlockWallet() +{ + if(!walletModel) + return; + // Unlock wallet when requested by wallet model + if(walletModel->getEncryptionStatus() == WalletModel::Locked) + { + AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this); + dlg.setModel(walletModel); + dlg.exec(); + } +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h new file mode 100644 index 0000000000..38eb0227af --- /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 <QStackedWidget> + +class BitcoinGUI; +class TransactionTableModel; +class ClientModel; +class WalletModel; +class TransactionView; +class OverviewPage; +class AddressBookPage; +class SendCoinsDialog; +class SignVerifyMessageDialog; +class Notificator; +class RPCConsole; + +QT_BEGIN_NAMESPACE +class QLabel; +class QModelIndex; +QT_END_NAMESPACE + +/* + WalletView class. This class represents the view to a single wallet. + It was added to support multiple wallet functionality. Each wallet gets its own WalletView instance. + It communicates with both the client and the wallet models to give the user an up-to-date view of the + current core state. +*/ +class WalletView : public QStackedWidget +{ + Q_OBJECT +public: + explicit WalletView(QWidget *parent, BitcoinGUI *_gui); + ~WalletView(); + + void setBitcoinGUI(BitcoinGUI *gui); + /** Set the client model. + The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. + */ + void setClientModel(ClientModel *clientModel); + /** Set the wallet model. + The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending + functionality. + */ + void setWalletModel(WalletModel *walletModel); + + bool handleURI(const QString &uri); + + void showOutOfSyncWarning(bool fShow); + +private: + BitcoinGUI *gui; + ClientModel *clientModel; + WalletModel *walletModel; + + OverviewPage *overviewPage; + QWidget *transactionsPage; + AddressBookPage *addressBookPage; + AddressBookPage *receiveCoinsPage; + SendCoinsDialog *sendCoinsPage; + SignVerifyMessageDialog *signVerifyMessageDialog; + + QLabel *labelEncryptionIcon; + QLabel *labelConnectionsIcon; + QLabel *labelBlocksIcon; + QLabel *progressBarLabel; + + QAction *overviewAction; + QAction *historyAction; + QAction *quitAction; + QAction *sendCoinsAction; + QAction *addressBookAction; + QAction *signMessageAction; + QAction *verifyMessageAction; + QAction *aboutAction; + QAction *receiveCoinsAction; + QAction *optionsAction; + QAction *toggleHideAction; + QAction *exportAction; + QAction *encryptWalletAction; + QAction *backupWalletAction; + QAction *changePassphraseAction; + QAction *aboutQtAction; + QAction *openRPCConsoleAction; + + TransactionView *transactionView; + + /** Create the main UI actions. */ + void createActions(); + /** Create the menu bar and sub-menus. */ + +public slots: + /** Switch to overview (home) page */ + void gotoOverviewPage(); + /** Switch to history (transactions) page */ + void gotoHistoryPage(); + /** Switch to address book page */ + void gotoAddressBookPage(); + /** Switch to receive coins page */ + void gotoReceiveCoinsPage(); + /** Switch to send coins page */ + void gotoSendCoinsPage(); + + /** Show Sign/Verify Message dialog and switch to sign message tab */ + void gotoSignMessageTab(QString addr = ""); + /** Show Sign/Verify Message dialog and switch to verify message tab */ + void gotoVerifyMessageTab(QString addr = ""); + + /** Show incoming transaction notification for new transactions. + + The new items are those between start and end inclusive, under the given parent item. + */ + void incomingTransaction(const QModelIndex& parent, int start, int /*end*/); + /** Encrypt the wallet */ + void encryptWallet(bool status); + /** Backup the wallet */ + void backupWallet(); + /** Change encrypted wallet passphrase */ + void changePassphrase(); + /** Ask for passphrase to unlock wallet temporarily */ + void unlockWallet(); + + void setEncryptionStatus(); +}; + +#endif // WALLETVIEW_H |