diff options
Diffstat (limited to 'src/qt/sendcoinsdialog.cpp')
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 206 |
1 files changed, 198 insertions, 8 deletions
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index ce94131cce..46eb58ca43 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -7,6 +7,7 @@ #include "addresstablemodel.h" #include "bitcoinunits.h" +#include "clientmodel.h" #include "coincontroldialog.h" #include "guiutil.h" #include "optionsmodel.h" @@ -16,15 +17,20 @@ #include "base58.h" #include "coincontrol.h" #include "ui_interface.h" +#include "wallet.h" #include <QMessageBox> #include <QScrollBar> +#include <QSettings> #include <QTextDocument> SendCoinsDialog::SendCoinsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), - model(0) + clientModel(0), + model(0), + fNewRecipientAllowed(true), + fFeeMinimized(true) { ui->setupUi(this); @@ -72,7 +78,46 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); ui->labelCoinControlChange->addAction(clipboardChangeAction); - fNewRecipientAllowed = true; + // 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()); +} + +void SendCoinsDialog::setClientModel(ClientModel *clientModel) +{ + this->clientModel = clientModel; + + if (clientModel) { + connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(updateSmartFeeLabel())); + } } void SendCoinsDialog::setModel(WalletModel *model) @@ -94,18 +139,50 @@ 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(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 +291,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 @@ -384,7 +464,7 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv) return true; } -void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, +void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchBalance, const CAmount& watchUnconfirmedBalance, const CAmount& watchImmatureBalance) { Q_UNUSED(unconfirmedBalance); @@ -402,6 +482,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 +521,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 +533,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 +652,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 +682,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 |