gui: Fix manual coin control with multiple wallets loaded

This commit is contained in:
João Barbosa 2020-05-05 23:56:21 +01:00
parent fbd522721c
commit a8b5f1b133
4 changed files with 45 additions and 67 deletions

View file

@ -41,10 +41,11 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
return QTreeWidgetItem::operator<(other); return QTreeWidgetItem::operator<(other);
} }
CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) : CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _model, const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::CoinControlDialog), ui(new Ui::CoinControlDialog),
model(nullptr), m_coin_control(coin_control),
model(_model),
platformStyle(_platformStyle) platformStyle(_platformStyle)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -136,6 +137,13 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
sortView(settings.value("nCoinControlSortColumn").toInt(), (static_cast<Qt::SortOrder>(settings.value("nCoinControlSortOrder").toInt()))); sortView(settings.value("nCoinControlSortColumn").toInt(), (static_cast<Qt::SortOrder>(settings.value("nCoinControlSortOrder").toInt())));
GUIUtil::handleCloseWindowShortcut(this); GUIUtil::handleCloseWindowShortcut(this);
if(_model->getOptionsModel() && _model->getAddressTableModel())
{
updateView();
updateLabelLocked();
CoinControlDialog::updateLabels(m_coin_control, _model, this);
}
} }
CoinControlDialog::~CoinControlDialog() CoinControlDialog::~CoinControlDialog()
@ -148,18 +156,6 @@ CoinControlDialog::~CoinControlDialog()
delete ui; delete ui;
} }
void CoinControlDialog::setModel(WalletModel *_model)
{
this->model = _model;
if(_model && _model->getOptionsModel() && _model->getAddressTableModel())
{
updateView();
updateLabelLocked();
CoinControlDialog::updateLabels(_model, this);
}
}
// ok button // ok button
void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
{ {
@ -185,8 +181,8 @@ void CoinControlDialog::buttonSelectAllClicked()
ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state); ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state);
ui->treeWidget->setEnabled(true); ui->treeWidget->setEnabled(true);
if (state == Qt::Unchecked) if (state == Qt::Unchecked)
coinControl()->UnSelectAll(); // just to be sure m_coin_control.UnSelectAll(); // just to be sure
CoinControlDialog::updateLabels(model, this); CoinControlDialog::updateLabels(m_coin_control, model, this);
} }
// context menu // context menu
@ -371,15 +367,15 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
COutPoint outpt(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt()); COutPoint outpt(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt());
if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
coinControl()->UnSelect(outpt); m_coin_control.UnSelect(outpt);
else if (item->isDisabled()) // locked (this happens if "check all" through parent node) else if (item->isDisabled()) // locked (this happens if "check all" through parent node)
item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
else else
coinControl()->Select(outpt); m_coin_control.Select(outpt);
// selection changed -> update labels // selection changed -> update labels
if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all
CoinControlDialog::updateLabels(model, this); CoinControlDialog::updateLabels(m_coin_control, model, this);
} }
} }
@ -396,7 +392,7 @@ void CoinControlDialog::updateLabelLocked()
else ui->labelLocked->setVisible(false); else ui->labelLocked->setVisible(false);
} }
void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *model, QDialog* dialog)
{ {
if (!model) if (!model)
return; return;
@ -428,7 +424,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
bool fWitness = false; bool fWitness = false;
std::vector<COutPoint> vCoinControl; std::vector<COutPoint> vCoinControl;
coinControl()->ListSelected(vCoinControl); m_coin_control.ListSelected(vCoinControl);
size_t i = 0; size_t i = 0;
for (const auto& out : model->wallet().getCoins(vCoinControl)) { for (const auto& out : model->wallet().getCoins(vCoinControl)) {
@ -439,7 +435,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
const COutPoint& outpt = vCoinControl[i++]; const COutPoint& outpt = vCoinControl[i++];
if (out.is_spent) if (out.is_spent)
{ {
coinControl()->UnSelect(outpt); m_coin_control.UnSelect(outpt);
continue; continue;
} }
@ -492,7 +488,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34; nBytes -= 34;
// Fee // Fee
nPayFee = model->wallet().getMinimumFee(nBytes, *coinControl(), nullptr /* returned_target */, nullptr /* reason */); nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control, nullptr /* returned_target */, nullptr /* reason */);
if (nPayAmount > 0) if (nPayAmount > 0)
{ {
@ -584,12 +580,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
label->setVisible(nChange < 0); label->setVisible(nChange < 0);
} }
CCoinControl* CoinControlDialog::coinControl()
{
static CCoinControl coin_control;
return &coin_control;
}
void CoinControlDialog::updateView() void CoinControlDialog::updateView()
{ {
if (!model || !model->getOptionsModel() || !model->getAddressTableModel()) if (!model || !model->getOptionsModel() || !model->getAddressTableModel())
@ -690,13 +680,13 @@ void CoinControlDialog::updateView()
// disable locked coins // disable locked coins
if (model->wallet().isLockedCoin(output)) if (model->wallet().isLockedCoin(output))
{ {
coinControl()->UnSelect(output); // just to be sure m_coin_control.UnSelect(output); // just to be sure
itemOutput->setDisabled(true); itemOutput->setDisabled(true);
itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed")); itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
} }
// set checkbox // set checkbox
if (coinControl()->IsSelected(output)) if (m_coin_control.IsSelected(output))
itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
} }

View file

@ -43,20 +43,18 @@ class CoinControlDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = nullptr); explicit CoinControlDialog(CCoinControl& coin_control, WalletModel* model, const PlatformStyle *platformStyle, QWidget *parent = nullptr);
~CoinControlDialog(); ~CoinControlDialog();
void setModel(WalletModel *model);
// static because also called from sendcoinsdialog // static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*); static void updateLabels(CCoinControl& m_coin_control, WalletModel*, QDialog*);
static QList<CAmount> payAmounts; static QList<CAmount> payAmounts;
static CCoinControl *coinControl();
static bool fSubtractFeeFromAmount; static bool fSubtractFeeFromAmount;
private: private:
Ui::CoinControlDialog *ui; Ui::CoinControlDialog *ui;
CCoinControl& m_coin_control;
WalletModel *model; WalletModel *model;
int sortColumn; int sortColumn;
Qt::SortOrder sortOrder; Qt::SortOrder sortOrder;

View file

@ -57,6 +57,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
ui(new Ui::SendCoinsDialog), ui(new Ui::SendCoinsDialog),
clientModel(nullptr), clientModel(nullptr),
model(nullptr), model(nullptr),
m_coin_control(new CCoinControl),
fNewRecipientAllowed(true), fNewRecipientAllowed(true),
fFeeMinimized(true), fFeeMinimized(true),
platformStyle(_platformStyle) platformStyle(_platformStyle)
@ -259,14 +260,9 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
m_current_transaction = MakeUnique<WalletModelTransaction>(recipients); m_current_transaction = MakeUnique<WalletModelTransaction>(recipients);
WalletModel::SendCoinsReturn prepareStatus; WalletModel::SendCoinsReturn prepareStatus;
// Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled updateCoinControlState(*m_coin_control);
CCoinControl ctrl;
if (model->getOptionsModel()->getCoinControlFeatures())
ctrl = *CoinControlDialog::coinControl();
updateCoinControlState(ctrl); prepareStatus = model->prepareTransaction(*m_current_transaction, *m_coin_control);
prepareStatus = model->prepareTransaction(*m_current_transaction, ctrl);
// process prepareStatus and on error generate message shown to user // process prepareStatus and on error generate message shown to user
processSendCoinsReturn(prepareStatus, processSendCoinsReturn(prepareStatus,
@ -454,7 +450,7 @@ void SendCoinsDialog::on_sendButton_clicked()
} }
if (!send_failure) { if (!send_failure) {
accept(); accept();
CoinControlDialog::coinControl()->UnSelectAll(); m_coin_control->UnSelectAll();
coinControlUpdateLabels(); coinControlUpdateLabels();
} }
fNewRecipientAllowed = true; fNewRecipientAllowed = true;
@ -466,7 +462,7 @@ void SendCoinsDialog::clear()
m_current_transaction.reset(); m_current_transaction.reset();
// Clear coin control settings // Clear coin control settings
CoinControlDialog::coinControl()->UnSelectAll(); m_coin_control->UnSelectAll();
ui->checkBoxCoinControlChange->setChecked(false); ui->checkBoxCoinControlChange->setChecked(false);
ui->lineEditCoinControlChange->clear(); ui->lineEditCoinControlChange->clear();
coinControlUpdateLabels(); coinControlUpdateLabels();
@ -689,17 +685,11 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry) void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
{ {
// Get CCoinControl instance if CoinControl is enabled or create a new one.
CCoinControl coin_control;
if (model->getOptionsModel()->getCoinControlFeatures()) {
coin_control = *CoinControlDialog::coinControl();
}
// Include watch-only for wallets without private key // Include watch-only for wallets without private key
coin_control.fAllowWatchOnly = model->wallet().privateKeysDisabled(); m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled();
// Calculate available amount to send. // Calculate available amount to send.
CAmount amount = model->wallet().getAvailableBalance(coin_control); CAmount amount = model->wallet().getAvailableBalance(*m_coin_control);
for (int i = 0; i < ui->entries->count(); ++i) { for (int i = 0; i < ui->entries->count(); ++i) {
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if (e && !e->isHidden() && e != entry) { if (e && !e->isHidden() && e != entry) {
@ -758,12 +748,11 @@ void SendCoinsDialog::updateSmartFeeLabel()
{ {
if(!model || !model->getOptionsModel()) if(!model || !model->getOptionsModel())
return; return;
CCoinControl coin_control; updateCoinControlState(*m_coin_control);
updateCoinControlState(coin_control); m_coin_control->m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
int returned_target; int returned_target;
FeeReason reason; FeeReason reason;
CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, coin_control, &returned_target, &reason)); CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, *m_coin_control, &returned_target, &reason));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
@ -834,7 +823,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
ui->frameCoinControl->setVisible(checked); ui->frameCoinControl->setVisible(checked);
if (!checked && model) // coin control features disabled if (!checked && model) // coin control features disabled
CoinControlDialog::coinControl()->SetNull(); m_coin_control->SetNull();
coinControlUpdateLabels(); coinControlUpdateLabels();
} }
@ -842,8 +831,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
// Coin Control: button inputs -> show actual coin control dialog // Coin Control: button inputs -> show actual coin control dialog
void SendCoinsDialog::coinControlButtonClicked() void SendCoinsDialog::coinControlButtonClicked()
{ {
CoinControlDialog dlg(platformStyle); CoinControlDialog dlg(*m_coin_control, model, platformStyle);
dlg.setModel(model);
dlg.exec(); dlg.exec();
coinControlUpdateLabels(); coinControlUpdateLabels();
} }
@ -853,7 +841,7 @@ void SendCoinsDialog::coinControlChangeChecked(int state)
{ {
if (state == Qt::Unchecked) if (state == Qt::Unchecked)
{ {
CoinControlDialog::coinControl()->destChange = CNoDestination(); m_coin_control->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->clear(); ui->labelCoinControlChangeLabel->clear();
} }
else else
@ -869,7 +857,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
if (model && model->getAddressTableModel()) if (model && model->getAddressTableModel())
{ {
// Default to no change address until verified // Default to no change address until verified
CoinControlDialog::coinControl()->destChange = CNoDestination(); m_coin_control->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}"); ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
const CTxDestination dest = DecodeDestination(text.toStdString()); const CTxDestination dest = DecodeDestination(text.toStdString());
@ -892,7 +880,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Yes) if(btnRetVal == QMessageBox::Yes)
CoinControlDialog::coinControl()->destChange = dest; m_coin_control->destChange = dest;
else else
{ {
ui->lineEditCoinControlChange->setText(""); ui->lineEditCoinControlChange->setText("");
@ -911,7 +899,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
else else
ui->labelCoinControlChangeLabel->setText(tr("(no label)")); ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
CoinControlDialog::coinControl()->destChange = dest; m_coin_control->destChange = dest;
} }
} }
} }
@ -923,7 +911,7 @@ void SendCoinsDialog::coinControlUpdateLabels()
if (!model || !model->getOptionsModel()) if (!model || !model->getOptionsModel())
return; return;
updateCoinControlState(*CoinControlDialog::coinControl()); updateCoinControlState(*m_coin_control);
// set pay amounts // set pay amounts
CoinControlDialog::payAmounts.clear(); CoinControlDialog::payAmounts.clear();
@ -941,10 +929,10 @@ void SendCoinsDialog::coinControlUpdateLabels()
} }
} }
if (CoinControlDialog::coinControl()->HasSelected()) if (m_coin_control->HasSelected())
{ {
// actual coin control calculation // actual coin control calculation
CoinControlDialog::updateLabels(model, this); CoinControlDialog::updateLabels(*m_coin_control, model, this);
// show coin control stats // show coin control stats
ui->labelCoinControlAutomaticallySelected->hide(); ui->labelCoinControlAutomaticallySelected->hide();

View file

@ -12,6 +12,7 @@
#include <QString> #include <QString>
#include <QTimer> #include <QTimer>
class CCoinControl;
class ClientModel; class ClientModel;
class PlatformStyle; class PlatformStyle;
class SendCoinsEntry; class SendCoinsEntry;
@ -60,6 +61,7 @@ private:
Ui::SendCoinsDialog *ui; Ui::SendCoinsDialog *ui;
ClientModel *clientModel; ClientModel *clientModel;
WalletModel *model; WalletModel *model;
std::unique_ptr<CCoinControl> m_coin_control;
std::unique_ptr<WalletModelTransaction> m_current_transaction; std::unique_ptr<WalletModelTransaction> m_current_transaction;
bool fNewRecipientAllowed; bool fNewRecipientAllowed;
bool fFeeMinimized; bool fFeeMinimized;