5#if defined(HAVE_CONFIG_H)
6#include <config/bitcoin-config.h>
10#include <qt/forms/ui_coincontroldialog.h>
27#include <QApplication>
30#include <QDialogButtonBox>
40 int column = treeWidget()->sortColumn();
44 return data(column, Qt::UserRole).toLongLong() <
45 other.data(column, Qt::UserRole).toLongLong();
55 m_coin_control(coin_control), model(_model),
56 platformStyle(_platformStyle) {
60 QAction *copyAddressAction =
new QAction(tr(
"Copy address"),
this);
61 QAction *copyLabelAction =
new QAction(tr(
"Copy label"),
this);
62 QAction *copyAmountAction =
new QAction(tr(
"Copy amount"),
this);
66 lockAction =
new QAction(tr(
"Lock unspent"),
this);
81 connect(
ui->treeWidget, &QWidget::customContextMenuRequested,
this,
83 connect(copyAddressAction, &QAction::triggered,
this,
85 connect(copyLabelAction, &QAction::triggered,
this,
87 connect(copyAmountAction, &QAction::triggered,
this,
97 QAction *clipboardQuantityAction =
new QAction(tr(
"Copy quantity"),
this);
98 QAction *clipboardAmountAction =
new QAction(tr(
"Copy amount"),
this);
99 QAction *clipboardFeeAction =
new QAction(tr(
"Copy fee"),
this);
100 QAction *clipboardAfterFeeAction =
new QAction(tr(
"Copy after fee"),
this);
101 QAction *clipboardBytesAction =
new QAction(tr(
"Copy bytes"),
this);
102 QAction *clipboardLowOutputAction =
new QAction(tr(
"Copy dust"),
this);
103 QAction *clipboardChangeAction =
new QAction(tr(
"Copy change"),
this);
105 connect(clipboardQuantityAction, &QAction::triggered,
this,
107 connect(clipboardAmountAction, &QAction::triggered,
this,
109 connect(clipboardFeeAction, &QAction::triggered,
this,
111 connect(clipboardAfterFeeAction, &QAction::triggered,
this,
113 connect(clipboardBytesAction, &QAction::triggered,
this,
115 connect(clipboardLowOutputAction, &QAction::triggered,
this,
117 connect(clipboardChangeAction, &QAction::triggered,
this,
120 ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
121 ui->labelCoinControlAmount->addAction(clipboardAmountAction);
122 ui->labelCoinControlFee->addAction(clipboardFeeAction);
123 ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
124 ui->labelCoinControlBytes->addAction(clipboardBytesAction);
125 ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
126 ui->labelCoinControlChange->addAction(clipboardChangeAction);
129 connect(
ui->radioTreeMode, &QRadioButton::toggled,
this,
131 connect(
ui->radioListMode, &QRadioButton::toggled,
this,
135 connect(
ui->treeWidget, &QTreeWidget::itemChanged,
this,
139 ui->treeWidget->header()->setSectionsClickable(
true);
140 connect(
ui->treeWidget->header(), &QHeaderView::sectionClicked,
this,
144 connect(
ui->buttonBox, &QDialogButtonBox::clicked,
this,
148 connect(
ui->pushButtonSelectAll, &QPushButton::clicked,
this,
163 if (settings.contains(
"nCoinControlMode") &&
164 !settings.value(
"nCoinControlMode").toBool()) {
165 ui->radioTreeMode->click();
167 if (settings.contains(
"nCoinControlSortColumn") &&
168 settings.contains(
"nCoinControlSortOrder")) {
169 sortView(settings.value(
"nCoinControlSortColumn").toInt(),
170 (
static_cast<Qt::SortOrder
>(
171 settings.value(
"nCoinControlSortOrder").toInt())));
185 settings.setValue(
"nCoinControlMode",
ui->radioListMode->isChecked());
186 settings.setValue(
"nCoinControlSortColumn",
sortColumn);
187 settings.setValue(
"nCoinControlSortOrder", (
int)
sortOrder);
194 if (
ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
196 done(QDialog::Accepted);
202 Qt::CheckState state = Qt::Checked;
203 for (
int i = 0; i <
ui->treeWidget->topLevelItemCount(); i++) {
206 state = Qt::Unchecked;
210 ui->treeWidget->setEnabled(
false);
211 for (
int i = 0; i <
ui->treeWidget->topLevelItemCount(); i++) {
218 ui->treeWidget->setEnabled(
true);
219 if (state == Qt::Unchecked) {
228 QTreeWidgetItem *item =
ui->treeWidget->itemAt(point);
267 if (
ui->radioTreeMode->isChecked() &&
278 if (
ui->radioTreeMode->isChecked() &&
324 ui->labelCoinControlAmount->text().indexOf(
" ")));
330 ui->labelCoinControlFee->text()
331 .left(
ui->labelCoinControlFee->text().indexOf(
" "))
338 ui->labelCoinControlAfterFee->text()
339 .left(
ui->labelCoinControlAfterFee->text().indexOf(
" "))
346 ui->labelCoinControlBytes->text().replace(
ASYMP_UTF8,
""));
357 ui->labelCoinControlChange->text()
358 .left(
ui->labelCoinControlChange->text().indexOf(
" "))
366 ui->treeWidget->sortItems(column, order);
378 ((
sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder
379 : Qt::AscendingOrder);
386 : Qt::DescendingOrder);
395 if (checked &&
model) {
402 if (checked &&
model) {
417 }
else if (item->isDisabled()) {
425 if (
ui->treeWidget->isEnabled()) {
434 std::vector<COutPoint> vOutpts;
436 if (vOutpts.size() > 0) {
437 ui->labelLocked->setText(tr(
"(%1 locked)").arg(vOutpts.size()));
438 ui->labelLocked->setVisible(
true);
440 ui->labelLocked->setVisible(
false);
454 nPayAmount += amount;
458 CTxOut txout(amount, CScript() << std::vector<uint8_t>(24, 0));
467 unsigned int nBytes = 0;
468 unsigned int nBytesInputs = 0;
469 unsigned int nQuantity = 0;
471 std::vector<COutPoint> vCoinControl;
476 if (out.depth_in_main_chain < 0) {
482 const COutPoint &output = vCoinControl[i++];
492 nAmount += out.txout.nValue;
498 PKHash *pkhash = std::get_if<PKHash>(&address);
515 nBytes = nBytesInputs +
535 nChange = nAmount - nPayAmount;
544 CTxOut txout(nChange, CScript() << std::vector<uint8_t>(24, 0));
562 nAfterFee = std::max(nAmount - nPayFee,
Amount::zero());
571 QLabel *l1 = dialog->findChild<QLabel *>(
"labelCoinControlQuantity");
572 QLabel *l2 = dialog->findChild<QLabel *>(
"labelCoinControlAmount");
573 QLabel *l3 = dialog->findChild<QLabel *>(
"labelCoinControlFee");
574 QLabel *l4 = dialog->findChild<QLabel *>(
"labelCoinControlAfterFee");
575 QLabel *l5 = dialog->findChild<QLabel *>(
"labelCoinControlBytes");
576 QLabel *l7 = dialog->findChild<QLabel *>(
"labelCoinControlLowOutput");
577 QLabel *l8 = dialog->findChild<QLabel *>(
"labelCoinControlChange");
580 dialog->findChild<QLabel *>(
"labelCoinControlLowOutputText")
582 dialog->findChild<QLabel *>(
"labelCoinControlLowOutput")
584 dialog->findChild<QLabel *>(
"labelCoinControlChangeText")
586 dialog->findChild<QLabel *>(
"labelCoinControlChange")
591 l1->setText(QString::number(nQuantity));
599 l5->setText(((nBytes > 0) ?
ASYMP_UTF8 :
"") + QString::number(nBytes));
601 l7->setText(fDust ? tr(
"yes") : tr(
"no"));
614 l7->setStyleSheet((fDust) ?
"color:red;" :
"");
617 QString toolTipDust =
618 tr(
"This label turns red if any recipient receives an amount smaller "
619 "than the current dust threshold.");
622 double dFeeVary = (nBytes != 0) ?
double(nPayFee /
SATOSHI) / nBytes : 0;
625 tr(
"Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
627 l3->setToolTip(toolTip4);
628 l4->setToolTip(toolTip4);
629 l7->setToolTip(toolTipDust);
630 l8->setToolTip(toolTip4);
631 dialog->findChild<QLabel *>(
"labelCoinControlFeeText")
632 ->setToolTip(l3->toolTip());
633 dialog->findChild<QLabel *>(
"labelCoinControlAfterFeeText")
634 ->setToolTip(l4->toolTip());
635 dialog->findChild<QLabel *>(
"labelCoinControlBytesText")
636 ->setToolTip(l5->toolTip());
637 dialog->findChild<QLabel *>(
"labelCoinControlLowOutputText")
638 ->setToolTip(l7->toolTip());
639 dialog->findChild<QLabel *>(
"labelCoinControlChangeText")
640 ->setToolTip(l8->toolTip());
643 QLabel *label = dialog->findChild<QLabel *>(
"labelCoinControlInsuffFunds");
660 bool treeMode =
ui->radioTreeMode->isChecked();
662 ui->treeWidget->clear();
665 ui->treeWidget->setEnabled(
false);
666 ui->treeWidget->setAlternatingRowColors(!treeMode);
667 QFlags<Qt::ItemFlag> flgCheckbox =
668 Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
669 QFlags<Qt::ItemFlag> flgTristate =
670 Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable |
677 QString sWalletAddress = QString::fromStdString(
679 QString sWalletLabel =
681 if (sWalletLabel.isEmpty()) {
682 sWalletLabel = tr(
"(no label)");
689 itemWalletAddress->setFlags(flgTristate);
701 for (
const auto &outpair : coins.second) {
702 const COutPoint &output = std::get<0>(outpair);
713 itemOutput->setFlags(flgCheckbox);
718 QString sAddress =
"";
720 sAddress = QString::fromStdString(
725 if (!treeMode || (!(sAddress == sWalletAddress))) {
731 if (!(sAddress == sWalletAddress)) {
733 itemOutput->setToolTip(
COLUMN_LABEL, tr(
"change from %1 (%2)")
735 .arg(sWalletAddress));
737 }
else if (!treeMode) {
740 if (sLabel.isEmpty()) {
741 sLabel = tr(
"(no label)");
758 QVariant((qlonglong)out.
time));
769 QString::fromStdString(output.GetTxId().GetHex()));
778 itemOutput->setDisabled(
true);
793 "(" + QString::number(nChildren) +
")");
794 itemWalletAddress->setText(
797 QVariant(qlonglong(nSum /
SATOSHI)));
803 for (
int i = 0; i <
ui->treeWidget->topLevelItemCount(); i++) {
805 Qt::PartiallyChecked) {
806 ui->treeWidget->topLevelItem(i)->setExpanded(
true);
813 ui->treeWidget->setEnabled(
true);
static constexpr Amount SATOSHI
std::string EncodeCashAddr(const CTxDestination &dst, const CChainParams ¶ms)
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
static QString formatWithUnit(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
static QString removeSpaces(QString text)
static QString format(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
bool IsSelected(const COutPoint &output) const
void Select(const COutPoint &output)
void UnSelect(const COutPoint &output)
void ListSelected(std::vector< COutPoint > &vOutpoints) const
An encapsulated public key.
bool IsCompressed() const
Check whether this is a compressed public key.
An output of a transaction.
void headerSectionClicked(int)
static COutPoint buildOutPoint(const QTreeWidgetItem *item)
QTreeWidgetItem * contextMenuItem
static QList< Amount > payAmounts
friend class CCoinControlWidgetItem
static void updateLabels(CCoinControl &m_coin_control, WalletModel *, QDialog *)
const PlatformStyle * platformStyle
CCoinControl & m_coin_control
QAction * copyTransactionHashAction
Ui::CoinControlDialog * ui
void sortView(int, Qt::SortOrder)
CoinControlDialog(CCoinControl &coin_control, WalletModel *model, const PlatformStyle *platformStyle, QWidget *parent=nullptr)
void showMenu(const QPoint &)
void copyTransactionHash()
void viewItemChanged(QTreeWidgetItem *, int)
void clipboardLowOutput()
void buttonSelectAllClicked()
static bool fSubtractFeeFromAmount
void buttonBoxClicked(QAbstractButton *)
int getDisplayUnit() const
Interface to Bitcoin wallet from Qt view code.
interfaces::Node & node() const
const CChainParams & getChainParams() const
AddressTableModel * getAddressTableModel()
OptionsModel * getOptionsModel()
interfaces::Wallet & wallet() const
void SetHex(const char *psz)
const uint8_t * data() const
virtual CFeeRate getDustRelayFee()=0
Get dust relay fee.
virtual CoinsList listCoins()=0
virtual bool getPubKey(const CScript &script, const CKeyID &address, CPubKey &pub_key)=0
Get public key.
virtual std::vector< WalletTxOut > getCoins(const std::vector< COutPoint > &outputs)=0
Return wallet transaction output information.
virtual void unlockCoin(const COutPoint &output)=0
Unlock coin.
virtual bool isLockedCoin(const COutPoint &output)=0
Return whether coin is locked.
virtual void listLockedCoins(std::vector< COutPoint > &outputs)=0
List locked coins.
virtual void lockCoin(const COutPoint &output)=0
Lock coin.
virtual Amount getMinimumFee(unsigned int tx_bytes, const CCoinControl &coin_control)=0
Get minimum fee.
static constexpr Amount MIN_CHANGE
target minimum change amount
void handleCloseWindowShortcut(QWidget *w)
QString dateTimeStr(const QDateTime &date)
void setClipboard(const QString &str)
bool operator<(const CNetAddr &a, const CNetAddr &b)
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
CKeyID ToKeyID(const PKHash &key_hash)
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
static constexpr Amount zero() noexcept
A TxId is the identifier of a transaction.
Wallet transaction output.