Merge bitcoin-core/gui#398: refactor: Pass WalletModel object to the WalletView constructor

d319c4dae9 qt, refactor: Replace WalletFrame::addWallet with WalletFrame::addView (Hennadii Stepanov)
92ddc02a16 qt, refactor: Declare getWalletModel with const and noexcept qualifiers (Hennadii Stepanov)
ca0e680bdc qt, refactor: Drop redundant checks of walletModel (Hennadii Stepanov)
404373bc6a qt, refactor: Pass WalletModel object to WalletView constructor (Hennadii Stepanov)

Pull request description:

  An instance of the `WalletView` class without the `walletModel` data member being set is invalid. So, it is better to set it in the constructor.

  Establishing one more `WalletView` class's invariant in constructor:
  - allows to drop all of checks of the`walletModel` in member functions
  - makes reasoning about the code that uses instances of the `WalletView` class  easier

  Possible follow ups could extend this approach to other classes, e.g., `OverviewPage`, `TransactionView`, `ReceiveCoinsDialog`, `SendCoinsDialog`, `AddressBookPage`.

ACKs for top commit:
  ShaMan239:
    Code review ACK d319c4dae9
  promag:
    Code review ACK d319c4dae9.
  jarolrod:
    ACK d319c4dae9

Tree-SHA512: b0c61f82811bb5aba2738067b53dc9ea4439230d547ce5c8fd85c480d8d70ea15f9942dbf13842383acbce467fba1ab4e132e37c56b654b46ba897301a41066e
This commit is contained in:
Hennadii Stepanov 2021-09-07 08:40:51 +03:00
commit 503194d2ee
No known key found for this signature in database
GPG key ID: 410108112E7EA81F
5 changed files with 49 additions and 64 deletions

View file

@ -676,8 +676,8 @@ void BitcoinGUI::addWallet(WalletModel* walletModel)
{ {
if (!walletFrame) return; if (!walletFrame) return;
WalletView* wallet_view = new WalletView(platformStyle, walletFrame); WalletView* wallet_view = new WalletView(walletModel, platformStyle, walletFrame);
if (!walletFrame->addWallet(walletModel, wallet_view)) return; if (!walletFrame->addView(wallet_view)) return;
rpcConsole->addWallet(walletModel); rpcConsole->addWallet(walletModel);
if (m_wallet_selector->count() == 0) { if (m_wallet_selector->count() == 0) {

View file

@ -64,14 +64,13 @@ void WalletFrame::setClientModel(ClientModel *_clientModel)
} }
} }
bool WalletFrame::addWallet(WalletModel* walletModel, WalletView* walletView) bool WalletFrame::addView(WalletView* walletView)
{ {
if (!clientModel || !walletModel) return false; if (!clientModel) return false;
if (mapWalletViews.count(walletModel) > 0) return false; if (mapWalletViews.count(walletView->getWalletModel()) > 0) return false;
walletView->setClientModel(clientModel); walletView->setClientModel(clientModel);
walletView->setWalletModel(walletModel);
walletView->showOutOfSyncWarning(bOutOfSync); walletView->showOutOfSyncWarning(bOutOfSync);
WalletView* current_wallet_view = currentWalletView(); WalletView* current_wallet_view = currentWalletView();
@ -82,7 +81,7 @@ bool WalletFrame::addWallet(WalletModel* walletModel, WalletView* walletView)
} }
walletStack->addWidget(walletView); walletStack->addWidget(walletView);
mapWalletViews[walletModel] = walletView; mapWalletViews[walletView->getWalletModel()] = walletView;
return true; return true;
} }

View file

@ -35,7 +35,7 @@ public:
void setClientModel(ClientModel *clientModel); void setClientModel(ClientModel *clientModel);
bool addWallet(WalletModel* walletModel, WalletView* walletView); bool addView(WalletView* walletView);
void setCurrentWallet(WalletModel* wallet_model); void setCurrentWallet(WalletModel* wallet_model);
void removeWallet(WalletModel* wallet_model); void removeWallet(WalletModel* wallet_model);
void removeAllWallets(); void removeAllWallets();

View file

@ -30,19 +30,24 @@
#include <QPushButton> #include <QPushButton>
#include <QVBoxLayout> #include <QVBoxLayout>
WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): WalletView::WalletView(WalletModel* wallet_model, const PlatformStyle* _platformStyle, QWidget* parent)
QStackedWidget(parent), : QStackedWidget(parent),
clientModel(nullptr), clientModel(nullptr),
walletModel(nullptr), walletModel(wallet_model),
platformStyle(_platformStyle) platformStyle(_platformStyle)
{ {
assert(walletModel);
// Create tabs // Create tabs
overviewPage = new OverviewPage(platformStyle); overviewPage = new OverviewPage(platformStyle);
overviewPage->setWalletModel(walletModel);
transactionsPage = new QWidget(this); transactionsPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout(); QVBoxLayout *vbox = new QVBoxLayout();
QHBoxLayout *hbox_buttons = new QHBoxLayout(); QHBoxLayout *hbox_buttons = new QHBoxLayout();
transactionView = new TransactionView(platformStyle, this); transactionView = new TransactionView(platformStyle, this);
transactionView->setModel(walletModel);
vbox->addWidget(transactionView); vbox->addWidget(transactionView);
QPushButton *exportButton = new QPushButton(tr("&Export"), this); QPushButton *exportButton = new QPushButton(tr("&Export"), this);
exportButton->setToolTip(tr("Export the data in the current tab to a file")); exportButton->setToolTip(tr("Export the data in the current tab to a file"));
@ -55,10 +60,16 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
transactionsPage->setLayout(vbox); transactionsPage->setLayout(vbox);
receiveCoinsPage = new ReceiveCoinsDialog(platformStyle); receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
receiveCoinsPage->setModel(walletModel);
sendCoinsPage = new SendCoinsDialog(platformStyle); sendCoinsPage = new SendCoinsDialog(platformStyle);
sendCoinsPage->setModel(walletModel);
usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this); usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
usedSendingAddressesPage->setModel(walletModel->getAddressTableModel());
usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this); usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel());
addWidget(overviewPage); addWidget(overviewPage);
addWidget(transactionsPage); addWidget(transactionsPage);
@ -84,6 +95,21 @@ WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
connect(transactionView, &TransactionView::message, this, &WalletView::message); connect(transactionView, &TransactionView::message, this, &WalletView::message);
connect(this, &WalletView::setPrivacy, overviewPage, &OverviewPage::setPrivacy); connect(this, &WalletView::setPrivacy, overviewPage, &OverviewPage::setPrivacy);
// Receive and pass through messages from wallet model
connect(walletModel, &WalletModel::message, this, &WalletView::message);
// Handle changes in encryption status
connect(walletModel, &WalletModel::encryptionStatusChanged, this, &WalletView::encryptionStatusChanged);
// Balloon pop-up for new transaction
connect(walletModel->getTransactionTableModel(), &TransactionTableModel::rowsInserted, this, &WalletView::processNewTransaction);
// Ask for passphrase if needed
connect(walletModel, &WalletModel::requireUnlock, this, &WalletView::unlockWallet);
// Show progress dialog
connect(walletModel, &WalletModel::showProgress, this, &WalletView::showProgress);
} }
WalletView::~WalletView() WalletView::~WalletView()
@ -96,45 +122,15 @@ void WalletView::setClientModel(ClientModel *_clientModel)
overviewPage->setClientModel(_clientModel); overviewPage->setClientModel(_clientModel);
sendCoinsPage->setClientModel(_clientModel); sendCoinsPage->setClientModel(_clientModel);
if (walletModel) walletModel->setClientModel(_clientModel); walletModel->setClientModel(_clientModel);
}
void WalletView::setWalletModel(WalletModel *_walletModel)
{
this->walletModel = _walletModel;
// Put transaction list in tabs
transactionView->setModel(_walletModel);
overviewPage->setWalletModel(_walletModel);
receiveCoinsPage->setModel(_walletModel);
sendCoinsPage->setModel(_walletModel);
usedReceivingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
usedSendingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
if (_walletModel)
{
// Receive and pass through messages from wallet model
connect(_walletModel, &WalletModel::message, this, &WalletView::message);
// Handle changes in encryption status
connect(_walletModel, &WalletModel::encryptionStatusChanged, this, &WalletView::encryptionStatusChanged);
// Balloon pop-up for new transaction
connect(_walletModel->getTransactionTableModel(), &TransactionTableModel::rowsInserted, this, &WalletView::processNewTransaction);
// Ask for passphrase if needed
connect(_walletModel, &WalletModel::requireUnlock, this, &WalletView::unlockWallet);
// Show progress dialog
connect(_walletModel, &WalletModel::showProgress, this, &WalletView::showProgress);
}
} }
void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/) void WalletView::processNewTransaction(const QModelIndex& parent, int start, int /*end*/)
{ {
// Prevent balloon-spam when initial block download is in progress // Prevent balloon-spam when initial block download is in progress
if (!walletModel || !clientModel || clientModel->node().isInitialBlockDownload()) if (!clientModel || clientModel->node().isInitialBlockDownload()) {
return; return;
}
TransactionTableModel *ttm = walletModel->getTransactionTableModel(); TransactionTableModel *ttm = walletModel->getTransactionTableModel();
if (!ttm || ttm->processingQueuedTransactions()) if (!ttm || ttm->processingQueuedTransactions())
@ -209,8 +205,6 @@ void WalletView::showOutOfSyncWarning(bool fShow)
void WalletView::encryptWallet() void WalletView::encryptWallet()
{ {
if(!walletModel)
return;
AskPassphraseDialog dlg(AskPassphraseDialog::Encrypt, this); AskPassphraseDialog dlg(AskPassphraseDialog::Encrypt, this);
dlg.setModel(walletModel); dlg.setModel(walletModel);
dlg.exec(); dlg.exec();
@ -247,8 +241,6 @@ void WalletView::changePassphrase()
void WalletView::unlockWallet() void WalletView::unlockWallet()
{ {
if(!walletModel)
return;
// Unlock wallet when requested by wallet model // Unlock wallet when requested by wallet model
if (walletModel->getEncryptionStatus() == WalletModel::Locked) if (walletModel->getEncryptionStatus() == WalletModel::Locked)
{ {
@ -260,17 +252,11 @@ void WalletView::unlockWallet()
void WalletView::usedSendingAddresses() void WalletView::usedSendingAddresses()
{ {
if(!walletModel)
return;
GUIUtil::bringToFront(usedSendingAddressesPage); GUIUtil::bringToFront(usedSendingAddressesPage);
} }
void WalletView::usedReceivingAddresses() void WalletView::usedReceivingAddresses()
{ {
if(!walletModel)
return;
GUIUtil::bringToFront(usedReceivingAddressesPage); GUIUtil::bringToFront(usedReceivingAddressesPage);
} }

View file

@ -35,19 +35,14 @@ class WalletView : public QStackedWidget
Q_OBJECT Q_OBJECT
public: public:
explicit WalletView(const PlatformStyle *platformStyle, QWidget *parent); explicit WalletView(WalletModel* wallet_model, const PlatformStyle* platformStyle, QWidget* parent);
~WalletView(); ~WalletView();
/** Set the client model. /** Set the client model.
The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic.
*/ */
void setClientModel(ClientModel *clientModel); void setClientModel(ClientModel *clientModel);
WalletModel *getWalletModel() { return walletModel; } WalletModel* getWalletModel() const noexcept { 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.
*/
void setWalletModel(WalletModel *walletModel);
bool handlePaymentRequest(const SendCoinsRecipient& recipient); bool handlePaymentRequest(const SendCoinsRecipient& recipient);
@ -55,7 +50,12 @@ public:
private: private:
ClientModel *clientModel; ClientModel *clientModel;
WalletModel *walletModel;
//!
//! The wallet model represents a bitcoin wallet, and offers access to
//! the list of transactions, address book and sending functionality.
//!
WalletModel* const walletModel;
OverviewPage *overviewPage; OverviewPage *overviewPage;
QWidget *transactionsPage; QWidget *transactionsPage;