5 #if defined(HAVE_CONFIG_H) 10 #include <qt/forms/ui_sendcoinsdialog.h> 30 #include <QFontMetrics> 33 #include <QTextDocument> 35 static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} };
37 if (index+1 > static_cast<int>(confTargets.size())) {
38 return confTargets.back();
41 return confTargets[0];
43 return confTargets[index];
46 for (
unsigned int i = 0; i < confTargets.size(); i++) {
47 if (confTargets[i] >= target) {
51 return confTargets.size() - 1;
59 fNewRecipientAllowed(true),
61 platformStyle(_platformStyle)
66 ui->addButton->setIcon(QIcon());
67 ui->clearButton->setIcon(QIcon());
68 ui->sendButton->setIcon(QIcon());
88 QAction *clipboardQuantityAction =
new QAction(tr(
"Copy quantity"),
this);
89 QAction *clipboardAmountAction =
new QAction(tr(
"Copy amount"),
this);
90 QAction *clipboardFeeAction =
new QAction(tr(
"Copy fee"),
this);
91 QAction *clipboardAfterFeeAction =
new QAction(tr(
"Copy after fee"),
this);
92 QAction *clipboardBytesAction =
new QAction(tr(
"Copy bytes"),
this);
93 QAction *clipboardLowOutputAction =
new QAction(tr(
"Copy dust"),
this);
94 QAction *clipboardChangeAction =
new QAction(tr(
"Copy change"),
this);
102 ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
103 ui->labelCoinControlAmount->addAction(clipboardAmountAction);
104 ui->labelCoinControlFee->addAction(clipboardFeeAction);
105 ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
106 ui->labelCoinControlBytes->addAction(clipboardBytesAction);
107 ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
108 ui->labelCoinControlChange->addAction(clipboardChangeAction);
112 if (!settings.contains(
"fFeeSectionMinimized"))
113 settings.setValue(
"fFeeSectionMinimized",
true);
114 if (!settings.contains(
"nFeeRadio") && settings.contains(
"nTransactionFee") && settings.value(
"nTransactionFee").toLongLong() > 0)
115 settings.setValue(
"nFeeRadio", 1);
116 if (!settings.contains(
"nFeeRadio"))
117 settings.setValue(
"nFeeRadio", 0);
118 if (!settings.contains(
"nSmartFeeSliderPosition"))
119 settings.setValue(
"nSmartFeeSliderPosition", 0);
120 if (!settings.contains(
"nTransactionFee"))
122 if (!settings.contains(
"fPayOnlyMinFee"))
123 settings.setValue(
"fPayOnlyMinFee",
false);
124 ui->groupFee->setId(
ui->radioSmartFee, 0);
125 ui->groupFee->setId(
ui->radioCustomFee, 1);
126 ui->groupFee->button((
int)std::max(0, std::min(1, settings.value(
"nFeeRadio").toInt())))->setChecked(
true);
127 ui->customFee->setValue(settings.value(
"nTransactionFee").toLongLong());
128 ui->checkBoxMinimumFee->setChecked(settings.value(
"fPayOnlyMinFee").toBool());
143 this->
model = _model;
147 for(
int i = 0; i <
ui->entries->count(); ++i)
169 for (
const int n : confTargets) {
188 ui->optInRBF->setCheckState(Qt::Checked);
192 if (settings.value(
"nSmartFeeSliderPosition").toInt() != 0) {
195 int nConfirmTarget = 25 - settings.value(
"nSmartFeeSliderPosition").toInt();
196 settings.setValue(
"nConfTarget", nConfirmTarget);
197 settings.remove(
"nSmartFeeSliderPosition");
199 if (settings.value(
"nConfTarget").toInt() == 0)
210 settings.setValue(
"nFeeRadio",
ui->groupFee->checkedId());
212 settings.setValue(
"nTransactionFee", (qint64)
ui->customFee->value());
213 settings.setValue(
"fPayOnlyMinFee",
ui->checkBoxMinimumFee->isChecked());
223 QList<SendCoinsRecipient> recipients;
226 for(
int i = 0; i <
ui->entries->count(); ++i)
233 recipients.append(entry->
getValue());
242 if(!valid || recipients.isEmpty())
281 QStringList formatted;
289 amount.append(
"</b>");
291 QString address =
"<span style='font-family: monospace;'>" + rcp.address;
292 address.append(
"</span>");
294 QString recipientElement;
295 recipientElement =
"<br />";
298 if (!rcp.paymentRequest.IsInitialized())
301 if(rcp.label.length() > 0)
304 recipientElement.append(QString(
" (%1)").arg(address));
308 recipientElement.append(tr(
"%1 to %2").arg(amount, address));
312 else if(!rcp.authenticatedMerchant.isEmpty())
314 recipientElement.append(tr(
"%1 to %2").arg(amount,
GUIUtil::HtmlEscape(rcp.authenticatedMerchant)));
318 recipientElement.append(tr(
"%1 to %2").arg(amount, address));
322 formatted.append(recipientElement);
325 QString questionString = tr(
"Are you sure you want to send?");
326 questionString.append(
"<br /><span style='font-size:10pt;'>");
327 questionString.append(tr(
"Please, review your transaction."));
328 questionString.append(
"</span><br />%1");
333 questionString.append(
"<hr /><b>");
334 questionString.append(tr(
"Transaction fee"));
335 questionString.append(
"</b>");
338 questionString.append(
" (" + QString::number((
double)currentTransaction.
getTransactionSize() / 1000) +
" kB): ");
341 questionString.append(
"<span style='color:#aa0000; font-weight:bold;'>");
343 questionString.append(
"</span><br />");
346 questionString.append(
"<span style='font-size:10pt; font-weight:normal;'>");
347 if (
ui->optInRBF->isChecked()) {
348 questionString.append(tr(
"You can increase the fee later (signals Replace-By-Fee, BIP-125)."));
350 questionString.append(tr(
"Not signalling Replace-By-Fee, BIP-125."));
352 questionString.append(
"</span>");
356 questionString.append(
"<hr />");
358 QStringList alternativeUnits;
364 questionString.append(QString(
"<b>%1</b>: <b>%2</b>").arg(tr(
"Total Amount"))
366 questionString.append(QString(
"<br /><span style='font-size:10pt; font-weight:normal;'>(=%1)</span>")
367 .arg(alternativeUnits.join(
" " + tr(
"or") +
" ")));
371 confirmationDialog.
exec();
372 QMessageBox::StandardButton retval =
static_cast<QMessageBox::StandardButton
>(confirmationDialog.result());
374 if(retval != QMessageBox::Yes)
399 ui->checkBoxCoinControlChange->setChecked(
false);
400 ui->lineEditCoinControlChange->clear();
404 while(
ui->entries->count())
406 ui->entries->takeAt(0)->widget()->deleteLater();
427 ui->entries->addWidget(entry);
436 ui->scrollAreaWidgetContents->resize(
ui->scrollAreaWidgetContents->sizeHint());
437 qApp->processEvents();
438 QScrollBar* bar =
ui->scrollArea->verticalScrollBar();
440 bar->setSliderPosition(bar->maximum());
457 if (
ui->entries->count() == 1)
460 entry->deleteLater();
467 for(
int i = 0; i <
ui->entries->count(); ++i)
475 QWidget::setTabOrder(prev,
ui->sendButton);
476 QWidget::setTabOrder(
ui->sendButton,
ui->clearButton);
477 QWidget::setTabOrder(
ui->clearButton,
ui->addButton);
478 return ui->addButton;
485 if(
ui->entries->count() == 1)
508 if(
ui->entries->count() == 1)
551 QPair<QString, CClientUIInterface::MessageBoxFlags> msgParams;
558 switch(sendCoinsReturn.
status)
561 msgParams.first = tr(
"The recipient address is not valid. Please recheck.");
564 msgParams.first = tr(
"The amount to pay must be larger than 0.");
567 msgParams.first = tr(
"The amount exceeds your balance.");
570 msgParams.first = tr(
"The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg);
573 msgParams.first = tr(
"Duplicate address found: addresses should only be used once each.");
576 msgParams.first = tr(
"Transaction creation failed!");
580 msgParams.first = tr(
"The transaction was rejected with the following reason: %1").arg(sendCoinsReturn.
reasonCommitFailed);
587 msgParams.first = tr(
"Payment request expired.");
596 Q_EMIT
message(tr(
"Send Coins"), msgParams.first, msgParams.second);
601 ui->labelFeeMinimized->setVisible(fMinimize);
602 ui->buttonChooseFee ->setVisible(fMinimize);
603 ui->buttonMinimizeFee->setVisible(!fMinimize);
604 ui->frameFeeSelection->setVisible(!fMinimize);
605 ui->horizontalLayoutSmartFee->setContentsMargins(0, (fMinimize ? 0 : 6), 0, 0);
630 for (
int i = 0; i <
ui->entries->count(); ++i) {
632 if (e && !e->isHidden() && e != entry) {
652 ui->confTargetSelector ->setEnabled(
ui->radioSmartFee->isChecked());
653 ui->labelSmartFee ->setEnabled(
ui->radioSmartFee->isChecked());
654 ui->labelSmartFee2 ->setEnabled(
ui->radioSmartFee->isChecked());
655 ui->labelSmartFee3 ->setEnabled(
ui->radioSmartFee->isChecked());
656 ui->labelFeeEstimation ->setEnabled(
ui->radioSmartFee->isChecked());
657 ui->checkBoxMinimumFee ->setEnabled(
ui->radioCustomFee->isChecked());
658 ui->labelMinFeeWarning ->setEnabled(
ui->radioCustomFee->isChecked());
659 ui->labelCustomPerKilobyte ->setEnabled(
ui->radioCustomFee->isChecked() && !
ui->checkBoxMinimumFee->isChecked());
660 ui->customFee ->setEnabled(
ui->radioCustomFee->isChecked() && !
ui->checkBoxMinimumFee->isChecked());
668 if (
ui->radioSmartFee->isChecked())
669 ui->labelFeeMinimized->setText(
ui->labelSmartFee->text());
678 ui->checkBoxMinimumFee->setText(tr(
"Pay only the required fee of %1").arg(
685 if (
ui->radioCustomFee->isChecked()) {
710 ui->labelSmartFee2->show();
711 ui->labelFeeEstimation->setText(
"");
712 ui->fallbackFeeWarningLabel->setVisible(
true);
713 int lightness =
ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
714 QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
715 ui->fallbackFeeWarningLabel->setStyleSheet(
"QLabel { color: " + warning_colour.name() +
"; }");
716 ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(
ui->fallbackFeeWarningLabel->font()).width(
"x"));
720 ui->labelSmartFee2->hide();
721 ui->labelFeeEstimation->setText(tr(
"Estimated to begin confirmation within %n block(s).",
"", returned_target));
722 ui->fallbackFeeWarningLabel->setVisible(
false);
773 ui->frameCoinControl->setVisible(checked);
775 if (!checked &&
model)
793 if (state == Qt::Unchecked)
796 ui->labelCoinControlChangeLabel->clear();
802 ui->lineEditCoinControlChange->setEnabled((state == Qt::Checked));
812 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:red;}");
818 ui->labelCoinControlChangeLabel->setText(
"");
822 ui->labelCoinControlChangeLabel->setText(tr(
"Warning: Invalid BSHA3 address"));
827 ui->labelCoinControlChangeLabel->setText(tr(
"Warning: Unknown change address"));
830 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?"),
831 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
833 if(btnRetVal == QMessageBox::Yes)
837 ui->lineEditCoinControlChange->setText(
"");
838 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:black;}");
839 ui->labelCoinControlChangeLabel->setText(
"");
844 ui->labelCoinControlChangeLabel->setStyleSheet(
"QLabel{color:black;}");
848 if (!associatedLabel.isEmpty())
849 ui->labelCoinControlChangeLabel->setText(associatedLabel);
851 ui->labelCoinControlChangeLabel->setText(tr(
"(no label)"));
871 for(
int i = 0; i <
ui->entries->count(); ++i)
874 if(entry && !entry->isHidden())
889 ui->labelCoinControlAutomaticallySelected->hide();
890 ui->widgetCoinControl->show();
895 ui->labelCoinControlAutomaticallySelected->show();
896 ui->widgetCoinControl->hide();
897 ui->labelCoinControlInsuffFunds->hide();
903 QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
905 setDefaultButton(QMessageBox::Cancel);
915 return QMessageBox::exec();
void removeEntry(SendCoinsEntry *entry)
std::unique_ptr< interfaces::PendingWalletTx > & getWtx()
interfaces::Wallet & wallet() const
void setValue(const SendCoinsRecipient &value)
QString reasonCommitFailed
void updateFeeMinimizedLabel()
constexpr CAmount DEFAULT_PAY_TX_FEE
-paytxfee default
boost::optional< unsigned int > m_confirm_target
Override the default confirmation target if set.
void on_buttonChooseFee_clicked()
SendCoinsRecipient getValue()
UnlockContext requestUnlock()
void coinControlClipboardQuantity()
static QString formatHtmlWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as HTML string (with unit)
void coinControlClipboardAfterFee()
void setAddress(const QString &address)
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
#define SEND_CONFIRM_DELAY
CAmount getTransactionFee() const
SendCoinsReturn sendCoins(WalletModelTransaction &transaction)
QList< SendCoinsRecipient > getRecipients() const
void coinControlFeaturesChanged(bool)
void updateCoinControlState(CCoinControl &ctrl)
QString HtmlEscape(const QString &str, bool fMultiLine)
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
AddressTableModel * getAddressTableModel()
virtual bool isSpendable(const CTxDestination &dest)=0
Return whether wallet has private key.
A single entry in the dialog for sending bitcoins.
boost::optional< CFeeRate > m_feerate
Override the wallet's m_pay_tx_fee if set.
int getDisplayUnit() const
void coinControlFeatureChanged(bool)
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
int64_t CAmount
Amount in satoshis (Can be negative)
static QList< CAmount > payAmounts
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 on_sendButton_clicked()
SendCoinsEntry * addEntry()
bool validate(interfaces::Node &node)
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
void setBalance(const interfaces::WalletBalances &balances)
void setAddress(const QString &address)
void coinControlClipboardChange()
Collection of wallet balances.
void useAvailableBalance(SendCoinsEntry *entry)
void setClientModel(ClientModel *clientModel)
void setClipboard(const QString &str)
boost::variant< CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
ClientModel * clientModel
CTxDestination destChange
Custom change destination, if not set an address is generated.
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
virtual CAmount getMaxTxFee()=0
Get max tx fee.
SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl &coinControl)
virtual CAmount getMinimumFee(unsigned int tx_bytes, const CCoinControl &coin_control, int *returned_target, FeeReason *reason)=0
Get minimum fee.
Dialog for sending bitcoins.
void coinControlChangeEdited(const QString &)
static void updateLabels(WalletModel *, QDialog *)
void numBlocksChanged(int count, const QDateTime &blockDate, double nVerificationProgress, bool header)
QString getWalletName() const
interfaces::Node & node() const
void removeEntry(SendCoinsEntry *entry)
void displayUnitChanged(int unit)
Model for Bitcoin network client.
void coinControlUpdateLabels()
boost::optional< bool > m_signal_bip125_rbf
Override the wallet's m_signal_rbf if set.
void setModel(WalletModel *model)
int getConfTargetForIndex(int index)
bool getCoinControlFeatures() const
void checkSubtractFeeFromAmount()
bool isClear()
Return whether the entry is still empty and unedited.
void minimizeFeeSection(bool fMinimize)
void coinControlClipboardLowOutput()
void updateFeeSectionControls()
static QList< Unit > availableUnits()
Get list of units, for drop-down box.
CTxDestination DecodeDestination(const std::string &str)
void subtractFeeFromAmountChanged()
void setModel(WalletModel *model)
static bool fSubtractFeeFromAmount
void updateSmartFeeLabel()
int getIndexForConfTarget(int target)
void updateTabsAndLabels()
const CChainParams & Params()
Return the currently selected parameters.
Interface to Bitcoin wallet from Qt view code.
SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent=0)
SendConfirmationDialog(const QString &title, const QString &text, int secDelay=SEND_CONFIRM_DELAY, QWidget *parent=0)
void setAmount(const CAmount &amount)
void setModel(WalletModel *model)
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg=QString())
Fee rate in satoshis per kilobyte: CAmount / kB.
Data model for a walletmodel transaction.
void coinControlClipboardBytes()
void useAvailableBalance(SendCoinsEntry *entry)
virtual unsigned int getConfirmTarget()=0
Get tx confirm target.
bool fSubtractFeeFromAmount
const PlatformStyle * platformStyle
CAmount getTotalTransactionAmount() const
QString formatNiceTimeOffset(qint64 secs)
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
void coinControlClipboardAmount()
void on_buttonMinimizeFee_clicked()
virtual CAmount getAvailableBalance(const CCoinControl &coin_control)=0
Get available balance.
virtual WalletBalances getBalances()=0
Get balances.
void pasteEntry(const SendCoinsRecipient &rv)
QAbstractButton * yesButton
virtual CAmount getRequiredFee(unsigned int tx_bytes)=0
Get required fee.
void message(const QString &title, const QString &message, unsigned int style)
void coinsSent(const uint256 &txid)
bool fNewRecipientAllowed
CAmount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
void balanceChanged(const interfaces::WalletBalances &balances)
void coinControlButtonClicked()
unsigned int getTransactionSize()
void coinControlClipboardFee()
OptionsModel * getOptionsModel()
void coinControlChangeChecked(int)
static CCoinControl * coinControl()