Merge #14608: qt: Remove the "Pay only required fee..." checkbox

a16f44c04 qt: Remove "Pay only required fee" checkbox (Hennadii Stepanov)
8711cc0c7 qt: Improve BitcoinAmountField class (Hennadii Stepanov)

Pull request description:

  Ref #13280
  This PR removes the "Pay only the required fee..." checkbox from the custom transaction fee section in the "Send" tab. Instead, a minimum value will be enforced on the custom fee input box.

  All comments from #13280 are addressed.

  Before:
  ![screenshot from 2018-10-30 16-42-18](https://user-images.githubusercontent.com/32963518/47726622-866d8e80-dc63-11e8-8670-3f97ff0fa5da.png)

  After:
  ![screenshot from 2018-10-30 16-40-37](https://user-images.githubusercontent.com/32963518/47726633-8f5e6000-dc63-11e8-82cf-5b9ff4aae91d.png)

  cc: @promag @MarcoFalke @Sjors

Tree-SHA512: 073577d38d8353b10e8f36fb52e3c6e81dd45d25d84df9b9e4f78f452ff0bdbff3e225bdd6122b5a03839ffdcc2a2a08175f81c2541cf2d12918536abbfa3fd1
This commit is contained in:
Jonas Schnelli 2018-11-13 15:35:25 +07:00
commit 083f535470
No known key found for this signature in database
GPG key ID: 1EB776BB03C7922D
5 changed files with 75 additions and 81 deletions

View file

@ -23,9 +23,7 @@ class AmountSpinBox: public QAbstractSpinBox
public: public:
explicit AmountSpinBox(QWidget *parent): explicit AmountSpinBox(QWidget *parent):
QAbstractSpinBox(parent), QAbstractSpinBox(parent)
currentUnit(BitcoinUnits::BTC),
singleStep(100000) // satoshis
{ {
setAlignment(Qt::AlignRight); setAlignment(Qt::AlignRight);
@ -44,10 +42,19 @@ public:
void fixup(QString &input) const void fixup(QString &input) const
{ {
bool valid = false; bool valid;
CAmount val = parse(input, &valid); CAmount val;
if(valid)
{ if (input.isEmpty() && !m_allow_empty) {
valid = true;
val = m_min_amount;
} else {
valid = false;
val = parse(input, &valid);
}
if (valid) {
val = qBound(m_min_amount, val, m_max_amount);
input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways); input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways);
lineEdit()->setText(input); lineEdit()->setText(input);
} }
@ -64,12 +71,27 @@ public:
Q_EMIT valueChanged(); Q_EMIT valueChanged();
} }
void SetAllowEmpty(bool allow)
{
m_allow_empty = allow;
}
void SetMinValue(const CAmount& value)
{
m_min_amount = value;
}
void SetMaxValue(const CAmount& value)
{
m_max_amount = value;
}
void stepBy(int steps) void stepBy(int steps)
{ {
bool valid = false; bool valid = false;
CAmount val = value(&valid); CAmount val = value(&valid);
val = val + steps * singleStep; val = val + steps * singleStep;
val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney()); val = qBound(m_min_amount, val, m_max_amount);
setValue(val); setValue(val);
} }
@ -125,9 +147,12 @@ public:
} }
private: private:
int currentUnit; int currentUnit{BitcoinUnits::BTC};
CAmount singleStep; CAmount singleStep{CAmount(100000)}; // satoshis
mutable QSize cachedMinimumSizeHint; mutable QSize cachedMinimumSizeHint;
bool m_allow_empty{true};
CAmount m_min_amount{CAmount(0)};
CAmount m_max_amount{BitcoinUnits::maxMoney()};
/** /**
* Parse a string into a number of base monetary units and * Parse a string into a number of base monetary units and
@ -174,11 +199,10 @@ protected:
StepEnabled rv = 0; StepEnabled rv = 0;
bool valid = false; bool valid = false;
CAmount val = value(&valid); CAmount val = value(&valid);
if(valid) if (valid) {
{ if (val > m_min_amount)
if(val > 0)
rv |= StepDownEnabled; rv |= StepDownEnabled;
if(val < BitcoinUnits::maxMoney()) if (val < m_max_amount)
rv |= StepUpEnabled; rv |= StepUpEnabled;
} }
return rv; return rv;
@ -275,6 +299,21 @@ void BitcoinAmountField::setValue(const CAmount& value)
amount->setValue(value); amount->setValue(value);
} }
void BitcoinAmountField::SetAllowEmpty(bool allow)
{
amount->SetAllowEmpty(allow);
}
void BitcoinAmountField::SetMinValue(const CAmount& value)
{
amount->SetMinValue(value);
}
void BitcoinAmountField::SetMaxValue(const CAmount& value)
{
amount->SetMaxValue(value);
}
void BitcoinAmountField::setReadOnly(bool fReadOnly) void BitcoinAmountField::setReadOnly(bool fReadOnly)
{ {
amount->setReadOnly(fReadOnly); amount->setReadOnly(fReadOnly);

View file

@ -31,6 +31,15 @@ public:
CAmount value(bool *value=0) const; CAmount value(bool *value=0) const;
void setValue(const CAmount& value); void setValue(const CAmount& value);
/** If allow empty is set to false the field will be set to the minimum allowed value if left empty. **/
void SetAllowEmpty(bool allow);
/** Set the minimum value in satoshis **/
void SetMinValue(const CAmount& value);
/** Set the maximum value in satoshis **/
void SetMaxValue(const CAmount& value);
/** Set single step in satoshis **/ /** Set single step in satoshis **/
void setSingleStep(const CAmount& step); void setSingleStep(const CAmount& step);

View file

@ -878,28 +878,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayoutFee8"> <layout class="QHBoxLayout" name="horizontalLayoutFee8">
<item> <item>
<widget class="QCheckBox" name="checkBoxMinimumFee"> <widget class="QLabel" name="labelCustomFeeWarning">
<property name="toolTip">
<string>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelMinFeeWarning">
<property name="enabled"> <property name="enabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</string> <string>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</string>
</property> </property>
<property name="text"> <property name="text">
<string>(read the tooltip)</string> <string>A too low fee might result in a never confirming transaction (read the tooltip)</string>
</property>
<property name="margin">
<number>5</number>
</property> </property>
</widget> </widget>
</item> </item>
@ -992,9 +979,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="margin">
<number>2</number>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -1009,9 +993,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<property name="text"> <property name="text">
<string>(Smart fee not initialized yet. This usually takes a few blocks...)</string> <string>(Smart fee not initialized yet. This usually takes a few blocks...)</string>
</property> </property>
<property name="margin">
<number>2</number>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -1038,24 +1019,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<property name="text"> <property name="text">
<string>Confirmation time target:</string> <string>Confirmation time target:</string>
</property> </property>
<property name="margin">
<number>2</number>
</property>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View file

@ -119,13 +119,11 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
settings.setValue("nSmartFeeSliderPosition", 0); settings.setValue("nSmartFeeSliderPosition", 0);
if (!settings.contains("nTransactionFee")) if (!settings.contains("nTransactionFee"))
settings.setValue("nTransactionFee", (qint64)DEFAULT_PAY_TX_FEE); settings.setValue("nTransactionFee", (qint64)DEFAULT_PAY_TX_FEE);
if (!settings.contains("fPayOnlyMinFee"))
settings.setValue("fPayOnlyMinFee", false);
ui->groupFee->setId(ui->radioSmartFee, 0); ui->groupFee->setId(ui->radioSmartFee, 0);
ui->groupFee->setId(ui->radioCustomFee, 1); ui->groupFee->setId(ui->radioCustomFee, 1);
ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true); ui->groupFee->button((int)std::max(0, std::min(1, settings.value("nFeeRadio").toInt())))->setChecked(true);
ui->customFee->SetAllowEmpty(false);
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
} }
@ -174,14 +172,15 @@ void SendCoinsDialog::setModel(WalletModel *_model)
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls); connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels); connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels); connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::setMinimumFee);
connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateFeeSectionControls);
connect(ui->checkBoxMinimumFee, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel); connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel);
connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels); connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
ui->customFee->setSingleStep(model->wallet().getRequiredFee(1000)); CAmount requiredFee = model->wallet().getRequiredFee(1000);
ui->customFee->SetMinValue(requiredFee);
if (ui->customFee->value() < requiredFee) {
ui->customFee->setValue(requiredFee);
}
ui->customFee->setSingleStep(requiredFee);
updateFeeSectionControls(); updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel(); updateSmartFeeLabel();
// set default rbf checkbox state // set default rbf checkbox state
@ -210,7 +209,6 @@ SendCoinsDialog::~SendCoinsDialog()
settings.setValue("nFeeRadio", ui->groupFee->checkedId()); settings.setValue("nFeeRadio", ui->groupFee->checkedId());
settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex())); settings.setValue("nConfTarget", getConfTargetForIndex(ui->confTargetSelector->currentIndex()));
settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("nTransactionFee", (qint64)ui->customFee->value());
settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked());
delete ui; delete ui;
} }
@ -542,7 +540,6 @@ void SendCoinsDialog::updateDisplayUnit()
{ {
setBalance(model->wallet().getBalances()); setBalance(model->wallet().getBalances());
ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
updateMinFeeLabel();
updateSmartFeeLabel(); updateSmartFeeLabel();
} }
@ -642,11 +639,6 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
} }
} }
void SendCoinsDialog::setMinimumFee()
{
ui->customFee->setValue(model->wallet().getRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls() void SendCoinsDialog::updateFeeSectionControls()
{ {
ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked()); ui->confTargetSelector ->setEnabled(ui->radioSmartFee->isChecked());
@ -654,10 +646,9 @@ void SendCoinsDialog::updateFeeSectionControls()
ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFee2 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFee3 ->setEnabled(ui->radioSmartFee->isChecked());
ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked()); ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked());
ui->checkBoxMinimumFee ->setEnabled(ui->radioCustomFee->isChecked()); ui->labelCustomFeeWarning ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelMinFeeWarning ->setEnabled(ui->radioCustomFee->isChecked()); ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked());
ui->labelCustomPerKilobyte ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked());
ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked());
} }
void SendCoinsDialog::updateFeeMinimizedLabel() void SendCoinsDialog::updateFeeMinimizedLabel()
@ -672,14 +663,6 @@ void SendCoinsDialog::updateFeeMinimizedLabel()
} }
} }
void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getRequiredFee(1000)) + "/kB")
);
}
void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl) void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
{ {
if (ui->radioCustomFee->isChecked()) { if (ui->radioCustomFee->isChecked()) {

View file

@ -92,9 +92,7 @@ private Q_SLOTS:
void coinControlClipboardBytes(); void coinControlClipboardBytes();
void coinControlClipboardLowOutput(); void coinControlClipboardLowOutput();
void coinControlClipboardChange(); void coinControlClipboardChange();
void setMinimumFee();
void updateFeeSectionControls(); void updateFeeSectionControls();
void updateMinFeeLabel();
void updateSmartFeeLabel(); void updateSmartFeeLabel();
Q_SIGNALS: Q_SIGNALS: