From 2af7ce84fb16033db1cf6a67e0d829eca1d60d72 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 26 Mar 2018 18:50:54 +0700 Subject: [PATCH] Merge #12610: Multiwallet for the GUI 779c5f984 Qt: hide RPCConsole wallet selector when no wallets are present (Jonas Schnelli) dc6f150f3 Qt: show wallet name in request dlg in case of multiwallet (Jonas Schnelli) 4826ca4b8 Qt: show wallet name in send confirmation dlg in case of multiwallet (Jonas Schnelli) cfa4133ce GUI: RPCConsole: Log wallet changes (Luke Dashjr) b6d04fc7c Qt: Get wallet name from WalletModel rather than passing it around (Luke Dashjr) 12d8d2681 Qt: When multiple wallets are used, include in notifications the name (Jonas Schnelli) d1ec34a76 Qt: QComboBox::setVisible doesn't work in toolbars, so defer adding it at all until needed (Luke Dashjr) d49cc70e6 Qt: Add wallet selector to debug console (Jonas Schnelli) d558f44c5 Bugfix: RPC: Add missing UnregisterHTTPHandler for /wallet/ (Luke Dashjr) 85d531971 Qt: Ensure UI updates only come from the currently selected walletView (Luke Dashjr) e449f9a9e Qt: Add a combobox to toolbar to select from multiple wallets (Luke Dashjr) 3dba3c3ac Qt: Load all wallets into WalletModels (Luke Dashjr) Pull request description: This is an overhaul of #11383 (plus some additions). It avoids unnecessary coupling of httpserver/jsonrpc and the wallet as well as it avoids pointer pure passing (and pointer deletion) of `CWallet` (plus other minor design changes). Additionally it adds the wallet name to the sendconfirmation and request dialog (in case multiwallet is active) Tree-SHA512: 3d06e18badbc5d1821e488bf1dae463bb0be544cf11b2b618e025812bfdd13c5f39604bb93b4c705313930e7dc4e66f4848b9469ba14871bade58e7a027246a1 --- src/httprpc.cpp | 3 ++ src/qt/bitcoingui.cpp | 54 +++++++++++++++++++++++++----- src/qt/bitcoingui.h | 28 +++++++++++----- src/qt/dash.cpp | 26 +++++++++------ src/qt/forms/debugwindow.ui | 16 +++++++++ src/qt/receivecoinsdialog.cpp | 4 +-- src/qt/receiverequestdialog.cpp | 9 +++-- src/qt/receiverequestdialog.h | 6 ++-- src/qt/rpcconsole.cpp | 58 +++++++++++++++++++++++++++------ src/qt/rpcconsole.h | 15 +++++---- src/qt/sendcoinsdialog.cpp | 6 ++-- src/qt/walletframe.cpp | 11 +++++-- src/qt/walletframe.h | 3 +- src/qt/walletmodel.cpp | 20 ++++++++++-- src/qt/walletmodel.h | 7 +++- src/qt/walletview.cpp | 14 ++++---- src/qt/walletview.h | 7 ++-- 17 files changed, 216 insertions(+), 71 deletions(-) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index c2b01b3c82..7fc6fc0dc6 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -258,6 +258,9 @@ void StopHTTPRPC() { LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); +#ifdef ENABLE_WALLET + UnregisterHTTPHandler("/wallet/", false); +#endif if (httpRPCTimerInterface) { RPCUnsetTimerInterface(httpRPCTimerInterface.get()); httpRPCTimerInterface.reset(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ef71c6fc2e..963ce24f27 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #endif // ENABLE_WALLET #ifdef Q_OS_MAC @@ -41,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -70,10 +72,6 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = #endif ; -/** Display name for default wallet name. Uses tilde to avoid name - * collisions in the future with additional wallets */ -const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; - BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), enableWallet(false), @@ -88,6 +86,7 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle * progressBar(0), progressDialog(0), appMenuBar(0), + appToolBar(0), overviewAction(0), historyAction(0), masternodeAction(0), @@ -588,6 +587,7 @@ void BitcoinGUI::createToolBars() if(walletFrame) { QToolBar *toolbar = new QToolBar(tr("Tabs toolbar")); + appToolBar = toolbar; toolbar->setContextMenuPolicy(Qt::PreventContextMenu); toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); toolbar->setToolButtonStyle(Qt::ToolButtonTextOnly); @@ -612,6 +612,15 @@ void BitcoinGUI::createToolBars() toolbar->setMovable(false); // remove unused icon in upper left corner overviewAction->setChecked(true); +#ifdef ENABLE_WALLET + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + toolbar->addWidget(spacer); + + m_wallet_selector = new QComboBox(); + connect(m_wallet_selector, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(setCurrentWallet(const QString&))); +#endif + QLabel *logoLabel = new QLabel(); logoLabel->setObjectName("lblToolbarLogo"); logoLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -729,12 +738,22 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel) } #ifdef ENABLE_WALLET -bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel) +bool BitcoinGUI::addWallet(WalletModel *walletModel) { if(!walletFrame) return false; + const QString name = walletModel->getWalletName(); setWalletActionsEnabled(true); - return walletFrame->addWallet(name, walletModel); + m_wallet_selector->addItem(name); + if (m_wallet_selector->count() == 2) { + m_wallet_selector_label = new QLabel(); + m_wallet_selector_label->setText(tr("Wallet:") + " "); + m_wallet_selector_label->setBuddy(m_wallet_selector); + appToolBar->addWidget(m_wallet_selector_label); + appToolBar->addWidget(m_wallet_selector); + } + rpcConsole->addWallet(walletModel); + return walletFrame->addWallet(walletModel); } bool BitcoinGUI::setCurrentWallet(const QString& name) @@ -1317,7 +1336,7 @@ void BitcoinGUI::showEvent(QShowEvent *event) } #ifdef ENABLE_WALLET -void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label) +void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName) { IncomingTransactionMessage itx = { date, unit, amount, type, address, label @@ -1386,8 +1405,11 @@ void BitcoinGUI::showIncomingTransactions() for (auto& itx : txs) { // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(itx.date) + - tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(itx.unit, itx.amount, true)) + - tr("Type: %1\n").arg(itx.type); + tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(itx.unit, itx.amount, true)); + if (WalletModel::isMultiwallet() && !walletName.isEmpty()) { + msg += tr("Wallet: %1\n").arg(walletName); + } + msg += tr("Type: %1\n").arg(itx.type); if (!itx.label.isEmpty()) msg += tr("Label: %1\n").arg(itx.label); else if (!itx.address.isEmpty()) @@ -1496,6 +1518,20 @@ void BitcoinGUI::setEncryptionStatus(int status) break; } } + +void BitcoinGUI::updateWalletStatus() +{ + if (!walletFrame) { + return; + } + WalletView * const walletView = walletFrame->currentWalletView(); + if (!walletView) { + return; + } + WalletModel * const walletModel = walletView->getWalletModel(); + setEncryptionStatus(walletModel->getEncryptionStatus()); + setHDStatus(walletModel->hdEnabled()); +} #endif // ENABLE_WALLET void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 4083cf6a65..503e42c3a7 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -38,6 +38,7 @@ class ModalOverlay; QT_BEGIN_NAMESPACE class QAction; +class QComboBox; class QProgressBar; class QProgressDialog; class QToolButton; @@ -52,7 +53,6 @@ class BitcoinGUI : public QMainWindow Q_OBJECT public: - static const QString DEFAULT_WALLET; static const std::string DEFAULT_UIPLATFORM; explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); @@ -68,8 +68,7 @@ public: The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. */ - bool addWallet(const QString& name, WalletModel *walletModel); - bool setCurrentWallet(const QString& name); + bool addWallet(WalletModel *walletModel); void removeAllWallets(); #endif // ENABLE_WALLET bool enableWallet; @@ -96,6 +95,7 @@ private: QProgressDialog *progressDialog; QMenuBar *appMenuBar; + QToolBar *appToolBar; QToolButton *overviewAction; QToolButton *historyAction; QToolButton *masternodeAction; @@ -130,6 +130,9 @@ private: QAction *showHelpMessageAction; QAction *showPrivateSendHelpAction; + QLabel *m_wallet_selector_label; + QComboBox *m_wallet_selector; + QSystemTrayIcon *trayIcon; QMenu *trayIconMenu; QMenu *dockIconMenu; @@ -212,22 +215,29 @@ public Q_SLOTS: void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr); #ifdef ENABLE_WALLET - /** Set the hd-enabled status as shown in the UI. - @param[in] status current hd enabled status - @see WalletModel::EncryptionStatus - */ - void setHDStatus(int hdEnabled); + bool setCurrentWallet(const QString& name); + /** Set the UI status indicators based on the currently selected wallet. + */ + void updateWalletStatus(); +private: /** Set the encryption status as shown in the UI. @param[in] status current encryption status @see WalletModel::EncryptionStatus */ void setEncryptionStatus(int status); + /** Set the hd-enabled status as shown in the UI. + @param[in] status current hd enabled status + @see WalletModel::EncryptionStatus + */ + void setHDStatus(int hdEnabled); + +public Q_SLOTS: bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); void showIncomingTransactions(); #endif // ENABLE_WALLET diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 29d90bb474..597483d8fb 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -232,7 +232,7 @@ private: QTimer *pollShutdownTimer; #ifdef ENABLE_WALLET PaymentServer* paymentServer; - WalletModel *walletModel; + std::vector m_wallet_models; #endif int returnValue; const PlatformStyle *platformStyle; @@ -334,7 +334,7 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv): pollShutdownTimer(0), #ifdef ENABLE_WALLET paymentServer(0), - walletModel(0), + m_wallet_models(), #endif returnValue(0) { @@ -461,8 +461,10 @@ void BitcoinApplication::requestShutdown() #ifdef ENABLE_WALLET window->removeAllWallets(); - delete walletModel; - walletModel = 0; + for (WalletModel *walletModel : m_wallet_models) { + delete walletModel; + } + m_wallet_models.clear(); #endif delete clientModel; clientModel = 0; @@ -491,16 +493,20 @@ void BitcoinApplication::initializeResult(bool success) window->setClientModel(clientModel); #ifdef ENABLE_WALLET - // TODO: Expose secondary wallets - if (HasWallets()) - { - walletModel = new WalletModel(platformStyle, GetWallets()[0], optionsModel); + bool fFirstWallet = true; + for (CWallet* pwallet : GetWallets()) { + WalletModel * const walletModel = new WalletModel(platformStyle, pwallet, optionsModel); - window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); - window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); + window->addWallet(walletModel); + if (fFirstWallet) { + window->setCurrentWallet(walletModel->getWalletName()); + fFirstWallet = false; + } connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); + + m_wallet_models.push_back(walletModel); } #endif diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 9df65c1139..e7992fdd3f 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -494,6 +494,22 @@ 4 + + + + Wallet: + + + + + + + + (none) + + + + diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 155abc915b..a393e7e197 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -143,7 +143,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() ui->reqAmount->value(), ui->reqMessage->text()); ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setModel(model->getOptionsModel()); + dialog->setModel(model); dialog->setInfo(info); dialog->show(); clear(); @@ -156,7 +156,7 @@ void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex & { const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel(); ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); - dialog->setModel(model->getOptionsModel()); + dialog->setModel(model); dialog->setInfo(submodel->entry(index.row()).recipient); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 441d3662da..6bb9c1238f 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -107,12 +107,12 @@ ReceiveRequestDialog::~ReceiveRequestDialog() delete ui; } -void ReceiveRequestDialog::setModel(OptionsModel *_model) +void ReceiveRequestDialog::setModel(WalletModel *_model) { this->model = _model; if (_model) - connect(_model, SIGNAL(displayUnitChanged(int)), this, SLOT(update())); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(update())); // update the display unit if necessary update(); @@ -143,11 +143,14 @@ void ReceiveRequestDialog::update() uri + "\">" + GUIUtil::HtmlEscape(uri) + "
"; html += ""+tr("Address")+": " + GUIUtil::HtmlEscape(info.address) + "
"; if(info.amount) - html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getDisplayUnit(), info.amount) + "
"; + html += ""+tr("Amount")+": " + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), info.amount) + "
"; if(!info.label.isEmpty()) html += ""+tr("Label")+": " + GUIUtil::HtmlEscape(info.label) + "
"; if(!info.message.isEmpty()) html += ""+tr("Message")+": " + GUIUtil::HtmlEscape(info.message) + "
"; + if(model->isMultiwallet()) { + html += ""+tr("Wallet")+": " + GUIUtil::HtmlEscape(model->getWalletName()) + "
"; + } ui->outUri->setText(html); #ifdef USE_QRCODE diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 303db5bac6..71feb54f42 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -12,8 +12,6 @@ #include #include -class OptionsModel; - namespace Ui { class ReceiveRequestDialog; } @@ -53,7 +51,7 @@ public: explicit ReceiveRequestDialog(QWidget *parent = 0); ~ReceiveRequestDialog(); - void setModel(OptionsModel *model); + void setModel(WalletModel *model); void setInfo(const SendCoinsRecipient &info); private Q_SLOTS: @@ -64,7 +62,7 @@ private Q_SLOTS: private: Ui::ReceiveRequestDialog *ui; - OptionsModel *model; + WalletModel *model; SendCoinsRecipient info; }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 35889bc9cb..37402e3aa8 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ class RPCExecutor : public QObject Q_OBJECT public Q_SLOTS: - void request(const QString &command); + void request(const QString &command, const QString &walletID); Q_SIGNALS: void reply(int category, const QString &command); @@ -152,7 +153,7 @@ public: * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data */ -bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut) +bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut, const std::string *walletID) { std::vector< std::vector > stack; stack.push_back(std::vector()); @@ -310,10 +311,8 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string & req.params = RPCConvertValues(stack.back()[0], std::vector(stack.back().begin() + 1, stack.back().end())); req.strMethod = stack.back()[0]; #ifdef ENABLE_WALLET - // TODO: Move this logic to WalletModel - if (HasWallets()) { - // in Qt, use always the wallet with index 0 when running with multiple wallets - QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(GetWallets()[0]->GetName())); + if (walletID && !walletID->empty()) { + QByteArray encodedName = QUrl::toPercentEncoding(QString::fromStdString(*walletID)); req.URI = "/wallet/"+std::string(encodedName.constData(), encodedName.length()); } #endif @@ -392,7 +391,7 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string & } } -void RPCExecutor::request(const QString &command) +void RPCExecutor::request(const QString &command, const QString &walletID) { try { @@ -423,7 +422,8 @@ void RPCExecutor::request(const QString &command) " example: getblock(getblockhash(0),true)[tx][0]\n\n"))); return; } - if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand)) + std::string wallet_id = walletID.toStdString(); + if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand, nullptr, &wallet_id)) { Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); return; @@ -498,6 +498,10 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller())); connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); + // disable the wallet selector by default + ui->WalletSelector->setVisible(false); + ui->WalletSelectorLabel->setVisible(false); + // Wallet Repair Buttons // connect(ui->btn_salvagewallet, SIGNAL(clicked()), this, SLOT(walletSalvage())); // Disable salvage option in GUI, it's way too powerful and can lead to funds loss @@ -735,6 +739,23 @@ void RPCConsole::setClientModel(ClientModel *model) } } +#ifdef ENABLE_WALLET +void RPCConsole::addWallet(WalletModel * const walletModel) +{ + const QString name = walletModel->getWalletName(); + // use name for text and internal data object (to allow to move to a wallet id later) + ui->WalletSelector->addItem(name, name); + if (ui->WalletSelector->count() == 2 && !isVisible()) { + // First wallet added, set to default so long as the window isn't presently visible (and potentially in use) + ui->WalletSelector->setCurrentIndex(1); + } + if (ui->WalletSelector->count() > 2) { + ui->WalletSelector->setVisible(true); + ui->WalletSelectorLabel->setVisible(true); + } +} +#endif + static QString categoryClass(int category) { switch(category) @@ -1016,8 +1037,25 @@ void RPCConsole::on_lineEdit_returnPressed() cmdBeforeBrowsing = QString(); + QString walletID; +#ifdef ENABLE_WALLET + const int wallet_index = ui->WalletSelector->currentIndex(); + if (wallet_index > 0) { + walletID = (QString)ui->WalletSelector->itemData(wallet_index).value(); + } + + if (m_last_wallet_id != walletID) { + if (walletID.isEmpty()) { + message(CMD_REQUEST, tr("Executing command without any wallet")); + } else { + message(CMD_REQUEST, tr("Executing command using \"%1\" wallet").arg(walletID)); + } + m_last_wallet_id = walletID; + } +#endif + message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); - Q_EMIT cmdRequest(cmd); + Q_EMIT cmdRequest(cmd, walletID); cmd = QString::fromStdString(strFilteredCmd); @@ -1065,7 +1103,7 @@ void RPCConsole::startExecutor() // Replies from executor object must go to this object connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); // Requests from this object must go to executor - connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString))); + connect(this, SIGNAL(cmdRequest(QString, QString)), executor, SLOT(request(QString, QString))); // On stopExecutor signal // - quit the Qt event loop in the execution thread diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 1ade453af7..11a99f86be 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -19,6 +19,7 @@ class ClientModel; class PlatformStyle; class RPCTimerInterface; +class WalletModel; namespace Ui { class RPCConsole; @@ -38,12 +39,13 @@ public: explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); - static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr); - static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr) { - return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut); + static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr); + static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = nullptr, const std::string *walletID = nullptr) { + return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut, walletID); } void setClientModel(ClientModel *model); + void addWallet(WalletModel * const walletModel); enum MessageClass { MC_ERROR, @@ -94,7 +96,7 @@ public Q_SLOTS: void fontBigger(); void fontSmaller(); void setFontSize(int newSize); - + /** Wallet repair options */ void walletSalvage(); void walletRescan(); @@ -102,7 +104,7 @@ public Q_SLOTS: void walletZaptxes2(); void walletUpgrade(); void walletReindex(); - + /** Append the message to the message widget */ void message(int category, const QString &message, bool html = false); /** Set number of connections shown in the UI */ @@ -139,7 +141,7 @@ public Q_SLOTS: Q_SIGNALS: // For RPC command executor void stopExecutor(); - void cmdRequest(const QString &command); + void cmdRequest(const QString &command, const QString &walletID); /** Get restart command-line parameters and handle restart */ void handleRestart(QStringList args); @@ -175,6 +177,7 @@ private: int consoleFontSize; QCompleter *autoCompleter; QThread thread; + QString m_last_wallet_id; /** Update UI with latest network info from model. */ void updateNetworkState(); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index fd699c97f9..36316e6abf 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -331,10 +331,12 @@ void SendCoinsDialog::send(QList recipients) QStringList formatted; for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { - // generate bold amount string + // generate bold amount string with wallet name in case of multiwallet QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); + if (model->isMultiwallet()) { + amount.append(" "+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+" "); + } amount.append(" "); - // generate monospace address string QString address = "" + rcp.address; address.append(""); diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 6f08ac82ea..0b38066080 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include @@ -39,10 +40,16 @@ void WalletFrame::setClientModel(ClientModel *_clientModel) this->clientModel = _clientModel; } -bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) +bool WalletFrame::addWallet(WalletModel *walletModel) { - if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) + if (!gui || !clientModel || !walletModel) { return false; + } + + const QString name = walletModel->getWalletName(); + if (mapWalletViews.count(name) > 0) { + return false; + } WalletView *walletView = new WalletView(platformStyle, this); walletView->setBitcoinGUI(gui); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 55210b080a..78aff0f166 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -36,7 +36,7 @@ public: void setClientModel(ClientModel *clientModel); - bool addWallet(const QString& name, WalletModel *walletModel); + bool addWallet(WalletModel *walletModel); bool setCurrentWallet(const QString& name); bool removeWallet(const QString &name); void removeAllWallets(); @@ -59,6 +59,7 @@ private: const PlatformStyle *platformStyle; +public: WalletView *currentWalletView(); public Q_SLOTS: diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2212186809..4c69ec9019 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -138,8 +138,9 @@ void WalletModel::updateStatus() { EncryptionStatus newEncryptionStatus = getEncryptionStatus(); - if(cachedEncryptionStatus != newEncryptionStatus) - Q_EMIT encryptionStatusChanged(newEncryptionStatus); + if(cachedEncryptionStatus != newEncryptionStatus) { + Q_EMIT encryptionStatusChanged(); + } } void WalletModel::pollBalanceChanged() @@ -808,3 +809,18 @@ int WalletModel::getDefaultConfirmTarget() const { return nTxConfirmTarget; } + +QString WalletModel::getWalletName() const +{ + LOCK(wallet->cs_wallet); + QString walletName = QString::fromStdString(wallet->GetName()); + if (walletName.endsWith(".dat")) { + walletName.truncate(walletName.size() - 4); + } + return walletName; +} + +bool WalletModel::isMultiwallet() +{ + return gArgs.GetArgs("-wallet").size() > 1; +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 27a64a4d9e..518f0a4cf7 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -133,6 +133,8 @@ public: TransactionTableModel *getTransactionTableModel(); RecentRequestsTableModel *getRecentRequestsTableModel(); + CWallet *getWallet() const { return wallet; }; + CAmount getBalance(const CCoinControl *coinControl = nullptr) const; CAmount getUnconfirmedBalance() const; CAmount getImmatureBalance() const; @@ -232,6 +234,9 @@ public: int getRealOutpointPrivateSendRounds(const COutPoint& outpoint) const; + QString getWalletName() const; + + static bool isMultiwallet(); private: CWallet *wallet; bool fHaveWatchOnly; @@ -270,7 +275,7 @@ Q_SIGNALS: const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); // Encryption status of wallet changed - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); // Signal emitted when wallet needs to be unlocked // It is valid behaviour for listeners to keep the wallet locked after this signal; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 7383f31a47..6415198db6 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -134,13 +134,13 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); // Pass through encryption status changed signals - connect(this, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + connect(this, SIGNAL(encryptionStatusChanged()), gui, SLOT(updateWalletStatus())); // Pass through transaction notifications - connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString))); + connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString,QString))); // Connect HD enabled state signal - connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int))); + connect(this, SIGNAL(hdEnabledStatusChanged()), gui, SLOT(updateWalletStatus())); } } @@ -178,11 +178,11 @@ void WalletView::setWalletModel(WalletModel *_walletModel) connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); // Handle changes in encryption status - connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); + connect(_walletModel, SIGNAL(encryptionStatusChanged()), this, SIGNAL(encryptionStatusChanged())); updateEncryptionStatus(); // update HD status - Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled()); + Q_EMIT hdEnabledStatusChanged(); // Balloon pop-up for new transaction connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), @@ -222,7 +222,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int QString address = ttm->data(index, TransactionTableModel::AddressRole).toString(); QString label = ttm->data(index, TransactionTableModel::LabelRole).toString(); - Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label); + Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label, walletModel->getWalletName()); } void WalletView::gotoOverviewPage() @@ -303,7 +303,7 @@ void WalletView::showOutOfSyncWarning(bool fShow) void WalletView::updateEncryptionStatus() { - Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus()); + Q_EMIT encryptionStatusChanged(); } void WalletView::encryptWallet(bool status) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index ba92577bdf..b40a186d9d 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -46,6 +46,7 @@ public: The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. */ void setClientModel(ClientModel *clientModel); + WalletModel *getWalletModel() { return walletModel; } /** Set the wallet model. The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. @@ -132,11 +133,11 @@ Q_SIGNALS: /** Fired when a message should be reported to the user */ void message(const QString &title, const QString &message, unsigned int style); /** Encryption status of wallet changed */ - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); /** HD-Enabled status of wallet changed (only possible during startup) */ - void hdEnabledStatusChanged(int hdEnabled); + void hdEnabledStatusChanged(); /** Notify that a new transaction appeared */ - void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label, const QString& walletName); /** Notify that the out of sync warning icon has been pressed */ void outOfSyncWarningClicked(); };