diff options
Diffstat (limited to 'src/qt/sendcoinsdialog.cpp')
| -rw-r--r-- | src/qt/sendcoinsdialog.cpp | 255 |
1 files changed, 171 insertions, 84 deletions
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index a1da6a481..0df6c5b20 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,35 +16,41 @@ #include "walletmodel.h" #include "base58.h" -#include "coincontrol.h" -#include "main.h" +#include "chainparams.h" +#include "wallet/coincontrol.h" +#include "validation.h" // mempool and minRelayTxFee #include "ui_interface.h" +#include "txmempool.h" #include "wallet/wallet.h" +#include <QFontMetrics> #include <QMessageBox> #include <QScrollBar> #include <QSettings> #include <QTextDocument> +#include <QTimer> -SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : +#define SEND_CONFIRM_DELAY 3 + +SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), clientModel(0), model(0), fNewRecipientAllowed(true), fFeeMinimized(true), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); - if (!platformStyle->getImagesOnButtons()) { + if (!_platformStyle->getImagesOnButtons()) { ui->addButton->setIcon(QIcon()); ui->clearButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon()); } else { - ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add")); - ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); - ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send")); + ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add")); + ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); + ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send")); } GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this); @@ -65,7 +71,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this); QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); - QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this); QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); @@ -73,7 +78,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee())); connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee())); connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes())); - connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority())); connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput())); connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange())); ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); @@ -81,7 +85,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa ui->labelCoinControlFee->addAction(clipboardFeeAction); ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); ui->labelCoinControlBytes->addAction(clipboardBytesAction); - ui->labelCoinControlPriority->addAction(clipboardPriorityAction); ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); ui->labelCoinControlChange->addAction(clipboardChangeAction); @@ -103,57 +106,51 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa settings.setValue("nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE); if (!settings.contains("fPayOnlyMinFee")) settings.setValue("fPayOnlyMinFee", false); - // Dogecoin: Disable free transactions - /* 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()); - // Dogecoin: Disable free transactions - // ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool()); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } -void SendCoinsDialog::setClientModel(ClientModel *clientModel) +void SendCoinsDialog::setClientModel(ClientModel *_clientModel) { - this->clientModel = clientModel; + this->clientModel = _clientModel; - if (clientModel) { - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(updateSmartFeeLabel())); + if (_clientModel) { + connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel())); } } -void SendCoinsDialog::setModel(WalletModel *model) +void SendCoinsDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; - if(model && model->getOptionsModel()) + if(_model && _model->getOptionsModel()) { for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); if(entry) { - entry->setModel(model); + entry->setModel(_model); } } - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), - 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())); + setBalance(_model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(), + _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))); - ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); + connect(_model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures()); coinControlUpdateLabels(); // fee section @@ -171,14 +168,18 @@ void SendCoinsDialog::setModel(WalletModel *model) 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())); - // Dogecoin: Disable free transactions - // connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); - // connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - ui->customFee->setSingleStep(CWallet::minTxFee.GetFeePerK()); + ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000)); updateFeeSectionControls(); updateMinFeeLabel(); updateSmartFeeLabel(); updateGlobalFeeVariables(); + + // set the smartfee-sliders default value (wallets default conf.target or last stored value) + QSettings settings; + if (settings.value("nSmartFeeSliderPosition").toInt() == 0) + ui->sliderSmartFee->setValue(ui->sliderSmartFee->maximum() - model->getDefaultConfirmTarget() + 2); + else + ui->sliderSmartFee->setValue(settings.value("nSmartFeeSliderPosition").toInt()); } } @@ -191,8 +192,6 @@ SendCoinsDialog::~SendCoinsDialog() settings.setValue("nSmartFeeSliderPosition", ui->sliderSmartFee->value()); settings.setValue("nTransactionFee", (qint64)ui->customFee->value()); settings.setValue("fPayOnlyMinFee", ui->checkBoxMinimumFee->isChecked()); - // Dogecoin: Disable free transactions - // settings.setValue("fSendFreeTransactions", ui->checkBoxFreeTx->isChecked()); delete ui; } @@ -238,10 +237,17 @@ void SendCoinsDialog::on_sendButton_clicked() // prepare transaction for getting txFee earlier WalletModelTransaction currentTransaction(recipients); WalletModel::SendCoinsReturn prepareStatus; - if (model->getOptionsModel()->getCoinControlFeatures()) // coin control enabled - prepareStatus = model->prepareTransaction(currentTransaction, CoinControlDialog::coinControl); + + // Always use a CCoinControl instance, use the CoinControlDialog instance if CoinControl has been enabled + CCoinControl ctrl; + if (model->getOptionsModel()->getCoinControlFeatures()) + ctrl = *CoinControlDialog::coinControl; + if (ui->radioSmartFee->isChecked()) + ctrl.nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2; else - prepareStatus = model->prepareTransaction(currentTransaction); + ctrl.nConfirmTarget = 0; + + prepareStatus = model->prepareTransaction(currentTransaction, &ctrl); // process prepareStatus and on error generate message shown to user processSendCoinsReturn(prepareStatus, @@ -256,7 +262,7 @@ void SendCoinsDialog::on_sendButton_clicked() // Format confirmation message QStringList formatted; - foreach(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) + Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) { // generate bold amount string QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); @@ -310,19 +316,20 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append("<hr />"); CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; QStringList alternativeUnits; - foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) + Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); } - questionString.append(tr("Total Amount %1 (= %2)") - .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount)) - .arg(alternativeUnits.join(" " + tr("or") + " "))); + questionString.append(tr("Total Amount %1") + .arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))); + questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>") + .arg(alternativeUnits.join(" " + tr("or") + "<br />"))); - QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"), - questionString.arg(formatted.join("<br />")), - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); + SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), + questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this); + confirmationDialog.exec(); + QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result(); if(retval != QMessageBox::Yes) { @@ -375,8 +382,6 @@ SendCoinsEntry *SendCoinsDialog::addEntry() connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels())); connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels())); - updateTabsAndLabels(); - // Focus the field, so that entry can start immediately entry->clear(); entry->setFocus(); @@ -385,6 +390,8 @@ SendCoinsEntry *SendCoinsDialog::addEntry() QScrollBar* bar = ui->scrollArea->verticalScrollBar(); if(bar) bar->setSliderPosition(bar->maximum()); + + updateTabsAndLabels(); return entry; } @@ -529,11 +536,11 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.second = CClientUIInterface::MSG_ERROR; break; case WalletModel::TransactionCommitFailed: - 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.first = tr("The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.reasonCommitFailed); msgParams.second = CClientUIInterface::MSG_ERROR; break; case WalletModel::AbsurdFee: - msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 100 * COIN)); + msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), maxTxFee)); break; case WalletModel::PaymentRequestExpired: msgParams.first = tr("Payment request expired."); @@ -545,7 +552,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn return; } - emit message(tr("Send Coins"), msgParams.first, msgParams.second); + Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second); } void SendCoinsDialog::minimizeFeeSection(bool fMinimize) @@ -572,7 +579,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked() void SendCoinsDialog::setMinimumFee() { ui->radioCustomPerKilobyte->setChecked(true); - ui->customFee->setValue(CWallet::minTxFee.GetFeePerK()); + ui->customFee->setValue(CWallet::GetRequiredFee(1000)); } void SendCoinsDialog::updateFeeSectionControls() @@ -584,10 +591,11 @@ void SendCoinsDialog::updateFeeSectionControls() ui->labelFeeEstimation ->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFeeNormal ->setEnabled(ui->radioSmartFee->isChecked()); ui->labelSmartFeeFast ->setEnabled(ui->radioSmartFee->isChecked()); + ui->confirmationTargetLabel ->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->radioCustomAtLeast ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() && CoinControlDialog::coinControl->HasSelected()); ui->customFee ->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked()); } @@ -595,18 +603,24 @@ void SendCoinsDialog::updateGlobalFeeVariables() { if (ui->radioSmartFee->isChecked()) { - nTxConfirmTarget = defaultConfirmTarget - ui->sliderSmartFee->value(); + int nConfirmTarget = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2; payTxFee = CFeeRate(0); + + // set nMinimumTotalFee to 0 to not accidentally pay a custom fee + CoinControlDialog::coinControl->nMinimumTotalFee = 0; + + // show the estimated required time for confirmation + // Dogecoin: We manually set height well past the last hard fork here + ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus(400000).nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget)); } else { - nTxConfirmTarget = defaultConfirmTarget; payTxFee = CFeeRate(ui->customFee->value()); - fPayAtLeastCustomFee = ui->radioCustomAtLeast->isChecked(); - } - // Dogecoin: Disable free transactions - // fSendFreeTransactions = ui->checkBoxFreeTx->isChecked(); + // if user has selected to set a minimum absolute fee, pass the value to coincontrol + // set nMinimumTotalFee to 0 in case of user has selected that the fee is per KB + CoinControlDialog::coinControl->nMinimumTotalFee = ui->radioCustomAtLeast->isChecked() ? ui->customFee->value() : 0; + } } void SendCoinsDialog::updateFeeMinimizedLabel() @@ -625,8 +639,8 @@ void SendCoinsDialog::updateFeeMinimizedLabel() 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") + ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg( + BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB") ); } @@ -635,19 +649,28 @@ void SendCoinsDialog::updateSmartFeeLabel() if(!model || !model->getOptionsModel()) return; - int nBlocksToConfirm = defaultConfirmTarget - ui->sliderSmartFee->value(); - CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm); + int nBlocksToConfirm = ui->sliderSmartFee->maximum() - ui->sliderSmartFee->value() + 2; + int estimateFoundAtBlocks = nBlocksToConfirm; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocksToConfirm, &estimateFoundAtBlocks); if (feeRate <= CFeeRate(0)) // not enough data => minfee { - ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB"); + ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), + std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelFeeEstimation->setText(""); + ui->fallbackFeeWarningLabel->setVisible(true); + int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness(); + QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14)); + ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }"); + ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x")); } else { - ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); + ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), + std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->hide(); - ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", nBlocksToConfirm)); + ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); + ui->fallbackFeeWarningLabel->setVisible(false); } updateFeeMinimizedLabel(); @@ -683,12 +706,6 @@ void SendCoinsDialog::coinControlClipboardBytes() GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } -// Coin Control: copy label "Priority" to clipboard -void SendCoinsDialog::coinControlClipboardPriority() -{ - GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); -} - // Coin Control: copy label "Dust" to clipboard void SendCoinsDialog::coinControlClipboardLowOutput() { @@ -709,8 +726,9 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked) if (!checked && model) // coin control features disabled CoinControlDialog::coinControl->SetNull(); - if (checked) - coinControlUpdateLabels(); + // make sure we set back the confirmation target + updateGlobalFeeVariables(); + coinControlUpdateLabels(); } // Coin Control: button inputs -> show actual coin control dialog @@ -754,16 +772,28 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) } else if (!addr.IsValid()) // Invalid address { - ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address")); + ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Dogecoin address")); } else // Valid address { - CPubKey pubkey; CKeyID keyid; addr.GetKeyID(keyid); - if (!model->getPubKey(keyid, pubkey)) // Unknown change address + if (!model->havePrivKey(keyid)) // Unknown change address { ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); + + // confirmation dialog + QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm custom change address"), tr("The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + + if(btnRetVal == QMessageBox::Yes) + CoinControlDialog::coinControl->destChange = addr.Get(); + else + { + ui->lineEditCoinControlChange->setText(""); + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}"); + ui->labelCoinControlChangeLabel->setText(""); + } } else // Known change address { @@ -785,16 +815,31 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) // Coin Control: update labels void SendCoinsDialog::coinControlUpdateLabels() { - if (!model || !model->getOptionsModel() || !model->getOptionsModel()->getCoinControlFeatures()) + if (!model || !model->getOptionsModel()) return; + if (model->getOptionsModel()->getCoinControlFeatures()) + { + // enable minimum absolute fee UI controls + ui->radioCustomAtLeast->setVisible(true); + + // only enable the feature if inputs are selected + ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() &&CoinControlDialog::coinControl->HasSelected()); + } + else + { + // in case coin control is disabled (=default), hide minimum absolute fee UI controls + ui->radioCustomAtLeast->setVisible(false); + return; + } + // set pay amounts CoinControlDialog::payAmounts.clear(); CoinControlDialog::fSubtractFeeFromAmount = false; for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); - if(entry) + if(entry && !entry->isHidden()) { SendCoinsRecipient rcp = entry->getValue(); CoinControlDialog::payAmounts.append(rcp.amount); @@ -820,3 +865,45 @@ void SendCoinsDialog::coinControlUpdateLabels() ui->labelCoinControlInsuffFunds->hide(); } } + +SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay, + QWidget *parent) : + QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay) +{ + setDefaultButton(QMessageBox::Cancel); + yesButton = button(QMessageBox::Yes); + updateYesButton(); + connect(&countDownTimer, SIGNAL(timeout()), this, SLOT(countDown())); +} + +int SendConfirmationDialog::exec() +{ + updateYesButton(); + countDownTimer.start(1000); + return QMessageBox::exec(); +} + +void SendConfirmationDialog::countDown() +{ + secDelay--; + updateYesButton(); + + if(secDelay <= 0) + { + countDownTimer.stop(); + } +} + +void SendConfirmationDialog::updateYesButton() +{ + if(secDelay > 0) + { + yesButton->setEnabled(false); + yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")"); + } + else + { + yesButton->setEnabled(true); + yesButton->setText(tr("Yes")); + } +} |