Skip to content

Commit

Permalink
Merge bitcoin#15153: gui: Add Open Wallet menu
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jonasschnelli authored and pravblockc committed Nov 18, 2021
1 parent 329b58c commit b8b3c80
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 15 deletions.
9 changes: 9 additions & 0 deletions src/dummywallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

class CWallet;

namespace interfaces {
class Chain;
}

class DummyWalletInit : public WalletInitInterface {
public:

Expand Down Expand Up @@ -89,6 +93,11 @@ std::vector<std::shared_ptr<CWallet>> GetWallets()
throw std::logic_error("Wallet function called in non-wallet build.");
}

std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}

namespace interfaces {

class Wallet;
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning);

namespace interfaces {

Expand Down Expand Up @@ -378,6 +379,11 @@ class NodeImpl : public Node
}
return wallets;
}
std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) override
{
return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning));
}

EVO& evo() override { return m_evo; }
LLMQ& llmq() override { return m_llmq; }
Masternode::Sync& masternodeSync() override { return m_masternodeSync; }
Expand Down
5 changes: 5 additions & 0 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ class Node
//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;

//! Attempts to load a wallet from file or directory.
//! The loaded wallet is also notified to handlers previously registered
//! with handleLoadWallet.
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) = 0;

//! Return interface for accessing evo related handler.
virtual EVO& evo() = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ class WalletClientImpl : public ChainClient

} // namespace

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

std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
{
Expand Down
37 changes: 37 additions & 0 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,10 @@ void BitcoinGUI::createActions()
openAction = new QAction(tr("Open &URI..."), this);
openAction->setStatusTip(tr("Open a dash: URI or payment request"));

m_open_wallet_action = new QAction(tr("Open Wallet"), this);
m_open_wallet_action->setMenu(new QMenu(this));
m_open_wallet_action->setStatusTip(tr("Open a wallet"));

showHelpMessageAction = new QAction(tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Dash command-line options").arg(tr(PACKAGE_NAME)));
Expand Down Expand Up @@ -475,6 +479,37 @@ void BitcoinGUI::createActions()
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
m_open_wallet_action->menu()->clear();
for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) {
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
QAction* action = m_open_wallet_action->menu()->addAction(name);
connect(action, &QAction::triggered, [this, name, path] {
OpenWalletActivity* activity = m_wallet_controller->openWallet(path);

QProgressDialog* dialog = new QProgressDialog(this);
dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
dialog->setRange(0, 0);
dialog->setCancelButton(nullptr);
dialog->setWindowModality(Qt::ApplicationModal);
dialog->show();

connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) {
QMessageBox box;
box.setIcon(icon);
box.setText(tr("Open Wallet Failed"));
box.setInformativeText(text);
box.setStandardButtons(QMessageBox::Ok);
box.setDefaultButton(QMessageBox::Ok);
connect(this, &QObject::destroyed, &box, &QDialog::accept);
box.exec();
});
connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater);
connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater);
});
}
});
}
#endif // ENABLE_WALLET

Expand All @@ -499,6 +534,8 @@ void BitcoinGUI::createMenuBar()
QMenu *file = appMenuBar->addMenu(tr("&File"));
if(walletFrame)
{
file->addAction(m_open_wallet_action);
file->addSeparator();
file->addAction(openAction);
file->addAction(backupWalletAction);
file->addAction(signMessageAction);
Expand Down
1 change: 1 addition & 0 deletions src/qt/bitcoingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class BitcoinGUI : public QMainWindow
QAction* showBackupsAction = nullptr;
QAction* openAction = nullptr;
QAction* showHelpMessageAction = nullptr;
QAction* m_open_wallet_action{nullptr};
QAction* showCoinJoinHelpAction = nullptr;
QAction* m_wallet_selector_action = nullptr;

Expand Down
2 changes: 1 addition & 1 deletion src/qt/dash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ int GuiMain(int argc, char* argv[])
// IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount");
qRegisterMetaType< std::function<void()> >("std::function<void()>");

qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
// Command-line options take precedence:
node->setupServerArgs();
Expand Down
49 changes: 48 additions & 1 deletion src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <algorithm>

#include <QApplication>
#include <QMessageBox>
#include <QMutexLocker>
#include <QThread>
#include <QWindow>
Expand All @@ -26,18 +27,43 @@ WalletController::WalletController(interfaces::Node& node, OptionsModel* options
for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) {
getOrCreateWallet(std::move(wallet));
}

m_activity_thread.start();
}

// Not using the default destructor because not all member types definitions are
// available in the header, just forward declared.
WalletController::~WalletController() {}
WalletController::~WalletController()
{
m_activity_thread.quit();
m_activity_thread.wait();
}

std::vector<WalletModel*> WalletController::getWallets() const
{
QMutexLocker locker(&m_mutex);
return m_wallets;
}

std::vector<std::string> WalletController::getWalletsAvailableToOpen() const
{
QMutexLocker locker(&m_mutex);
std::vector<std::string> wallets = m_node.listWalletDir();
for (WalletModel* wallet_model : m_wallets) {
auto it = std::remove(wallets.begin(), wallets.end(), wallet_model->wallet().getWalletName());
if (it != wallets.end()) wallets.erase(it);
}
return wallets;
}

OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent)
{
OpenWalletActivity* activity = new OpenWalletActivity(this, name);
activity->moveToThread(&m_activity_thread);
QMetaObject::invokeMethod(activity, "open", Qt::QueuedConnection);
return activity;
}

WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)
{
QMutexLocker locker(&m_mutex);
Expand Down Expand Up @@ -111,3 +137,24 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model)
// CWallet shared pointer.
delete wallet_model;
}


OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name)
: m_wallet_controller(wallet_controller)
, m_name(name)
{}

void OpenWalletActivity::open()
{
std::string error, warning;
std::unique_ptr<interfaces::Wallet> wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning);
if (!warning.empty()) {
Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning));
}
if (wallet) {
Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet)));
} else {
Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error));
}
Q_EMIT finished();
}
30 changes: 30 additions & 0 deletions src/qt/walletcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
#include <memory>
#include <vector>

#include <QMessageBox>
#include <QMutex>
#include <QThread>

class OptionsModel;
class PlatformStyle;
Expand All @@ -22,6 +24,8 @@ class Handler;
class Node;
} // namespace interfaces

class OpenWalletActivity;

/**
* Controller between interfaces::Node, WalletModel instances and the GUI.
*/
Expand All @@ -37,6 +41,9 @@ class WalletController : public QObject
~WalletController();

std::vector<WalletModel*> getWallets() const;
std::vector<std::string> getWalletsAvailableToOpen() const;

OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr);

private Q_SLOTS:
void addWallet(WalletModel* wallet_model);
Expand All @@ -48,11 +55,34 @@ private Q_SLOTS:
void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction);

private:
QThread m_activity_thread;
interfaces::Node& m_node;
OptionsModel* const m_options_model;
mutable QMutex m_mutex;
std::vector<WalletModel*> m_wallets;
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;

friend class OpenWalletActivity;
};

class OpenWalletActivity : public QObject
{
Q_OBJECT

public:
OpenWalletActivity(WalletController* wallet_controller, const std::string& name);

public Q_SLOTS:
void open();

Q_SIGNALS:
void message(QMessageBox::Icon icon, const QString text);
void finished();
void opened(WalletModel* wallet_model);

private:
WalletController* const m_wallet_controller;
std::string const m_name;
};

#endif // BITCOIN_QT_WALLETCONTROLLER_H
15 changes: 3 additions & 12 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2856,7 +2856,6 @@ static UniValue loadwallet(const JSONRPCRequest& request)
);

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

if (!location.Exists()) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
Expand All @@ -2868,17 +2867,9 @@ static UniValue loadwallet(const JSONRPCRequest& request)
}
}

std::string warning;
if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
}

std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location);
if (!wallet) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed.");
}

wallet->postInitProcess();
std::string error, warning;
std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_interfaces->chain, location, error, warning);
if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);

UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
Expand Down
22 changes: 22 additions & 0 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,28 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
}

std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning)
{
if (!CWallet::Verify(chain, location, false, error, warning)) {
error = "Wallet file verification failed: " + error;
return nullptr;
}

std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location);
if (!wallet) {
error = "Wallet loading failed.";
return nullptr;
}
AddWallet(wallet);
wallet->postInitProcess();
return wallet;
}

std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
{
return LoadWallet(chain, WalletLocation(name), error, warning);
}

const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));

/** @defgroup mapWallet
Expand Down
1 change: 1 addition & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning);

static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default
Expand Down

0 comments on commit b8b3c80

Please sign in to comment.