Skip to content

Commit 7d3f255

Browse files
committed
Merge #15153: gui: Add Open Wallet menu
1951ea4 gui: Show indeterminate progress dialog while opening walllet (João Barbosa) 8847cda gui: Add OpenWalletActivity (João Barbosa) 4c8982a interfaces: Avoid interface instance if wallet is null (João Barbosa) be82dea gui: Add thread to run background activity in WalletController (João Barbosa) 6c49a55 gui: Add Open Wallet menu (João Barbosa) 32a8c6a gui: Add openWallet and getWalletsAvailableToOpen to WalletController (João Barbosa) ab288b4 interfaces: Add loadWallet to Node (João Barbosa) 17abc0f wallet: Factor out LoadWallet (João Barbosa) Pull request description: The *Open Wallet* menu has all the available wallets currently not loaded. The list of the available wallets comes from `listWalletDir`. In the future the menu can be replaced by a custom dialog. <img width="674" alt="screenshot 2019-01-12 at 12 17 02" src="https://user-images.githubusercontent.com/3534524/51073166-ac041480-1664-11e9-8302-be81702bc146.png"> Tree-SHA512: ebfd75eee0c8264863748899843afab67dadb7dff21313c11e3cb5b6108d954978dd1f1ae786bc07580c5a771ea4ab38d18c1643c9b9b3683ed53f0f6c582e38
2 parents d8794a7 + 1951ea4 commit 7d3f255

File tree

12 files changed

+163
-16
lines changed

12 files changed

+163
-16
lines changed

src/dummywallet.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
class CWallet;
1010

11+
namespace interfaces {
12+
class Chain;
13+
}
14+
1115
class DummyWalletInit : public WalletInitInterface {
1216
public:
1317

@@ -43,6 +47,11 @@ std::vector<std::shared_ptr<CWallet>> GetWallets()
4347
throw std::logic_error("Wallet function called in non-wallet build.");
4448
}
4549

50+
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
51+
{
52+
throw std::logic_error("Wallet function called in non-wallet build.");
53+
}
54+
4655
namespace interfaces {
4756

4857
class Wallet;

src/interfaces/node.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class CWallet;
4242
fs::path GetWalletDir();
4343
std::vector<fs::path> ListWalletDir();
4444
std::vector<std::shared_ptr<CWallet>> GetWallets();
45+
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning);
4546

4647
namespace interfaces {
4748

@@ -252,6 +253,10 @@ class NodeImpl : public Node
252253
}
253254
return wallets;
254255
}
256+
std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) override
257+
{
258+
return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning));
259+
}
255260
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
256261
{
257262
return MakeHandler(::uiInterface.InitMessage_connect(fn));

src/interfaces/node.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ class Node
192192
//! Return interfaces for accessing wallets (if any).
193193
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
194194

195+
//! Attempts to load a wallet from file or directory.
196+
//! The loaded wallet is also notified to handlers previously registered
197+
//! with handleLoadWallet.
198+
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) = 0;
199+
195200
//! Register handler for init messages.
196201
using InitMessageFn = std::function<void(const std::string& message)>;
197202
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;

src/interfaces/wallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ class WalletClientImpl : public ChainClient
525525

526526
} // namespace
527527

528-
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); }
528+
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
529529

530530
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
531531
{

src/qt/bitcoin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ int GuiMain(int argc, char* argv[])
456456
// IMPORTANT if it is no longer a typedef use the normal variant above
457457
qRegisterMetaType< CAmount >("CAmount");
458458
qRegisterMetaType< std::function<void()> >("std::function<void()>");
459-
459+
qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
460460
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
461461
// Command-line options take precedence:
462462
node->setupServerArgs();

src/qt/bitcoingui.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ void BitcoinGUI::createActions()
334334
openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
335335
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
336336

337+
m_open_wallet_action = new QAction(tr("Open Wallet"), this);
338+
m_open_wallet_action->setMenu(new QMenu(this));
339+
m_open_wallet_action->setStatusTip(tr("Open a wallet"));
340+
337341
showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
338342
showHelpMessageAction->setMenuRole(QAction::NoRole);
339343
showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME)));
@@ -361,6 +365,37 @@ void BitcoinGUI::createActions()
361365
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
362366
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
363367
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
368+
connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
369+
m_open_wallet_action->menu()->clear();
370+
for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) {
371+
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
372+
QAction* action = m_open_wallet_action->menu()->addAction(name);
373+
connect(action, &QAction::triggered, [this, name, path] {
374+
OpenWalletActivity* activity = m_wallet_controller->openWallet(path);
375+
376+
QProgressDialog* dialog = new QProgressDialog(this);
377+
dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
378+
dialog->setRange(0, 0);
379+
dialog->setCancelButton(nullptr);
380+
dialog->setWindowModality(Qt::ApplicationModal);
381+
dialog->show();
382+
383+
connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) {
384+
QMessageBox box;
385+
box.setIcon(icon);
386+
box.setText(tr("Open Wallet Failed"));
387+
box.setInformativeText(text);
388+
box.setStandardButtons(QMessageBox::Ok);
389+
box.setDefaultButton(QMessageBox::Ok);
390+
connect(this, &QObject::destroyed, &box, &QDialog::accept);
391+
box.exec();
392+
});
393+
connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
394+
connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater);
395+
connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater);
396+
});
397+
}
398+
});
364399
}
365400
#endif // ENABLE_WALLET
366401

@@ -382,6 +417,8 @@ void BitcoinGUI::createMenuBar()
382417
QMenu *file = appMenuBar->addMenu(tr("&File"));
383418
if(walletFrame)
384419
{
420+
file->addAction(m_open_wallet_action);
421+
file->addSeparator();
385422
file->addAction(openAction);
386423
file->addAction(backupWalletAction);
387424
file->addAction(signMessageAction);

src/qt/bitcoingui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class BitcoinGUI : public QMainWindow
147147
QAction* openRPCConsoleAction = nullptr;
148148
QAction* openAction = nullptr;
149149
QAction* showHelpMessageAction = nullptr;
150+
QAction* m_open_wallet_action{nullptr};
150151
QAction* m_wallet_selector_label_action = nullptr;
151152
QAction* m_wallet_selector_action = nullptr;
152153

src/qt/walletcontroller.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <algorithm>
1111

12+
#include <QMessageBox>
1213
#include <QMutexLocker>
1314
#include <QThread>
1415

@@ -25,18 +26,43 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle*
2526
for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) {
2627
getOrCreateWallet(std::move(wallet));
2728
}
29+
30+
m_activity_thread.start();
2831
}
2932

3033
// Not using the default destructor because not all member types definitions are
3134
// available in the header, just forward declared.
32-
WalletController::~WalletController() {}
35+
WalletController::~WalletController()
36+
{
37+
m_activity_thread.quit();
38+
m_activity_thread.wait();
39+
}
3340

3441
std::vector<WalletModel*> WalletController::getWallets() const
3542
{
3643
QMutexLocker locker(&m_mutex);
3744
return m_wallets;
3845
}
3946

47+
std::vector<std::string> WalletController::getWalletsAvailableToOpen() const
48+
{
49+
QMutexLocker locker(&m_mutex);
50+
std::vector<std::string> wallets = m_node.listWalletDir();
51+
for (WalletModel* wallet_model : m_wallets) {
52+
auto it = std::remove(wallets.begin(), wallets.end(), wallet_model->wallet().getWalletName());
53+
if (it != wallets.end()) wallets.erase(it);
54+
}
55+
return wallets;
56+
}
57+
58+
OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent)
59+
{
60+
OpenWalletActivity* activity = new OpenWalletActivity(this, name);
61+
activity->moveToThread(&m_activity_thread);
62+
QMetaObject::invokeMethod(activity, "open", Qt::QueuedConnection);
63+
return activity;
64+
}
65+
4066
WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)
4167
{
4268
QMutexLocker locker(&m_mutex);
@@ -93,3 +119,24 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model)
93119
// CWallet shared pointer.
94120
delete wallet_model;
95121
}
122+
123+
124+
OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name)
125+
: m_wallet_controller(wallet_controller)
126+
, m_name(name)
127+
{}
128+
129+
void OpenWalletActivity::open()
130+
{
131+
std::string error, warning;
132+
std::unique_ptr<interfaces::Wallet> wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning);
133+
if (!warning.empty()) {
134+
Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning));
135+
}
136+
if (wallet) {
137+
Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet)));
138+
} else {
139+
Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error));
140+
}
141+
Q_EMIT finished();
142+
}

src/qt/walletcontroller.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
#include <memory>
1313
#include <vector>
1414

15+
#include <QMessageBox>
1516
#include <QMutex>
17+
#include <QThread>
1618

1719
class OptionsModel;
1820
class PlatformStyle;
@@ -22,6 +24,8 @@ class Handler;
2224
class Node;
2325
} // namespace interfaces
2426

27+
class OpenWalletActivity;
28+
2529
/**
2630
* Controller between interfaces::Node, WalletModel instances and the GUI.
2731
*/
@@ -37,6 +41,9 @@ class WalletController : public QObject
3741
~WalletController();
3842

3943
std::vector<WalletModel*> getWallets() const;
44+
std::vector<std::string> getWalletsAvailableToOpen() const;
45+
46+
OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr);
4047

4148
private Q_SLOTS:
4249
void addWallet(WalletModel* wallet_model);
@@ -48,12 +55,35 @@ private Q_SLOTS:
4855
void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction);
4956

5057
private:
58+
QThread m_activity_thread;
5159
interfaces::Node& m_node;
5260
const PlatformStyle* const m_platform_style;
5361
OptionsModel* const m_options_model;
5462
mutable QMutex m_mutex;
5563
std::vector<WalletModel*> m_wallets;
5664
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
65+
66+
friend class OpenWalletActivity;
67+
};
68+
69+
class OpenWalletActivity : public QObject
70+
{
71+
Q_OBJECT
72+
73+
public:
74+
OpenWalletActivity(WalletController* wallet_controller, const std::string& name);
75+
76+
public Q_SLOTS:
77+
void open();
78+
79+
Q_SIGNALS:
80+
void message(QMessageBox::Icon icon, const QString text);
81+
void finished();
82+
void opened(WalletModel* wallet_model);
83+
84+
private:
85+
WalletController* const m_wallet_controller;
86+
std::string const m_name;
5787
};
5888

5989
#endif // BITCOIN_QT_WALLETCONTROLLER_H

src/wallet/rpcwallet.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,7 +2555,6 @@ static UniValue loadwallet(const JSONRPCRequest& request)
25552555
}.ToString());
25562556

25572557
WalletLocation location(request.params[0].get_str());
2558-
std::string error;
25592558

25602559
if (!location.Exists()) {
25612560
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
@@ -2567,18 +2566,9 @@ static UniValue loadwallet(const JSONRPCRequest& request)
25672566
}
25682567
}
25692568

2570-
std::string warning;
2571-
if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
2572-
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
2573-
}
2574-
2575-
std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location);
2576-
if (!wallet) {
2577-
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed.");
2578-
}
2579-
AddWallet(wallet);
2580-
2581-
wallet->postInitProcess();
2569+
std::string error, warning;
2570+
std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_interfaces->chain, location, error, warning);
2571+
if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
25822572

25832573
UniValue obj(UniValue::VOBJ);
25842574
obj.pushKV("name", wallet->GetName());

0 commit comments

Comments
 (0)