mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 14:38:29 +01:00
[Qt] Add Smartfee to GUI
This commit is contained in:
@@ -7,10 +7,12 @@
|
||||
|
||||
#include "addresstablemodel.h"
|
||||
#include "bitcoinunits.h"
|
||||
#include "clientmodel.h"
|
||||
#include "coincontroldialog.h"
|
||||
#include "guiutil.h"
|
||||
#include "optionsmodel.h"
|
||||
#include "sendcoinsentry.h"
|
||||
#include "wallet.h"
|
||||
#include "walletmodel.h"
|
||||
|
||||
#include "base58.h"
|
||||
@@ -19,6 +21,7 @@
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
#include <QTextDocument>
|
||||
|
||||
SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
|
||||
@@ -72,9 +75,46 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
|
||||
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
|
||||
ui->labelCoinControlChange->addAction(clipboardChangeAction);
|
||||
|
||||
// init transaction fee section
|
||||
QSettings settings;
|
||||
if (!settings.contains("fFeeSectionMinimized"))
|
||||
settings.setValue("fFeeSectionMinimized", true);
|
||||
if (!settings.contains("nFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
|
||||
settings.setValue("nFeeRadio", 1); // custom
|
||||
if (!settings.contains("nFeeRadio"))
|
||||
settings.setValue("nFeeRadio", 0); // recommended
|
||||
if (!settings.contains("nCustomFeeRadio") && settings.contains("nTransactionFee") && settings.value("nTransactionFee").toLongLong() > 0) // compatibility
|
||||
settings.setValue("nCustomFeeRadio", 1); // total at least
|
||||
if (!settings.contains("nCustomFeeRadio"))
|
||||
settings.setValue("nCustomFeeRadio", 0); // per kilobyte
|
||||
if (!settings.contains("nSmartFeeSliderPosition"))
|
||||
settings.setValue("nSmartFeeSliderPosition", 0);
|
||||
if (!settings.contains("nTransactionFee"))
|
||||
settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
|
||||
if (!settings.contains("fPayOnlyMinFee"))
|
||||
settings.setValue("fPayOnlyMinFee", false);
|
||||
if (!settings.contains("fSendFreeTransactions"))
|
||||
settings.setValue("fSendFreeTransactions", false);
|
||||
ui->groupFee->setId(ui->radioSmartFee, 0);
|
||||
ui->groupFee->setId(ui->radioCustomFee, 1);
|
||||
ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
|
||||
ui->groupCustomFee->setId(ui->radioCustomPerKilobyte, 0);
|
||||
ui->groupCustomFee->setId(ui->radioCustomAtLeast, 1);
|
||||
ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);
|
||||
ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt());
|
||||
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
|
||||
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
|
||||
ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool());
|
||||
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
|
||||
|
||||
fNewRecipientAllowed = true;
|
||||
}
|
||||
|
||||
void SendCoinsDialog::setClientModel(ClientModel *clientModel)
|
||||
{
|
||||
this->clientModel = clientModel;
|
||||
}
|
||||
|
||||
void SendCoinsDialog::setModel(WalletModel *model)
|
||||
{
|
||||
this->model = model;
|
||||
@@ -94,18 +134,51 @@ void SendCoinsDialog::setModel(WalletModel *model)
|
||||
model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
|
||||
connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
|
||||
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||
updateDisplayUnit();
|
||||
|
||||
// Coin Control
|
||||
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
|
||||
connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(CAmount)), this, SLOT(coinControlUpdateLabels()));
|
||||
ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures());
|
||||
coinControlUpdateLabels();
|
||||
|
||||
// fee section
|
||||
connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(updateSmartFeeLabel()));
|
||||
connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateSmartFeeLabel()));
|
||||
connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->sliderSmartFee, SIGNAL(valueChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateFeeSectionControls()));
|
||||
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->groupFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->groupCustomFee, SIGNAL(buttonClicked(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->customFee, SIGNAL(valueChanged()), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee()));
|
||||
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls()));
|
||||
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
|
||||
connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
|
||||
ui->customFee->setSingleStep(CWallet::minTxFee.GetFeePerK());
|
||||
updateFeeSectionControls();
|
||||
updateMinFeeLabel();
|
||||
updateSmartFeeLabel();
|
||||
updateGlobalFeeVariables();
|
||||
}
|
||||
}
|
||||
|
||||
SendCoinsDialog::~SendCoinsDialog()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("fFeeSectionMinimized", fFeeMinimized);
|
||||
settings.setValue("nFeeRadio", ui->groupFee->checkedId());
|
||||
settings.setValue("nCustomFeeRadio", ui->groupCustomFee->checkedId());
|
||||
settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value());
|
||||
settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
|
||||
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
|
||||
settings.setValue("fSendFreeTransactions", ui->checkBoxFreeTx->isChecked());
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
@@ -214,6 +287,9 @@ void SendCoinsDialog::on_sendButton_clicked()
|
||||
questionString.append(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), txFee));
|
||||
questionString.append("</span> ");
|
||||
questionString.append(tr("added as transaction fee"));
|
||||
|
||||
// append transaction size
|
||||
questionString.append(" (" + QString::number((double)currentTransaction.getTransactionSize() / 1000) + " kB)");
|
||||
}
|
||||
|
||||
// add total amount in all subdivision units
|
||||
@@ -402,6 +478,9 @@ void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfir
|
||||
void SendCoinsDialog::updateDisplayUnit()
|
||||
{
|
||||
setBalance(model->getBalance(), 0, 0, 0, 0, 0);
|
||||
ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
|
||||
updateMinFeeLabel();
|
||||
updateSmartFeeLabel();
|
||||
}
|
||||
|
||||
void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg)
|
||||
@@ -438,6 +517,9 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
|
||||
msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
|
||||
msgParams.second = CClientUIInterface::MSG_ERROR;
|
||||
break;
|
||||
case WalletModel::InsaneFee:
|
||||
msgParams.first = tr("A fee higher than %1 is considered an insanely high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000));
|
||||
break;
|
||||
// included to prevent a compiler warning.
|
||||
case WalletModel::OK:
|
||||
default:
|
||||
@@ -447,6 +529,110 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
|
||||
emit message(tr("Send Coins"), msgParams.first, msgParams.second);
|
||||
}
|
||||
|
||||
void SendCoinsDialog::minimizeFeeSection(bool fMinimize)
|
||||
{
|
||||
ui->labelFeeMinimized->setVisible(fMinimize);
|
||||
ui->buttonChooseFee ->setVisible(fMinimize);
|
||||
ui->buttonMinimizeFee->setVisible(!fMinimize);
|
||||
ui->frameFeeSelection->setVisible(!fMinimize);
|
||||
ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);
|
||||
fFeeMinimized = fMinimize;
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_buttonChooseFee_clicked()
|
||||
{
|
||||
minimizeFeeSection(false);
|
||||
}
|
||||
|
||||
void SendCoinsDialog::on_buttonMinimizeFee_clicked()
|
||||
{
|
||||
updateFeeMinimizedLabel();
|
||||
minimizeFeeSection(true);
|
||||
}
|
||||
|
||||
void SendCoinsDialog::setMinimumFee()
|
||||
{
|
||||
ui->radioCustomPerKilobyte->setChecked(true);
|
||||
ui->customFee->setValue(CWallet::minTxFee.GetFeePerK());
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateFeeSectionControls()
|
||||
{
|
||||
ui->sliderSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelSmartFee ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelSmartFeeNormal ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->labelSmartFeeFast ->setEnabled(ui->radioSmartFee->isChecked());
|
||||
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked());
|
||||
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
|
||||
ui->radioCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
|
||||
ui->radioCustomAtLeast ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
|
||||
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateGlobalFeeVariables()
|
||||
{
|
||||
if (ui->radioSmartFee->isChecked())
|
||||
{
|
||||
nTxConfirmTarget = (int)25 - (int)std::max(0, std::min(24, ui->sliderSmartFee->value()));
|
||||
payTxFee = CFeeRate(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
nTxConfirmTarget = 25;
|
||||
payTxFee = CFeeRate(ui->customFee->value());
|
||||
fPayAtLeastCustomFee = ui->radioCustomAtLeast->isChecked();
|
||||
}
|
||||
|
||||
fSendFreeTransactions = ui->checkBoxFreeTx->isChecked();
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateFeeMinimizedLabel()
|
||||
{
|
||||
if(!model || !model->getOptionsModel())
|
||||
return;
|
||||
|
||||
if (ui->radioSmartFee->isChecked())
|
||||
ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
|
||||
else {
|
||||
ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) +
|
||||
((ui->radioCustomPerKilobyte->isChecked()) ? "/kB" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateMinFeeLabel()
|
||||
{
|
||||
if (model && model->getOptionsModel())
|
||||
ui->checkBoxMinimumFee->setText(tr("Pay only the minimum fee of %1").arg(
|
||||
BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB")
|
||||
);
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateSmartFeeLabel()
|
||||
{
|
||||
if(!model || !model->getOptionsModel())
|
||||
return;
|
||||
|
||||
int nBlocksToConfirm = (int)25 - (int)std::max(0, std::min(24, ui->sliderSmartFee->value()));
|
||||
CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm);
|
||||
if (feeRate <= CFeeRate(0)) // not enough data => minfee
|
||||
{
|
||||
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB");
|
||||
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
|
||||
ui->labelFeeEstimation->setText("");
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
|
||||
ui->labelSmartFee2->hide();
|
||||
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %1 block(s).").arg(nBlocksToConfirm));
|
||||
}
|
||||
|
||||
updateFeeMinimizedLabel();
|
||||
}
|
||||
|
||||
// Coin Control: copy label "Quantity" to clipboard
|
||||
void SendCoinsDialog::coinControlClipboardQuantity()
|
||||
{
|
||||
@@ -462,19 +648,19 @@ void SendCoinsDialog::coinControlClipboardAmount()
|
||||
// Coin Control: copy label "Fee" to clipboard
|
||||
void SendCoinsDialog::coinControlClipboardFee()
|
||||
{
|
||||
GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")));
|
||||
GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace("~", ""));
|
||||
}
|
||||
|
||||
// Coin Control: copy label "After fee" to clipboard
|
||||
void SendCoinsDialog::coinControlClipboardAfterFee()
|
||||
{
|
||||
GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")));
|
||||
GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace("~", ""));
|
||||
}
|
||||
|
||||
// Coin Control: copy label "Bytes" to clipboard
|
||||
void SendCoinsDialog::coinControlClipboardBytes()
|
||||
{
|
||||
GUIUtil::setClipboard(ui->labelCoinControlBytes->text());
|
||||
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", ""));
|
||||
}
|
||||
|
||||
// Coin Control: copy label "Priority" to clipboard
|
||||
@@ -492,7 +678,7 @@ void SendCoinsDialog::coinControlClipboardLowOutput()
|
||||
// Coin Control: copy label "Change" to clipboard
|
||||
void SendCoinsDialog::coinControlClipboardChange()
|
||||
{
|
||||
GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")));
|
||||
GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace("~", ""));
|
||||
}
|
||||
|
||||
// Coin Control: settings menu - coin control enabled/disabled by user
|
||||
|
||||
Reference in New Issue
Block a user