Merge bitcoin-core/gui#471: Add Wallet Restore in the GUI

bc13ec888c doc: Add a release note about the "restore wallet" menu item (w0xlt)
e7a3f698b5 gui: Add Wallet Restore in the GUI (w0xlt)

Pull request description:

  This PR adds a menu item to restore a wallet from a backup file in the GUI.
  Currently this option exists only in RPC interface.

  Motivation: It makes easier for non-technical users to restore backups.

  Master | PR |
  --- | ---
  <img width="307" alt="master" src="https://user-images.githubusercontent.com/94266259/141673349-0bf8a237-ecec-42e4-a0d7-1d5863940036.png"> | <img width="307" alt="pr" src="https://user-images.githubusercontent.com/94266259/141673350-972dea23-ae56-4283-a365-819da62b7067.png"> |

ACKs for top commit:
  w0xlt:
    Added a release note in a new commit (bc13ec888c) to not invalidate the ACKs for the previous one.
  furszy:
    utACK bc13ec8
  shaavan:
    ACK bc13ec888c
  hebasto:
    ACK bc13ec888c

Tree-SHA512: edc3675484238857b77e74382a4041dd5d2cbcda1e2d5bfe52c83d9d7bb7be8a243ecd97e25e994d8c30ab6d7c59ead5a1c953a46dce173666b137eeffc3c94f
pull/25587/head
Hennadii Stepanov 2 years ago
commit f9783b0f07
No known key found for this signature in database
GPG Key ID: 410108112E7EA81F

@ -0,0 +1,4 @@
GUI changes
--------
- A new menu item to restore a wallet from a backup file has been added (#471).

@ -47,6 +47,7 @@
#include <QCursor> #include <QCursor>
#include <QDateTime> #include <QDateTime>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QInputDialog>
#include <QKeySequence> #include <QKeySequence>
#include <QListWidget> #include <QListWidget>
#include <QMenu> #include <QMenu>
@ -348,6 +349,12 @@ void BitcoinGUI::createActions()
m_create_wallet_action->setEnabled(false); m_create_wallet_action->setEnabled(false);
m_create_wallet_action->setStatusTip(tr("Create a new wallet")); m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
//: Name of the menu item that restores wallet from a backup file.
m_restore_wallet_action = new QAction(tr("Restore Wallet…"), this);
m_restore_wallet_action->setEnabled(false);
//: Status tip for Restore Wallet menu item
m_restore_wallet_action->setStatusTip(tr("Restore a wallet from a backup file"));
m_close_all_wallets_action = new QAction(tr("Close All Wallets…"), this); m_close_all_wallets_action = new QAction(tr("Close All Wallets…"), this);
m_close_all_wallets_action->setStatusTip(tr("Close all wallets")); m_close_all_wallets_action->setStatusTip(tr("Close all wallets"));
@ -412,6 +419,27 @@ void BitcoinGUI::createActions()
action->setEnabled(false); action->setEnabled(false);
} }
}); });
connect(m_restore_wallet_action, &QAction::triggered, [this] {
//: Name of the wallet data file format.
QString name_data_file = tr("Wallet Data");
//: The title for Restore Wallet File Windows
QString title_windows = tr("Load Wallet Backup");
QString backup_file = GUIUtil::getOpenFileName(this, title_windows, QString(), name_data_file + QLatin1String(" (*.dat)"), nullptr);
if (backup_file.isEmpty()) return;
bool wallet_name_ok;
//: Title of the Restore Wallet input dialog (where the wallet name is entered)
QString wallet_name = QInputDialog::getText(this, tr("Restore Name"), tr("Wallet Name:"), QLineEdit::Normal, "", &wallet_name_ok);
if (!wallet_name_ok || wallet_name.isEmpty()) return;
auto activity = new RestoreWalletActivity(m_wallet_controller, this);
connect(activity, &RestoreWalletActivity::restored, this, &BitcoinGUI::setCurrentWallet, Qt::QueuedConnection);
auto backup_file_path = fs::PathFromString(backup_file.toStdString());
activity->restore(backup_file_path, wallet_name.toStdString());
});
connect(m_close_wallet_action, &QAction::triggered, [this] { connect(m_close_wallet_action, &QAction::triggered, [this] {
m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this); m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this);
}); });
@ -450,8 +478,10 @@ void BitcoinGUI::createMenuBar()
file->addAction(m_close_wallet_action); file->addAction(m_close_wallet_action);
file->addAction(m_close_all_wallets_action); file->addAction(m_close_all_wallets_action);
file->addSeparator(); file->addSeparator();
file->addAction(openAction);
file->addAction(backupWalletAction); file->addAction(backupWalletAction);
file->addAction(m_restore_wallet_action);
file->addSeparator();
file->addAction(openAction);
file->addAction(signMessageAction); file->addAction(signMessageAction);
file->addAction(verifyMessageAction); file->addAction(verifyMessageAction);
file->addAction(m_load_psbt_action); file->addAction(m_load_psbt_action);
@ -642,6 +672,7 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
m_create_wallet_action->setEnabled(true); m_create_wallet_action->setEnabled(true);
m_open_wallet_action->setEnabled(true); m_open_wallet_action->setEnabled(true);
m_open_wallet_action->setMenu(m_open_wallet_menu); m_open_wallet_action->setMenu(m_open_wallet_menu);
m_restore_wallet_action->setEnabled(true);
GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);

@ -157,6 +157,7 @@ private:
QAction* m_create_wallet_action{nullptr}; QAction* m_create_wallet_action{nullptr};
QAction* m_open_wallet_action{nullptr}; QAction* m_open_wallet_action{nullptr};
QMenu* m_open_wallet_menu{nullptr}; QMenu* m_open_wallet_menu{nullptr};
QAction* m_restore_wallet_action{nullptr};
QAction* m_close_wallet_action{nullptr}; QAction* m_close_wallet_action{nullptr};
QAction* m_close_all_wallets_action{nullptr}; QAction* m_close_all_wallets_action{nullptr};
QAction* m_wallet_selector_label_action = nullptr; QAction* m_wallet_selector_label_action = nullptr;

@ -373,3 +373,46 @@ void LoadWalletsActivity::load()
QTimer::singleShot(0, this, [this] { Q_EMIT finished(); }); QTimer::singleShot(0, this, [this] { Q_EMIT finished(); });
}); });
} }
RestoreWalletActivity::RestoreWalletActivity(WalletController* wallet_controller, QWidget* parent_widget)
: WalletControllerActivity(wallet_controller, parent_widget)
{
}
void RestoreWalletActivity::restore(const fs::path& backup_file, const std::string& wallet_name)
{
QString name = QString::fromStdString(wallet_name);
showProgressDialog(
//: Title of progress window which is displayed when wallets are being restored.
tr("Restore Wallet"),
/*: Descriptive text of the restore wallets progress window which indicates to
the user that wallets are currently being restored.*/
tr("Restoring Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().restoreWallet(backup_file, wallet_name, m_error_message, m_warning_message);
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
QTimer::singleShot(0, this, &RestoreWalletActivity::finish);
});
}
void RestoreWalletActivity::finish()
{
if (!m_error_message.empty()) {
//: Title of message box which is displayed when the wallet could not be restored.
QMessageBox::critical(m_parent_widget, tr("Restore wallet failed"), QString::fromStdString(m_error_message.translated));
} else if (!m_warning_message.empty()) {
//: Title of message box which is displayed when the wallet is restored with some warning.
QMessageBox::warning(m_parent_widget, tr("Restore wallet warning"), QString::fromStdString(Join(m_warning_message, Untranslated("\n")).translated));
} else {
//: Title of message box which is displayed when the wallet is successfully restored.
QMessageBox::information(m_parent_widget, tr("Restore wallet message"), QString::fromStdString(Untranslated("Wallet restored successfully \n").translated));
}
if (m_wallet_model) Q_EMIT restored(m_wallet_model);
Q_EMIT finished();
}

@ -33,6 +33,10 @@ class Node;
class Wallet; class Wallet;
} // namespace interfaces } // namespace interfaces
namespace fs {
class path;
}
class AskPassphraseDialog; class AskPassphraseDialog;
class CreateWalletActivity; class CreateWalletActivity;
class CreateWalletDialog; class CreateWalletDialog;
@ -155,4 +159,20 @@ public:
void load(); void load();
}; };
class RestoreWalletActivity : public WalletControllerActivity
{
Q_OBJECT
public:
RestoreWalletActivity(WalletController* wallet_controller, QWidget* parent_widget);
void restore(const fs::path& backup_file, const std::string& wallet_name);
Q_SIGNALS:
void restored(WalletModel* wallet_model);
private:
void finish();
};
#endif // BITCOIN_QT_WALLETCONTROLLER_H #endif // BITCOIN_QT_WALLETCONTROLLER_H

Loading…
Cancel
Save