Changeset View
Changeset View
Standalone View
Standalone View
src/qt/sendcoinsdialog.cpp
Show All 27 Lines | |||||
#include <QScrollBar> | #include <QScrollBar> | ||||
#include <QSettings> | #include <QSettings> | ||||
#include <QTextDocument> | #include <QTextDocument> | ||||
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, | SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, | ||||
WalletModel *_model, QWidget *parent) | WalletModel *_model, QWidget *parent) | ||||
: QDialog(parent), ui(new Ui::SendCoinsDialog), clientModel(nullptr), | : QDialog(parent), ui(new Ui::SendCoinsDialog), clientModel(nullptr), | ||||
model(_model), fNewRecipientAllowed(true), fFeeMinimized(true), | model(_model), m_coin_control(new CCoinControl), | ||||
fNewRecipientAllowed(true), fFeeMinimized(true), | |||||
platformStyle(_platformStyle) { | platformStyle(_platformStyle) { | ||||
ui->setupUi(this); | ui->setupUi(this); | ||||
if (!_platformStyle->getImagesOnButtons()) { | if (!_platformStyle->getImagesOnButtons()) { | ||||
ui->addButton->setIcon(QIcon()); | ui->addButton->setIcon(QIcon()); | ||||
ui->clearButton->setIcon(QIcon()); | ui->clearButton->setIcon(QIcon()); | ||||
ui->sendButton->setIcon(QIcon()); | ui->sendButton->setIcon(QIcon()); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | if (!ctx.isValid()) { | ||||
return false; | return false; | ||||
} | } | ||||
// prepare transaction for getting txFee earlier | // prepare transaction for getting txFee earlier | ||||
m_current_transaction = | m_current_transaction = | ||||
std::make_unique<WalletModelTransaction>(recipients); | std::make_unique<WalletModelTransaction>(recipients); | ||||
WalletModel::SendCoinsReturn prepareStatus; | WalletModel::SendCoinsReturn prepareStatus; | ||||
// Always use a CCoinControl instance, use the CoinControlDialog instance if | updateCoinControlState(*m_coin_control); | ||||
// CoinControl has been enabled | |||||
CCoinControl ctrl; | |||||
if (model->getOptionsModel()->getCoinControlFeatures()) { | |||||
ctrl = *CoinControlDialog::coinControl(); | |||||
} | |||||
updateCoinControlState(ctrl); | |||||
prepareStatus = model->prepareTransaction(*m_current_transaction, ctrl); | prepareStatus = | ||||
model->prepareTransaction(*m_current_transaction, *m_coin_control); | |||||
// process prepareStatus and on error generate message shown to user | // process prepareStatus and on error generate message shown to user | ||||
processSendCoinsReturn(prepareStatus, | processSendCoinsReturn(prepareStatus, | ||||
BitcoinUnits::formatWithUnit( | BitcoinUnits::formatWithUnit( | ||||
model->getOptionsModel()->getDisplayUnit(), | model->getOptionsModel()->getDisplayUnit(), | ||||
m_current_transaction->getTransactionFee())); | m_current_transaction->getTransactionFee())); | ||||
if (prepareStatus.status != WalletModel::OK) { | if (prepareStatus.status != WalletModel::OK) { | ||||
▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | if (model->wallet().privateKeysDisabled()) { | ||||
if (sendStatus.status == WalletModel::OK) { | if (sendStatus.status == WalletModel::OK) { | ||||
Q_EMIT coinsSent(m_current_transaction->getWtx()->GetId()); | Q_EMIT coinsSent(m_current_transaction->getWtx()->GetId()); | ||||
} else { | } else { | ||||
send_failure = true; | send_failure = true; | ||||
} | } | ||||
} | } | ||||
if (!send_failure) { | if (!send_failure) { | ||||
accept(); | accept(); | ||||
CoinControlDialog::coinControl()->UnSelectAll(); | m_coin_control->UnSelectAll(); | ||||
coinControlUpdateLabels(); | coinControlUpdateLabels(); | ||||
} | } | ||||
fNewRecipientAllowed = true; | fNewRecipientAllowed = true; | ||||
m_current_transaction.reset(); | m_current_transaction.reset(); | ||||
} | } | ||||
void SendCoinsDialog::clear() { | 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(); | ||||
// Remove entries until only one left | // Remove entries until only one left | ||||
while (ui->entries->count()) { | while (ui->entries->count()) { | ||||
ui->entries->takeAt(0)->widget()->deleteLater(); | ui->entries->takeAt(0)->widget()->deleteLater(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void SendCoinsDialog::on_buttonMinimizeFee_clicked() { | void SendCoinsDialog::on_buttonMinimizeFee_clicked() { | ||||
updateFeeMinimizedLabel(); | updateFeeMinimizedLabel(); | ||||
minimizeFeeSection(true); | minimizeFeeSection(true); | ||||
} | } | ||||
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. | ||||
Amount amount = model->wallet().getAvailableBalance(coin_control); | Amount 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 = | SendCoinsEntry *e = | ||||
qobject_cast<SendCoinsEntry *>(ui->entries->itemAt(i)->widget()); | qobject_cast<SendCoinsEntry *>(ui->entries->itemAt(i)->widget()); | ||||
if (e && !e->isHidden() && e != entry) { | if (e && !e->isHidden() && e != entry) { | ||||
amount -= e->getValue().amount; | amount -= e->getValue().amount; | ||||
} | } | ||||
} | } | ||||
Show All 40 Lines | void SendCoinsDialog::updateCoinControlState(CCoinControl &ctrl) { | ||||
ctrl.fAllowWatchOnly = model->wallet().privateKeysDisabled(); | ctrl.fAllowWatchOnly = model->wallet().privateKeysDisabled(); | ||||
} | } | ||||
void SendCoinsDialog::updateSmartFeeLabel() { | void SendCoinsDialog::updateSmartFeeLabel() { | ||||
if (!model || !model->getOptionsModel()) { | if (!model || !model->getOptionsModel()) { | ||||
return; | return; | ||||
} | } | ||||
CCoinControl coin_control; | updateCoinControlState(*m_coin_control); | ||||
updateCoinControlState(coin_control); | |||||
// Explicitly use only fee estimation rate for smart fee labels | // Explicitly use only fee estimation rate for smart fee labels | ||||
coin_control.m_feerate.reset(); | m_coin_control->m_feerate.reset(); | ||||
CFeeRate feeRate(model->wallet().getMinimumFee(1000, coin_control)); | CFeeRate feeRate(model->wallet().getMinimumFee(1000, *m_coin_control)); | ||||
ui->labelSmartFee->setText( | ui->labelSmartFee->setText( | ||||
BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), | BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), | ||||
feeRate.GetFeePerK()) + | feeRate.GetFeePerK()) + | ||||
"/kB"); | "/kB"); | ||||
// not enough data => minfee | // not enough data => minfee | ||||
if (feeRate <= CFeeRate(Amount::zero())) { | if (feeRate <= CFeeRate(Amount::zero())) { | ||||
// (Smart fee not initialized yet. This usually takes a few blocks...) | // (Smart fee not initialized yet. This usually takes a few blocks...) | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
// Coin Control: settings menu - coin control enabled/disabled by user | // Coin Control: settings menu - coin control enabled/disabled by user | ||||
void SendCoinsDialog::coinControlFeatureChanged(bool checked) { | void SendCoinsDialog::coinControlFeatureChanged(bool checked) { | ||||
ui->frameCoinControl->setVisible(checked); | ui->frameCoinControl->setVisible(checked); | ||||
// coin control features disabled | // coin control features disabled | ||||
if (!checked && model) { | if (!checked && model) { | ||||
CoinControlDialog::coinControl()->SetNull(); | m_coin_control->SetNull(); | ||||
} | } | ||||
coinControlUpdateLabels(); | coinControlUpdateLabels(); | ||||
} | } | ||||
// 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(); | ||||
} | } | ||||
// Coin Control: checkbox custom change address | // Coin Control: checkbox custom change address | ||||
void SendCoinsDialog::coinControlChangeChecked(int state) { | 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 { | ||||
// use this to re-validate an already entered address | // use this to re-validate an already entered address | ||||
coinControlChangeEdited(ui->lineEditCoinControlChange->text()); | coinControlChangeEdited(ui->lineEditCoinControlChange->text()); | ||||
} | } | ||||
ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked)); | ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked)); | ||||
} | } | ||||
// Coin Control: custom change address changed | // Coin Control: custom change address changed | ||||
void SendCoinsDialog::coinControlChangeEdited(const QString &text) { | 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 = | const CTxDestination dest = | ||||
DecodeDestination(text.toStdString(), model->getChainParams()); | DecodeDestination(text.toStdString(), model->getChainParams()); | ||||
if (text.isEmpty()) { | if (text.isEmpty()) { | ||||
// Nothing entered | // Nothing entered | ||||
ui->labelCoinControlChangeLabel->setText(""); | ui->labelCoinControlChangeLabel->setText(""); | ||||
Show All 12 Lines | if (model && model->getAddressTableModel()) { | ||||
this, tr("Confirm custom change address"), | this, tr("Confirm custom change address"), | ||||
tr("The address you selected for change is not part of " | tr("The address you selected for change is not part of " | ||||
"this wallet. Any or all funds in your wallet may be " | "this wallet. Any or all funds in your wallet may be " | ||||
"sent to this address. Are you sure?"), | "sent to this address. Are you sure?"), | ||||
QMessageBox::Yes | QMessageBox::Cancel, | QMessageBox::Yes | QMessageBox::Cancel, | ||||
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(""); | ||||
ui->labelCoinControlChangeLabel->setStyleSheet( | ui->labelCoinControlChangeLabel->setStyleSheet( | ||||
"QLabel{color:black;}"); | "QLabel{color:black;}"); | ||||
ui->labelCoinControlChangeLabel->setText(""); | ui->labelCoinControlChangeLabel->setText(""); | ||||
} | } | ||||
} else { | } else { | ||||
// Known change address | // Known change address | ||||
ui->labelCoinControlChangeLabel->setStyleSheet( | ui->labelCoinControlChangeLabel->setStyleSheet( | ||||
"QLabel{color:black;}"); | "QLabel{color:black;}"); | ||||
// Query label | // Query label | ||||
QString associatedLabel = | QString associatedLabel = | ||||
model->getAddressTableModel()->labelForAddress(text); | model->getAddressTableModel()->labelForAddress(text); | ||||
if (!associatedLabel.isEmpty()) { | if (!associatedLabel.isEmpty()) { | ||||
ui->labelCoinControlChangeLabel->setText(associatedLabel); | ui->labelCoinControlChangeLabel->setText(associatedLabel); | ||||
} else { | } else { | ||||
ui->labelCoinControlChangeLabel->setText(tr("(no label)")); | ui->labelCoinControlChangeLabel->setText(tr("(no label)")); | ||||
} | } | ||||
CoinControlDialog::coinControl()->destChange = dest; | m_coin_control->destChange = dest; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Coin Control: update labels | // Coin Control: update labels | ||||
void SendCoinsDialog::coinControlUpdateLabels() { | 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(); | ||||
CoinControlDialog::fSubtractFeeFromAmount = false; | CoinControlDialog::fSubtractFeeFromAmount = false; | ||||
for (int i = 0; i < ui->entries->count(); ++i) { | for (int i = 0; i < ui->entries->count(); ++i) { | ||||
SendCoinsEntry *entry = | SendCoinsEntry *entry = | ||||
qobject_cast<SendCoinsEntry *>(ui->entries->itemAt(i)->widget()); | qobject_cast<SendCoinsEntry *>(ui->entries->itemAt(i)->widget()); | ||||
if (entry && !entry->isHidden()) { | if (entry && !entry->isHidden()) { | ||||
SendCoinsRecipient rcp = entry->getValue(); | SendCoinsRecipient rcp = entry->getValue(); | ||||
CoinControlDialog::payAmounts.append(rcp.amount); | CoinControlDialog::payAmounts.append(rcp.amount); | ||||
if (rcp.fSubtractFeeFromAmount) { | if (rcp.fSubtractFeeFromAmount) { | ||||
CoinControlDialog::fSubtractFeeFromAmount = true; | CoinControlDialog::fSubtractFeeFromAmount = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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(); | ||||
ui->widgetCoinControl->show(); | ui->widgetCoinControl->show(); | ||||
} else { | } else { | ||||
// hide coin control stats | // hide coin control stats | ||||
ui->labelCoinControlAutomaticallySelected->show(); | ui->labelCoinControlAutomaticallySelected->show(); | ||||
ui->widgetCoinControl->hide(); | ui->widgetCoinControl->hide(); | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |