6 #include "ui_sendcoinsdialog.h"
21 #include "validation.h"
26 #include <QFontMetrics>
27 #include <QMessageBox>
30 #include <QTextDocument>
33 #define SEND_CONFIRM_DELAY 3
40 fNewRecipientAllowed(true),
42 platformStyle(_platformStyle)
47 ui->addButton->setIcon(QIcon());
48 ui->clearButton->setIcon(QIcon());
49 ui->sendButton->setIcon(QIcon());
60 connect(
ui->addButton, SIGNAL(clicked()),
this, SLOT(
addEntry()));
61 connect(
ui->clearButton, SIGNAL(clicked()),
this, SLOT(
clear()));
66 connect(
ui->lineEditCoinControlChange, SIGNAL(textEdited(
const QString &)),
this, SLOT(
coinControlChangeEdited(
const QString &)));
69 QAction *clipboardQuantityAction =
new QAction(tr(
"Copy quantity"),
this);
70 QAction *clipboardAmountAction =
new QAction(tr(
"Copy amount"),
this);
71 QAction *clipboardFeeAction =
new QAction(tr(
"Copy fee"),
this);
72 QAction *clipboardAfterFeeAction =
new QAction(tr(
"Copy after fee"),
this);
73 QAction *clipboardBytesAction =
new QAction(tr(
"Copy bytes"),
this);
74 QAction *clipboardLowOutputAction =
new QAction(tr(
"Copy dust"),
this);
75 QAction *clipboardChangeAction =
new QAction(tr(
"Copy change"),
this);
83 ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
84 ui->labelCoinControlAmount->addAction(clipboardAmountAction);
85 ui->labelCoinControlFee->addAction(clipboardFeeAction);
86 ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
87 ui->labelCoinControlBytes->addAction(clipboardBytesAction);
88 ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
89 ui->labelCoinControlChange->addAction(clipboardChangeAction);
93 if (!settings.contains(
"fFeeSectionMinimized"))
94 settings.setValue(
"fFeeSectionMinimized",
true);
95 if (!settings.contains(
"nFeeRadio") && settings.contains(
"nTransactionFee") && settings.value(
"nTransactionFee").toLongLong() > 0)
96 settings.setValue(
"nFeeRadio", 1);
97 if (!settings.contains(
"nFeeRadio"))
98 settings.setValue(
"nFeeRadio", 0);
99 if (!settings.contains(
"nCustomFeeRadio") && settings.contains(
"nTransactionFee") && settings.value(
"nTransactionFee").toLongLong() > 0)
100 settings.setValue(
"nCustomFeeRadio", 1);
101 if (!settings.contains(
"nCustomFeeRadio"))
102 settings.setValue(
"nCustomFeeRadio", 0);
103 if (!settings.contains(
"nSmartFeeSliderPosition"))
104 settings.setValue(
"nSmartFeeSliderPosition", 0);
105 if (!settings.contains(
"nTransactionFee"))
106 settings.setValue(
"nTransactionFee", (qint64)DEFAULT_TRANSACTION_FEE);
107 if (!settings.contains(
"fPayOnlyMinFee"))
108 settings.setValue(
"fPayOnlyMinFee",
false);
109 ui->groupFee->setId(
ui->radioSmartFee, 0);
110 ui->groupFee->setId(
ui->radioCustomFee, 1);
111 ui->groupFee->button((
int)std::max(0, std::min(1, settings.value(
"nFeeRadio").toInt())))->setChecked(
true);
112 ui->groupCustomFee->setId(
ui->radioCustomPerKilobyte, 0);
113 ui->groupCustomFee->setId(
ui->radioCustomAtLeast, 1);
114 ui->groupCustomFee->button((
int)std::max(0, std::min(1, settings.value(
"nCustomFeeRadio").toInt())))->setChecked(
true);
115 ui->customFee->setValue(settings.value(
"nTransactionFee").toLongLong());
116 ui->checkBoxMinimumFee->setChecked(settings.value(
"fPayOnlyMinFee").toBool());
125 connect(_clientModel, SIGNAL(numBlocksChanged(
int,QDateTime,
double,
bool)),
this, SLOT(
updateSmartFeeLabel()));
131 this->
model = _model;
135 for(
int i = 0; i <
ui->entries->count(); ++i)
137 SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(i)->widget());
146 connect(_model, SIGNAL(balanceChanged(
CAmount,
CAmount,
CAmount,
CAmount,
CAmount,
CAmount)),
this, SLOT(
setBalance(
CAmount,
CAmount,
CAmount,
CAmount,
CAmount,
CAmount)));
167 connect(
ui->checkBoxMinimumFee, SIGNAL(stateChanged(
int)),
this, SLOT(
setMinimumFee()));
179 if (settings.value(
"nSmartFeeSliderPosition").toInt() == 0)
182 ui->sliderSmartFee->setValue(settings.value(
"nSmartFeeSliderPosition").toInt());
190 settings.setValue(
"nFeeRadio",
ui->groupFee->checkedId());
191 settings.setValue(
"nCustomFeeRadio",
ui->groupCustomFee->checkedId());
192 settings.setValue(
"nSmartFeeSliderPosition",
ui->sliderSmartFee->value());
193 settings.setValue(
"nTransactionFee", (qint64)
ui->customFee->value());
194 settings.setValue(
"fPayOnlyMinFee",
ui->checkBoxMinimumFee->isChecked());
204 QList<SendCoinsRecipient> recipients;
207 for(
int i = 0; i <
ui->entries->count(); ++i)
209 SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(i)->widget());
214 recipients.append(entry->
getValue());
223 if(!valid || recipients.isEmpty())
245 if (
ui->radioSmartFee->isChecked())
246 ctrl.
nConfirmTarget =
ui->sliderSmartFee->maximum() -
ui->sliderSmartFee->value() + 2;
264 QStringList formatted;
269 amount.append(
"</b>");
271 QString address =
"<span style='font-family: monospace;'>" + rcp.
address;
272 address.append(
"</span>");
274 QString recipientElement;
278 if(rcp.
label.length() > 0)
281 recipientElement.append(QString(
" (%1)").arg(address));
285 recipientElement = tr(
"%1 to %2").arg(amount, address);
294 recipientElement = tr(
"%1 to %2").arg(amount, address);
297 formatted.append(recipientElement);
300 QString questionString = tr(
"Are you sure you want to send?");
301 questionString.append(
"<br /><br />%1");
306 questionString.append(
"<hr /><span style='color:#aa0000;'>");
308 questionString.append(
"</span> ");
309 questionString.append(tr(
"added as transaction fee"));
312 questionString.append(
" (" + QString::number((
double)currentTransaction.
getTransactionSize() / 1000) +
" kB)");
316 questionString.append(
"<hr />");
318 QStringList alternativeUnits;
324 questionString.append(tr(
"Total Amount %1")
326 questionString.append(QString(
"<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
327 .arg(alternativeUnits.join(
" " + tr(
"or") +
"<br />")));
331 confirmationDialog.
exec();
332 QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
334 if(retval != QMessageBox::Yes)
357 while(
ui->entries->count())
359 ui->entries->takeAt(0)->widget()->deleteLater();
380 ui->entries->addWidget(entry);
388 ui->scrollAreaWidgetContents->resize(
ui->scrollAreaWidgetContents->sizeHint());
389 qApp->processEvents();
390 QScrollBar* bar =
ui->scrollArea->verticalScrollBar();
392 bar->setSliderPosition(bar->maximum());
409 if (
ui->entries->count() == 1)
412 entry->deleteLater();
419 for(
int i = 0; i <
ui->entries->count(); ++i)
421 SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(i)->widget());
427 QWidget::setTabOrder(prev,
ui->sendButton);
428 QWidget::setTabOrder(
ui->sendButton,
ui->clearButton);
429 QWidget::setTabOrder(
ui->clearButton,
ui->addButton);
430 return ui->addButton;
437 if(
ui->entries->count() == 1)
439 SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(0)->widget());
460 if(
ui->entries->count() == 1)
462 SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(0)->widget());
486 const CAmount& watchBalance,
const CAmount& watchUnconfirmedBalance,
const CAmount& watchImmatureBalance)
488 Q_UNUSED(unconfirmedBalance);
489 Q_UNUSED(immatureBalance);
490 Q_UNUSED(watchBalance);
491 Q_UNUSED(watchUnconfirmedBalance);
492 Q_UNUSED(watchImmatureBalance);
510 QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
517 switch(sendCoinsReturn.
status)
520 msgParams.first = tr(
"The recipient address is not valid. Please recheck.");
523 msgParams.first = tr(
"The amount to pay must be larger than 0.");
526 msgParams.first = tr(
"The amount exceeds your balance.");
529 msgParams.first = tr(
"The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
532 msgParams.first = tr(
"Duplicate address found: addresses should only be used once each.");
535 msgParams.first = tr(
"Transaction creation failed!");
539 msgParams.first = tr(
"The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.
reasonCommitFailed);
546 msgParams.first = tr(
"Payment request expired.");
555 Q_EMIT
message(tr(
"Send Coins"), msgParams.first, msgParams.second);
560 ui->labelFeeMinimized->setVisible(fMinimize);
561 ui->buttonChooseFee ->setVisible(fMinimize);
562 ui->buttonMinimizeFee->setVisible(!fMinimize);
563 ui->frameFeeSelection->setVisible(!fMinimize);
564 ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);
581 ui->radioCustomPerKilobyte->setChecked(
true);
587 ui->sliderSmartFee ->setEnabled(
ui->radioSmartFee->isChecked());
588 ui->labelSmartFee ->setEnabled(
ui->radioSmartFee->isChecked());
589 ui->labelSmartFee2 ->setEnabled(
ui->radioSmartFee->isChecked());
590 ui->labelSmartFee3 ->setEnabled(
ui->radioSmartFee->isChecked());
591 ui->labelFeeEstimation ->setEnabled(
ui->radioSmartFee->isChecked());
592 ui->labelSmartFeeNormal ->setEnabled(
ui->radioSmartFee->isChecked());
593 ui->labelSmartFeeFast ->setEnabled(
ui->radioSmartFee->isChecked());
594 ui->confirmationTargetLabel ->setEnabled(
ui->radioSmartFee->isChecked());
595 ui->checkBoxMinimumFee ->setEnabled(
ui->radioCustomFee->isChecked());
596 ui->labelMinFeeWarning ->setEnabled(
ui->radioCustomFee->isChecked());
597 ui->radioCustomPerKilobyte ->setEnabled(
ui->radioCustomFee->isChecked() && !
ui->checkBoxMinimumFee->isChecked());
599 ui->customFee ->setEnabled(
ui->radioCustomFee->isChecked() && !
ui->checkBoxMinimumFee->isChecked());
604 if (
ui->radioSmartFee->isChecked())
606 int nConfirmTarget =
ui->sliderSmartFee->maximum() -
ui->sliderSmartFee->value() + 2;
614 ui->confirmationTargetLabel->setText(
GUIUtil::formatDurationStr(nConfirmTarget *
Params().GetConsensus(400000).nPowTargetSpacing) +
" / " + tr(
"%n block(s)",
"", nConfirmTarget));
631 if (
ui->radioSmartFee->isChecked())
632 ui->labelFeeMinimized->setText(
ui->labelSmartFee->text());
635 ((
ui->radioCustomPerKilobyte->isChecked()) ?
"/kB" :
""));
642 ui->checkBoxMinimumFee->setText(tr(
"Pay only the required fee of %1").arg(
652 int nBlocksToConfirm =
ui->sliderSmartFee->maximum() -
ui->sliderSmartFee->value() + 2;
653 int estimateFoundAtBlocks = nBlocksToConfirm;
659 ui->labelSmartFee2->show();
660 ui->labelFeeEstimation->setText(
"");
661 ui->fallbackFeeWarningLabel->setVisible(
true);
662 int lightness =
ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
663 QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
664 ui->fallbackFeeWarningLabel->setStyleSheet(
"QLabel { color: " + warning_colour.name() +
"; }");
665 ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(
ui->fallbackFeeWarningLabel->font()).width(
"x"));
671 ui->labelSmartFee2->hide();
672 ui->labelFeeEstimation->setText(tr(
"Estimated to begin confirmation within %n block(s).",
"", estimateFoundAtBlocks));
673 ui->fallbackFeeWarningLabel->setVisible(
false);
724 ui->frameCoinControl->setVisible(checked);
726 if (!checked &&
model)
746 if (state == Qt::Unchecked)
749 ui->labelCoinControlChangeLabel->clear();
755 ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
765 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:red;}");
771 ui->labelCoinControlChangeLabel->setText(
"");
775 ui->labelCoinControlChangeLabel->setText(tr(
"Warning: Invalid Dogecoin address"));
783 ui->labelCoinControlChangeLabel->setText(tr(
"Warning: Unknown change address"));
786 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?"),
787 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
789 if(btnRetVal == QMessageBox::Yes)
793 ui->lineEditCoinControlChange->setText(
"");
794 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:black;}");
795 ui->labelCoinControlChangeLabel->setText(
"");
800 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:black;}");
804 if (!associatedLabel.isEmpty())
805 ui->labelCoinControlChangeLabel->setText(associatedLabel);
807 ui->labelCoinControlChangeLabel->setText(tr(
"(no label)"));
824 ui->radioCustomAtLeast->setVisible(
true);
832 ui->radioCustomAtLeast->setVisible(
false);
839 for(
int i = 0; i <
ui->entries->count(); ++i)
841 SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(
ui->entries->itemAt(i)->widget());
842 if(entry && !entry->isHidden())
857 ui->labelCoinControlAutomaticallySelected->hide();
858 ui->widgetCoinControl->show();
863 ui->labelCoinControlAutomaticallySelected->show();
864 ui->widgetCoinControl->hide();
865 ui->labelCoinControlInsuffFunds->hide();
871 QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
873 setDefaultButton(QMessageBox::Cancel);
883 return QMessageBox::exec();
int64_t CAmount
Amount in satoshis (Can be negative)
const CChainParams & Params()
Return the currently selected parameters.
QString labelForAddress(const QString &address) const
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as HTML string (with unit)
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
base58-encoded Bitcoin addresses.
CTxDestination Get() const
bool GetKeyID(CKeyID &keyID) const
int nConfirmTarget
Override the default confirmation target, 0 = use default.
CTxDestination destChange
CAmount nMinimumTotalFee
Minimum absolute fee (not per kilobyte)
Fee rate in satoshis per kilobyte: CAmount / kB.
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
A reference to a CKey: the Hash160 of its serialized public key.
CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks=NULL) const
Estimate fee rate needed to get into the next nBlocks If no answer can be given at nBlocks,...
static CFeeRate fallbackFee
If fee estimation does not have enough data to provide estimates, use this fee instead.
Model for Bitcoin network client.
void setModel(WalletModel *model)
static void updateLabels(WalletModel *, QDialog *)
static CCoinControl * coinControl
static QList< CAmount > payAmounts
static bool fSubtractFeeFromAmount
bool getCoinControlFeatures()
bool IsInitialized() const
Dialog for sending bitcoins.
void updateGlobalFeeVariables()
void setBalance(const CAmount &balance, const CAmount &unconfirmedBalance, const CAmount &immatureBalance, const CAmount &watchOnlyBalance, const CAmount &watchUnconfBalance, const CAmount &watchImmatureBalance)
ClientModel * clientModel
void coinControlChangeEdited(const QString &)
void coinControlChangeChecked(int)
void coinControlClipboardFee()
void on_sendButton_clicked()
void on_buttonChooseFee_clicked()
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg=QString())
void setClientModel(ClientModel *clientModel)
void updateTabsAndLabels()
void updateFeeSectionControls()
SendCoinsEntry * addEntry()
void pasteEntry(const SendCoinsRecipient &rv)
void updateFeeMinimizedLabel()
const PlatformStyle * platformStyle
void coinControlClipboardQuantity()
void coinControlButtonClicked()
void coinControlClipboardAfterFee()
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
void setModel(WalletModel *model)
void coinControlClipboardLowOutput()
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
void coinControlClipboardAmount()
void setAddress(const QString &address)
void coinControlClipboardChange()
bool fNewRecipientAllowed
void removeEntry(SendCoinsEntry *entry)
void updateSmartFeeLabel()
void coinControlClipboardBytes()
void message(const QString &title, const QString &message, unsigned int style)
void on_buttonMinimizeFee_clicked()
void coinControlUpdateLabels()
void coinControlFeatureChanged(bool)
void minimizeFeeSection(bool fMinimize)
SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=0)
A single entry in the dialog for sending bitcoins.
void setAddress(const QString &address)
bool isClear()
Return whether the entry is still empty and unedited.
void setValue(const SendCoinsRecipient &value)
void setModel(WalletModel *model)
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
SendCoinsRecipient getValue()
PaymentRequestPlus paymentRequest
bool fSubtractFeeFromAmount
QString authenticatedMerchant
QAbstractButton * yesButton
SendConfirmationDialog(const QString &title, const QString &text, int secDelay=0, QWidget *parent=0)
Interface to Bitcoin wallet from Qt view code.
CAmount getBalance(const CCoinControl *coinControl=NULL) const
CAmount getUnconfirmedBalance() const
SendCoinsReturn sendCoins(WalletModelTransaction &transaction)
CAmount getWatchUnconfirmedBalance() const
bool havePrivKey(const CKeyID &address) const
CAmount getWatchBalance() const
AddressTableModel * getAddressTableModel()
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl=NULL)
OptionsModel * getOptionsModel()
CAmount getWatchImmatureBalance() const
CAmount getImmatureBalance() const
UnlockContext requestUnlock()
@ AmountWithFeeExceedsBalance
@ TransactionCreationFailed
@ TransactionCommitFailed
int getDefaultConfirmTarget() const
Data model for a walletmodel transaction.
CAmount getTotalTransactionAmount()
QList< SendCoinsRecipient > getRecipients()
unsigned int getTransactionSize()
CAmount getTransactionFee()
static CAmount GetRequiredFee(const CMutableTransaction &tx, unsigned int nTxBytes)
Return the minimum required fee taking into account the floating relay fee and user set minimum trans...
QString HtmlEscape(const QString &str, bool fMultiLine)
QString formatDurationStr(int secs)
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
void setClipboard(const QString &str)
#define SEND_CONFIRM_DELAY
QString reasonCommitFailed
CTxMemPool mempool(::minRelayTxFee)
CAmount maxTxFee
Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendra...
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE)
Transaction fee set by the user.