diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 07a6506eee..d58ad36f15 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -459,39 +459,15 @@ void BitcoinGUI::createActions() { continue; } - connect(action, &QAction::triggered, [this, name, path] { - OpenWalletActivity *activity = - m_wallet_controller->openWallet( - config->GetChainParams(), path); - - QProgressDialog *dialog = new QProgressDialog(this); - dialog->setLabelText(tr("Opening Wallet %1...") - .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(action, &QAction::triggered, [this, path] { + auto activity = + new OpenWalletActivity(m_wallet_controller, this, + this->config->GetChainParams()); connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet); connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater); - connect(activity, &OpenWalletActivity::finished, dialog, - &QObject::deleteLater); - bool invoked = QMetaObject::invokeMethod(activity, "open"); - assert(invoked); + activity->open(path); }); } if (m_open_wallet_menu->isEmpty()) { diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 7a77e8857d..765b2f1116 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -9,6 +10,7 @@ #include #include +#include #include #include @@ -16,8 +18,9 @@ WalletController::WalletController(interfaces::Node &node, const PlatformStyle *platform_style, OptionsModel *options_model, QObject *parent) - : QObject(parent), m_node(node), m_platform_style(platform_style), - m_options_model(options_model) { + : QObject(parent), m_activity_thread(new QThread(this)), + m_activity_worker(new QObject), m_node(node), + m_platform_style(platform_style), m_options_model(options_model) { m_handler_load_wallet = m_node.handleLoadWallet( [this](std::unique_ptr wallet) { getOrCreateWallet(std::move(wallet)); @@ -27,14 +30,16 @@ WalletController::WalletController(interfaces::Node &node, getOrCreateWallet(std::move(wallet)); } - m_activity_thread.start(); + m_activity_worker->moveToThread(m_activity_thread); + 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() { - m_activity_thread.quit(); - m_activity_thread.wait(); + m_activity_thread->quit(); + m_activity_thread->wait(); + delete m_activity_worker; } std::vector WalletController::getOpenWallets() const { @@ -57,13 +62,6 @@ std::map WalletController::listWalletDir() const { return wallets; } -OpenWalletActivity *WalletController::openWallet(const CChainParams ¶ms, - const std::string &name, - QWidget *parent) { - OpenWalletActivity *activity = new OpenWalletActivity(this, name, params); - activity->moveToThread(&m_activity_thread); - return activity; -} void WalletController::closeWallet(WalletModel *wallet_model, QWidget *parent) { QMessageBox box(parent); box.setWindowTitle(tr("Close wallet")); @@ -150,25 +148,65 @@ void WalletController::removeAndDeleteWallet(WalletModel *wallet_model) { delete wallet_model; } +WalletControllerActivity::WalletControllerActivity( + WalletController *wallet_controller, QWidget *parent_widget, + const CChainParams &chainparams) + : QObject(wallet_controller), m_wallet_controller(wallet_controller), + m_parent_widget(parent_widget), m_chainparams(chainparams) {} + +WalletControllerActivity::~WalletControllerActivity() { + delete m_progress_dialog; +} + +void WalletControllerActivity::showProgressDialog(const QString &label_text) { + m_progress_dialog = new QProgressDialog(m_parent_widget); + + m_progress_dialog->setLabelText(label_text); + m_progress_dialog->setRange(0, 0); + m_progress_dialog->setCancelButton(nullptr); + m_progress_dialog->setWindowModality(Qt::ApplicationModal); + GUIUtil::PolishProgressDialog(m_progress_dialog); +} + OpenWalletActivity::OpenWalletActivity(WalletController *wallet_controller, - const std::string &name, - const CChainParams ¶ms) - : m_wallet_controller(wallet_controller), m_name(name), - m_chain_params(params) {} - -void OpenWalletActivity::open() { - std::string error, warning; - std::unique_ptr wallet = - m_wallet_controller->m_node.loadWallet(m_chain_params, m_name, error, - warning); - if (!warning.empty()) { - Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning)); + QWidget *parent_widget, + const CChainParams &chainparams) + : WalletControllerActivity(wallet_controller, parent_widget, chainparams) {} + +void OpenWalletActivity::finish() { + m_progress_dialog->hide(); + + if (!m_error_message.empty()) { + QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), + QString::fromStdString(m_error_message)); + } else if (!m_warning_message.empty()) { + QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), + QString::fromStdString(m_warning_message)); } - if (wallet) { - Q_EMIT opened( - m_wallet_controller->getOrCreateWallet(std::move(wallet))); - } else { - Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error)); + + if (m_wallet_model) { + Q_EMIT opened(m_wallet_model); } + Q_EMIT finished(); } + +void OpenWalletActivity::open(const std::string &path) { + QString name = path.empty() ? QString("[" + tr("default wallet") + "]") + : QString::fromStdString(path); + + showProgressDialog( + tr("Opening Wallet %1...").arg(name.toHtmlEscaped())); + + QTimer::singleShot(0, worker(), [this, path] { + std::unique_ptr wallet = node().loadWallet( + this->m_chainparams, path, m_error_message, m_warning_message); + + if (wallet) { + m_wallet_model = + m_wallet_controller->getOrCreateWallet(std::move(wallet)); + } + + QTimer::singleShot(0, this, &OpenWalletActivity::finish); + }); +} diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index 03a0cfb297..852afb0d80 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -12,9 +12,12 @@ #include #include +#include #include #include +#include +#include #include class OptionsModel; @@ -26,6 +29,7 @@ class Node; } // namespace interfaces class OpenWalletActivity; +class WalletControllerActivity; /** * Controller between interfaces::Node, WalletModel instances and the GUI. @@ -33,7 +37,6 @@ class OpenWalletActivity; class WalletController : public QObject { Q_OBJECT - WalletModel *getOrCreateWallet(std::unique_ptr wallet); void removeAndDeleteWallet(WalletModel *wallet_model); public: @@ -45,13 +48,12 @@ class WalletController : public QObject { //! Returns wallet models currently open. std::vector getOpenWallets() const; + WalletModel *getOrCreateWallet(std::unique_ptr wallet); + //! Returns all wallet names in the wallet dir mapped to whether the wallet //! is loaded. std::map listWalletDir() const; - OpenWalletActivity *openWallet(const CChainParams ¶ms, - const std::string &name, - QWidget *parent = nullptr); void closeWallet(WalletModel *wallet_model, QWidget *parent = nullptr); Q_SIGNALS: @@ -62,7 +64,8 @@ class WalletController : public QObject { QByteArray transaction); private: - QThread m_activity_thread; + QThread *const m_activity_thread; + QObject *const m_activity_worker; interfaces::Node &m_node; const PlatformStyle *const m_platform_style; OptionsModel *const m_options_model; @@ -70,28 +73,51 @@ class WalletController : public QObject { std::vector m_wallets; std::unique_ptr m_handler_load_wallet; - friend class OpenWalletActivity; + friend class WalletControllerActivity; +}; + +class WalletControllerActivity : public QObject { + Q_OBJECT + +public: + WalletControllerActivity(WalletController *wallet_controller, + QWidget *parent_widget, + const CChainParams &chainparams); + virtual ~WalletControllerActivity(); + +Q_SIGNALS: + void finished(); + +protected: + interfaces::Node &node() const { return m_wallet_controller->m_node; } + QObject *worker() const { return m_wallet_controller->m_activity_worker; } + + void showProgressDialog(const QString &label_text); + + WalletController *const m_wallet_controller; + QWidget *const m_parent_widget; + QProgressDialog *m_progress_dialog{nullptr}; + WalletModel *m_wallet_model{nullptr}; + std::string m_error_message; + std::string m_warning_message; + + const CChainParams &m_chainparams; }; -class OpenWalletActivity : public QObject { +class OpenWalletActivity : public WalletControllerActivity { Q_OBJECT public: OpenWalletActivity(WalletController *wallet_controller, - const std::string &name, const CChainParams ¶ms); + QWidget *parent_widget, const CChainParams &chainparams); -public Q_SLOTS: - void open(); + void open(const std::string &path); 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; - const CChainParams &m_chain_params; + void finish(); }; #endif // BITCOIN_QT_WALLETCONTROLLER_H