Bitcoin ABC  0.24.7
P2P Digital Currency
coincontroldialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #if defined(HAVE_CONFIG_H)
6 #include <config/bitcoin-config.h>
7 #endif
8 
9 #include <qt/coincontroldialog.h>
10 #include <qt/forms/ui_coincontroldialog.h>
11 
12 #include <cashaddrenc.h>
13 #include <interfaces/node.h>
14 #include <key_io.h>
15 #include <policy/policy.h>
16 #include <qt/addresstablemodel.h>
17 #include <qt/bitcoinunits.h>
18 #include <qt/guiutil.h>
19 #include <qt/optionsmodel.h>
20 #include <qt/platformstyle.h>
21 #include <qt/walletmodel.h>
22 #include <wallet/coincontrol.h>
23 #include <wallet/wallet.h>
24 
25 #include <QApplication>
26 #include <QCheckBox>
27 #include <QCursor>
28 #include <QDialogButtonBox>
29 #include <QFlags>
30 #include <QIcon>
31 #include <QSettings>
32 #include <QTreeWidget>
33 
34 QList<Amount> CoinControlDialog::payAmounts;
36 
37 bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
38  int column = treeWidget()->sortColumn();
39  if (column == CoinControlDialog::COLUMN_AMOUNT ||
42  return data(column, Qt::UserRole).toLongLong() <
43  other.data(column, Qt::UserRole).toLongLong();
44  }
45  return QTreeWidgetItem::operator<(other);
46 }
47 
49  WalletModel *_model,
50  const PlatformStyle *_platformStyle,
51  QWidget *parent)
52  : QDialog(parent), ui(new Ui::CoinControlDialog),
53  m_coin_control(coin_control), model(_model),
54  platformStyle(_platformStyle) {
55  ui->setupUi(this);
56 
57  // context menu actions
58  QAction *copyAddressAction = new QAction(tr("Copy address"), this);
59  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
60  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
61  // we need to enable/disable this
62  copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this);
63  // we need to enable/disable this
64  lockAction = new QAction(tr("Lock unspent"), this);
65  // we need to enable/disable this
66  unlockAction = new QAction(tr("Unlock unspent"), this);
67 
68  // context menu
69  contextMenu = new QMenu(this);
70  contextMenu->addAction(copyAddressAction);
71  contextMenu->addAction(copyLabelAction);
72  contextMenu->addAction(copyAmountAction);
74  contextMenu->addSeparator();
75  contextMenu->addAction(lockAction);
76  contextMenu->addAction(unlockAction);
77 
78  // context menu signals
79  connect(ui->treeWidget, &QWidget::customContextMenuRequested, this,
81  connect(copyAddressAction, &QAction::triggered, this,
83  connect(copyLabelAction, &QAction::triggered, this,
85  connect(copyAmountAction, &QAction::triggered, this,
87  connect(copyTransactionHashAction, &QAction::triggered, this,
89  connect(lockAction, &QAction::triggered, this,
91  connect(unlockAction, &QAction::triggered, this,
93 
94  // clipboard actions
95  QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
96  QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
97  QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
98  QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
99  QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
100  QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
101  QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
102 
103  connect(clipboardQuantityAction, &QAction::triggered, this,
105  connect(clipboardAmountAction, &QAction::triggered, this,
107  connect(clipboardFeeAction, &QAction::triggered, this,
109  connect(clipboardAfterFeeAction, &QAction::triggered, this,
111  connect(clipboardBytesAction, &QAction::triggered, this,
113  connect(clipboardLowOutputAction, &QAction::triggered, this,
115  connect(clipboardChangeAction, &QAction::triggered, this,
117 
118  ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
119  ui->labelCoinControlAmount->addAction(clipboardAmountAction);
120  ui->labelCoinControlFee->addAction(clipboardFeeAction);
121  ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
122  ui->labelCoinControlBytes->addAction(clipboardBytesAction);
123  ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
124  ui->labelCoinControlChange->addAction(clipboardChangeAction);
125 
126  // toggle tree/list mode
127  connect(ui->radioTreeMode, &QRadioButton::toggled, this,
129  connect(ui->radioListMode, &QRadioButton::toggled, this,
131 
132  // click on checkbox
133  connect(ui->treeWidget, &QTreeWidget::itemChanged, this,
135 
136  // click on header
137  ui->treeWidget->header()->setSectionsClickable(true);
138  connect(ui->treeWidget->header(), &QHeaderView::sectionClicked, this,
140 
141  // ok button
142  connect(ui->buttonBox, &QDialogButtonBox::clicked, this,
144 
145  // (un)select all
146  connect(ui->pushButtonSelectAll, &QPushButton::clicked, this,
148 
149  ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
150  ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
151  ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
152  ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320);
153  ui->treeWidget->setColumnWidth(COLUMN_DATE, 130);
154  ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
155 
156  // default view is sorted by amount desc
157  sortView(COLUMN_AMOUNT, Qt::DescendingOrder);
158 
159  // restore list mode and sortorder as a convenience feature
160  QSettings settings;
161  if (settings.contains("nCoinControlMode") &&
162  !settings.value("nCoinControlMode").toBool()) {
163  ui->radioTreeMode->click();
164  }
165  if (settings.contains("nCoinControlSortColumn") &&
166  settings.contains("nCoinControlSortOrder")) {
167  sortView(settings.value("nCoinControlSortColumn").toInt(),
168  (static_cast<Qt::SortOrder>(
169  settings.value("nCoinControlSortOrder").toInt())));
170  }
171 
173 
174  if (_model->getOptionsModel() && _model->getAddressTableModel()) {
175  updateView();
178  }
179 }
180 
182  QSettings settings;
183  settings.setValue("nCoinControlMode", ui->radioListMode->isChecked());
184  settings.setValue("nCoinControlSortColumn", sortColumn);
185  settings.setValue("nCoinControlSortOrder", (int)sortOrder);
186 
187  delete ui;
188 }
189 
190 // ok button
191 void CoinControlDialog::buttonBoxClicked(QAbstractButton *button) {
192  if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
193  // closes the dialog
194  done(QDialog::Accepted);
195  }
196 }
197 
198 // (un)select all
200  Qt::CheckState state = Qt::Checked;
201  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) {
202  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) !=
203  Qt::Unchecked) {
204  state = Qt::Unchecked;
205  break;
206  }
207  }
208  ui->treeWidget->setEnabled(false);
209  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) {
210  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) !=
211  state) {
212  ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX,
213  state);
214  }
215  }
216  ui->treeWidget->setEnabled(true);
217  if (state == Qt::Unchecked) {
218  // just to be sure
220  }
222 }
223 
224 // context menu
225 void CoinControlDialog::showMenu(const QPoint &point) {
226  QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
227  if (item) {
228  contextMenuItem = item;
229 
230  // disable some items (like Copy Transaction ID, lock, unlock) for tree
231  // roots in context menu
232  if (item->data(COLUMN_ADDRESS, TxIdRole).toString().length() == 64) {
233  COutPoint outpoint = buildOutPoint(item);
234 
235  // transaction hash is 64 characters (this means it is a child node,
236  // so it is not a parent node in tree mode)
237  copyTransactionHashAction->setEnabled(true);
238  if (model->wallet().isLockedCoin(outpoint)) {
239  lockAction->setEnabled(false);
240  unlockAction->setEnabled(true);
241  } else {
242  lockAction->setEnabled(true);
243  unlockAction->setEnabled(false);
244  }
245  } else {
246  // this means click on parent node in tree mode -> disable all
247  copyTransactionHashAction->setEnabled(false);
248  lockAction->setEnabled(false);
249  unlockAction->setEnabled(false);
250  }
251 
252  // show context menu
253  contextMenu->exec(QCursor::pos());
254  }
255 }
256 
257 // context menu action: copy amount
261 }
262 
263 // context menu action: copy label
265  if (ui->radioTreeMode->isChecked() &&
266  contextMenuItem->text(COLUMN_LABEL).length() == 0 &&
267  contextMenuItem->parent()) {
269  } else {
271  }
272 }
273 
274 // context menu action: copy address
276  if (ui->radioTreeMode->isChecked() &&
277  contextMenuItem->text(COLUMN_ADDRESS).length() == 0 &&
278  contextMenuItem->parent()) {
280  } else {
282  }
283 }
284 
285 // context menu action: copy transaction id
288  contextMenuItem->data(COLUMN_ADDRESS, TxIdRole).toString());
289 }
290 
291 // context menu action: lock coin
293  if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) {
294  contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
295  }
296 
298  model->wallet().lockCoin(outpoint);
299  contextMenuItem->setDisabled(true);
300  contextMenuItem->setIcon(
301  COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
303 }
304 
305 // context menu action: unlock coin
308  model->wallet().unlockCoin(outpoint);
309  contextMenuItem->setDisabled(false);
310  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
312 }
313 
314 // copy label "Quantity" to clipboard
316  GUIUtil::setClipboard(ui->labelCoinControlQuantity->text());
317 }
318 
319 // copy label "Amount" to clipboard
321  GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(
322  ui->labelCoinControlAmount->text().indexOf(" ")));
323 }
324 
325 // copy label "Fee" to clipboard
328  ui->labelCoinControlFee->text()
329  .left(ui->labelCoinControlFee->text().indexOf(" "))
330  .replace(ASYMP_UTF8, ""));
331 }
332 
333 // copy label "After fee" to clipboard
336  ui->labelCoinControlAfterFee->text()
337  .left(ui->labelCoinControlAfterFee->text().indexOf(" "))
338  .replace(ASYMP_UTF8, ""));
339 }
340 
341 // copy label "Bytes" to clipboard
344  ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
345 }
346 
347 // copy label "Dust" to clipboard
349  GUIUtil::setClipboard(ui->labelCoinControlLowOutput->text());
350 }
351 
352 // copy label "Change" to clipboard
355  ui->labelCoinControlChange->text()
356  .left(ui->labelCoinControlChange->text().indexOf(" "))
357  .replace(ASYMP_UTF8, ""));
358 }
359 
360 // treeview: sort
361 void CoinControlDialog::sortView(int column, Qt::SortOrder order) {
362  sortColumn = column;
363  sortOrder = order;
364  ui->treeWidget->sortItems(column, order);
365  ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
366 }
367 
368 // treeview: clicked on header
370  // click on most left column -> do nothing
371  if (logicalIndex == COLUMN_CHECKBOX) {
372  ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
373  } else {
374  if (sortColumn == logicalIndex) {
375  sortOrder =
376  ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder
377  : Qt::AscendingOrder);
378  } else {
379  sortColumn = logicalIndex;
380  // if label or address then default => asc, else default => desc
381  sortOrder =
383  ? Qt::AscendingOrder
384  : Qt::DescendingOrder);
385  }
386 
388  }
389 }
390 
391 // toggle tree mode
393  if (checked && model) {
394  updateView();
395  }
396 }
397 
398 // toggle list mode
400  if (checked && model) {
401  updateView();
402  }
403 }
404 
405 // checkbox clicked by user
406 void CoinControlDialog::viewItemChanged(QTreeWidgetItem *item, int column) {
407  // transaction hash is 64 characters (this means it is a child node, so it
408  // is not a parent node in tree mode)
409  if (column == COLUMN_CHECKBOX &&
410  item->data(COLUMN_ADDRESS, TxIdRole).toString().length() == 64) {
411  COutPoint outpoint = buildOutPoint(item);
412 
413  if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) {
414  m_coin_control.UnSelect(outpoint);
415  } else if (item->isDisabled()) {
416  // locked (this happens if "check all" through parent node)
417  item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
418  } else {
419  m_coin_control.Select(outpoint);
420  }
421 
422  // selection changed -> update labels
423  if (ui->treeWidget->isEnabled()) {
424  // do not update on every click for (un)select all
426  }
427  }
428 }
429 
430 // shows count of locked unspent outputs
432  std::vector<COutPoint> vOutpts;
433  model->wallet().listLockedCoins(vOutpts);
434  if (vOutpts.size() > 0) {
435  ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
436  ui->labelLocked->setVisible(true);
437  } else {
438  ui->labelLocked->setVisible(false);
439  }
440 }
441 
443  WalletModel *model, QDialog *dialog) {
444  if (!model) {
445  return;
446  }
447 
448  // nPayAmount
449  Amount nPayAmount = Amount::zero();
450  bool fDust = false;
451  for (const Amount &amount : CoinControlDialog::payAmounts) {
452  nPayAmount += amount;
453 
454  if (amount > Amount::zero()) {
455  // Assumes a p2pkh script size
456  CTxOut txout(amount, CScript() << std::vector<uint8_t>(24, 0));
457  fDust |= IsDust(txout, model->node().getDustRelayFee());
458  }
459  }
460 
461  Amount nAmount = Amount::zero();
462  Amount nPayFee = Amount::zero();
463  Amount nAfterFee = Amount::zero();
464  Amount nChange = Amount::zero();
465  unsigned int nBytes = 0;
466  unsigned int nBytesInputs = 0;
467  unsigned int nQuantity = 0;
468 
469  std::vector<COutPoint> vCoinControl;
470  m_coin_control.ListSelected(vCoinControl);
471 
472  size_t i = 0;
473  for (const auto &out : model->wallet().getCoins(vCoinControl)) {
474  if (out.depth_in_main_chain < 0) {
475  continue;
476  }
477 
478  // unselect already spent, very unlikely scenario, this could happen
479  // when selected are spent elsewhere, like rpc or another computer
480  const COutPoint &output = vCoinControl[i++];
481  if (out.is_spent) {
482  m_coin_control.UnSelect(output);
483  continue;
484  }
485 
486  // Quantity
487  nQuantity++;
488 
489  // Amount
490  nAmount += out.txout.nValue;
491 
492  // Bytes
493  CTxDestination address;
494  if (ExtractDestination(out.txout.scriptPubKey, address)) {
495  CPubKey pubkey;
496  PKHash *pkhash = boost::get<PKHash>(&address);
497  if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey,
498  ToKeyID(*pkhash), pubkey)) {
499  nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
500  } else {
501  // in all error cases, simply assume 148 here
502  nBytesInputs += 148;
503  }
504  } else {
505  nBytesInputs += 148;
506  }
507  }
508 
509  // calculation
510  if (nQuantity > 0) {
511  // Bytes
512  // always assume +1 output for change here
513  nBytes = nBytesInputs +
514  ((CoinControlDialog::payAmounts.size() > 0
515  ? CoinControlDialog::payAmounts.size() + 1
516  : 2) *
517  34) +
518  10;
519 
520  // in the subtract fee from amount case, we can tell if zero change
521  // already and subtract the bytes, so that fee calculation afterwards is
522  // accurate
524  if (nAmount - nPayAmount == Amount::zero()) {
525  nBytes -= 34;
526  }
527  }
528 
529  // Fee
530  nPayFee = model->wallet().getMinimumFee(nBytes, m_coin_control);
531 
532  if (nPayAmount > Amount::zero()) {
533  nChange = nAmount - nPayAmount;
535  nChange -= nPayFee;
536  }
537 
538  // Never create dust outputs; if we would, just add the dust to the
539  // fee.
540  if (nChange > Amount::zero() && nChange < MIN_CHANGE) {
541  // Assumes a p2pkh script size
542  CTxOut txout(nChange, CScript() << std::vector<uint8_t>(24, 0));
543  if (IsDust(txout, model->node().getDustRelayFee())) {
544  nPayFee += nChange;
545  nChange = Amount::zero();
547  // we didn't detect lack of change above
548  nBytes -= 34;
549  }
550  }
551  }
552 
553  if (nChange == Amount::zero() &&
555  nBytes -= 34;
556  }
557  }
558 
559  // after fee
560  nAfterFee = std::max(nAmount - nPayFee, Amount::zero());
561  }
562 
563  // actually update labels
564  int nDisplayUnit = BitcoinUnits::base;
565  if (model && model->getOptionsModel()) {
566  nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
567  }
568 
569  QLabel *l1 = dialog->findChild<QLabel *>("labelCoinControlQuantity");
570  QLabel *l2 = dialog->findChild<QLabel *>("labelCoinControlAmount");
571  QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
572  QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
573  QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
574  QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
575  QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
576 
577  // enable/disable "dust" and "change"
578  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")
579  ->setEnabled(nPayAmount > Amount::zero());
580  dialog->findChild<QLabel *>("labelCoinControlLowOutput")
581  ->setEnabled(nPayAmount > Amount::zero());
582  dialog->findChild<QLabel *>("labelCoinControlChangeText")
583  ->setEnabled(nPayAmount > Amount::zero());
584  dialog->findChild<QLabel *>("labelCoinControlChange")
585  ->setEnabled(nPayAmount > Amount::zero());
586 
587  // stats
588  // Quantity
589  l1->setText(QString::number(nQuantity));
590  // Amount
591  l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount));
592  // Fee
593  l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee));
594  // After Fee
595  l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee));
596  // Bytes
597  l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes));
598  // Dust
599  l7->setText(fDust ? tr("yes") : tr("no"));
600  // Change
601  l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange));
602  if (nPayFee > Amount::zero()) {
603  l3->setText(ASYMP_UTF8 + l3->text());
604  l4->setText(ASYMP_UTF8 + l4->text());
605  if (nChange > Amount::zero() &&
607  l8->setText(ASYMP_UTF8 + l8->text());
608  }
609  }
610 
611  // turn label red when dust
612  l7->setStyleSheet((fDust) ? "color:red;" : "");
613 
614  // tool tips
615  QString toolTipDust =
616  tr("This label turns red if any recipient receives an amount smaller "
617  "than the current dust threshold.");
618 
619  // how many satoshis the estimated fee can vary per byte we guess wrong
620  double dFeeVary = (nBytes != 0) ? double(nPayFee / SATOSHI) / nBytes : 0;
621 
622  QString toolTip4 =
623  tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
624 
625  l3->setToolTip(toolTip4);
626  l4->setToolTip(toolTip4);
627  l7->setToolTip(toolTipDust);
628  l8->setToolTip(toolTip4);
629  dialog->findChild<QLabel *>("labelCoinControlFeeText")
630  ->setToolTip(l3->toolTip());
631  dialog->findChild<QLabel *>("labelCoinControlAfterFeeText")
632  ->setToolTip(l4->toolTip());
633  dialog->findChild<QLabel *>("labelCoinControlBytesText")
634  ->setToolTip(l5->toolTip());
635  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")
636  ->setToolTip(l7->toolTip());
637  dialog->findChild<QLabel *>("labelCoinControlChangeText")
638  ->setToolTip(l8->toolTip());
639 
640  // Insufficient funds
641  QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds");
642  if (label) {
643  label->setVisible(nChange < Amount::zero());
644  }
645 }
646 
647 COutPoint CoinControlDialog::buildOutPoint(const QTreeWidgetItem *item) {
648  TxId txid;
649  txid.SetHex(item->data(COLUMN_ADDRESS, TxIdRole).toString().toStdString());
650  return COutPoint(txid, item->data(COLUMN_ADDRESS, VOutRole).toUInt());
651 }
652 
655  return;
656  }
657 
658  bool treeMode = ui->radioTreeMode->isChecked();
659 
660  ui->treeWidget->clear();
661  // performance, otherwise updateLabels would be called for every checked
662  // checkbox
663  ui->treeWidget->setEnabled(false);
664  ui->treeWidget->setAlternatingRowColors(!treeMode);
665  QFlags<Qt::ItemFlag> flgCheckbox =
666  Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
667  QFlags<Qt::ItemFlag> flgTristate =
668  Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable |
669  Qt::ItemIsTristate;
670 
671  int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
672 
673  for (const auto &coins : model->wallet().listCoins()) {
674  CCoinControlWidgetItem *itemWalletAddress{nullptr};
675  QString sWalletAddress = QString::fromStdString(
676  EncodeCashAddr(coins.first, model->getChainParams()));
677  QString sWalletLabel =
678  model->getAddressTableModel()->labelForAddress(sWalletAddress);
679  if (sWalletLabel.isEmpty()) {
680  sWalletLabel = tr("(no label)");
681  }
682 
683  if (treeMode) {
684  // wallet address
685  itemWalletAddress = new CCoinControlWidgetItem(ui->treeWidget);
686 
687  itemWalletAddress->setFlags(flgTristate);
688  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
689 
690  // label
691  itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel);
692 
693  // address
694  itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress);
695  }
696 
697  Amount nSum = Amount::zero();
698  int nChildren = 0;
699  for (const auto &outpair : coins.second) {
700  const COutPoint &output = std::get<0>(outpair);
701  const interfaces::WalletTxOut &out = std::get<1>(outpair);
702  nSum += out.txout.nValue;
703  nChildren++;
704 
705  CCoinControlWidgetItem *itemOutput;
706  if (treeMode) {
707  itemOutput = new CCoinControlWidgetItem(itemWalletAddress);
708  } else {
709  itemOutput = new CCoinControlWidgetItem(ui->treeWidget);
710  }
711  itemOutput->setFlags(flgCheckbox);
712  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
713 
714  // address
715  CTxDestination outputAddress;
716  QString sAddress = "";
717  if (ExtractDestination(out.txout.scriptPubKey, outputAddress)) {
718  sAddress = QString::fromStdString(
719  EncodeCashAddr(outputAddress, model->getChainParams()));
720 
721  // if listMode or change => show bitcoin address. In tree mode,
722  // address is not shown again for direct wallet address outputs
723  if (!treeMode || (!(sAddress == sWalletAddress))) {
724  itemOutput->setText(COLUMN_ADDRESS, sAddress);
725  }
726  }
727 
728  // label
729  if (!(sAddress == sWalletAddress)) {
730  // change tooltip from where the change comes from
731  itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)")
732  .arg(sWalletLabel)
733  .arg(sWalletAddress));
734  itemOutput->setText(COLUMN_LABEL, tr("(change)"));
735  } else if (!treeMode) {
736  QString sLabel =
738  if (sLabel.isEmpty()) {
739  sLabel = tr("(no label)");
740  }
741  itemOutput->setText(COLUMN_LABEL, sLabel);
742  }
743 
744  // amount
745  itemOutput->setText(
747  BitcoinUnits::format(nDisplayUnit, out.txout.nValue));
748  // padding so that sorting works correctly
749  itemOutput->setData(
750  COLUMN_AMOUNT, Qt::UserRole,
751  QVariant(qlonglong(out.txout.nValue / SATOSHI)));
752 
753  // date
754  itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.time));
755  itemOutput->setData(COLUMN_DATE, Qt::UserRole,
756  QVariant((qlonglong)out.time));
757 
758  // confirmations
759  itemOutput->setText(COLUMN_CONFIRMATIONS,
760  QString::number(out.depth_in_main_chain));
761  itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole,
762  QVariant((qlonglong)out.depth_in_main_chain));
763 
764  // transaction id
765  itemOutput->setData(
767  QString::fromStdString(output.GetTxId().GetHex()));
768 
769  // vout index
770  itemOutput->setData(COLUMN_ADDRESS, VOutRole, output.GetN());
771 
772  // disable locked coins
773  if (model->wallet().isLockedCoin(output)) {
774  // just to be sure
775  m_coin_control.UnSelect(output);
776  itemOutput->setDisabled(true);
777  itemOutput->setIcon(
779  platformStyle->SingleColorIcon(":/icons/lock_closed"));
780  }
781 
782  // set checkbox
783  if (m_coin_control.IsSelected(output)) {
784  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
785  }
786  }
787 
788  // amount
789  if (treeMode) {
790  itemWalletAddress->setText(COLUMN_CHECKBOX,
791  "(" + QString::number(nChildren) + ")");
792  itemWalletAddress->setText(
793  COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
794  itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole,
795  QVariant(qlonglong(nSum / SATOSHI)));
796  }
797  }
798 
799  // expand all partially selected
800  if (treeMode) {
801  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) {
802  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) ==
803  Qt::PartiallyChecked) {
804  ui->treeWidget->topLevelItem(i)->setExpanded(true);
805  }
806  }
807  }
808 
809  // sort view
811  ui->treeWidget->setEnabled(true);
812 }
MIN_CHANGE
static constexpr Amount MIN_CHANGE
target minimum change amount
Definition: coinselection.h:15
ASYMP_UTF8
#define ASYMP_UTF8
Definition: coincontroldialog.h:29
CoinControlDialog::unlockAction
QAction * unlockAction
Definition: coincontroldialog.h:68
CCoinControl::Select
void Select(const COutPoint &output)
Definition: coincontrol.h:58
policy.h
WalletModel::getOptionsModel
OptionsModel * getOptionsModel()
Definition: walletmodel.cpp:315
CoinControlDialog::lockCoin
void lockCoin()
Definition: coincontroldialog.cpp:292
CTxOut::nValue
Amount nValue
Definition: transaction.h:132
CoinControlDialog::platformStyle
const PlatformStyle * platformStyle
Definition: coincontroldialog.h:70
CoinControlDialog::viewItemChanged
void viewItemChanged(QTreeWidgetItem *, int)
Definition: coincontroldialog.cpp:406
wallet.h
WalletModel
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
CoinControlDialog::showMenu
void showMenu(const QPoint &)
Definition: coincontroldialog.cpp:225
CCoinControl::ListSelected
void ListSelected(std::vector< COutPoint > &vOutpoints) const
Definition: coincontrol.h:64
key_io.h
interfaces::WalletTxOut::depth_in_main_chain
int depth_in_main_chain
Definition: wallet.h:404
operator<
bool operator<(const CNetAddr &a, const CNetAddr &b)
Definition: netaddress.cpp:605
PlatformStyle::SingleColorIcon
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
Definition: platformstyle.cpp:97
walletmodel.h
CoinControlDialog::updateView
void updateView()
Definition: coincontroldialog.cpp:653
WalletModel::getAddressTableModel
AddressTableModel * getAddressTableModel()
Definition: walletmodel.cpp:319
AddressTableModel::labelForAddress
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
Definition: addresstablemodel.cpp:386
CCoinControl
Coin Control Features.
Definition: coincontrol.h:21
interfaces::Wallet::listLockedCoins
virtual void listLockedCoins(std::vector< COutPoint > &outputs)=0
List locked coins.
CoinControlDialog
Definition: coincontroldialog.h:41
node.h
CoinControlDialog::m_coin_control
CCoinControl & m_coin_control
Definition: coincontroldialog.h:59
interfaces::Wallet::getMinimumFee
virtual Amount getMinimumFee(unsigned int tx_bytes, const CCoinControl &coin_control)=0
Get minimum fee.
CoinControlDialog::sortColumn
int sortColumn
Definition: coincontroldialog.h:61
CoinControlDialog::clipboardChange
void clipboardChange()
Definition: coincontroldialog.cpp:353
CCoinControl::IsSelected
bool IsSelected(const COutPoint &output) const
Definition: coincontrol.h:54
interfaces::WalletTxOut
Wallet transaction output.
Definition: wallet.h:401
CoinControlDialog::updateLabels
static void updateLabels(CCoinControl &m_coin_control, WalletModel *, QDialog *)
Definition: coincontroldialog.cpp:442
CoinControlDialog::radioListMode
void radioListMode(bool)
Definition: coincontroldialog.cpp:399
CoinControlDialog::model
WalletModel * model
Definition: coincontroldialog.h:60
CoinControlDialog::headerSectionClicked
void headerSectionClicked(int)
Definition: coincontroldialog.cpp:369
CoinControlDialog::clipboardLowOutput
void clipboardLowOutput()
Definition: coincontroldialog.cpp:348
BitcoinUnits::format
static QString format(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
Definition: bitcoinunits.cpp:108
GUIUtil::setClipboard
void setClipboard(const QString &str)
Definition: guiutil.cpp:766
Amount::zero
static constexpr Amount zero()
Definition: amount.h:42
CoinControlDialog::copyTransactionHashAction
QAction * copyTransactionHashAction
Definition: coincontroldialog.h:66
CoinControlDialog::copyLabel
void copyLabel()
Definition: coincontroldialog.cpp:264
WalletModel::node
interfaces::Node & node() const
Definition: walletmodel.h:149
CoinControlDialog::fSubtractFeeFromAmount
static bool fSubtractFeeFromAmount
Definition: coincontroldialog.h:55
CoinControlDialog::buttonSelectAllClicked
void buttonSelectAllClicked()
Definition: coincontroldialog.cpp:199
SATOSHI
static constexpr Amount SATOSHI
Definition: amount.h:153
BitcoinUnits::removeSpaces
static QString removeSpaces(QString text)
Definition: bitcoinunits.h:98
CoinControlDialog::sortView
void sortView(int, Qt::SortOrder)
Definition: coincontroldialog.cpp:361
WalletModel::wallet
interfaces::Wallet & wallet() const
Definition: walletmodel.h:150
interfaces::Wallet::unlockCoin
virtual void unlockCoin(const COutPoint &output)=0
Unlock coin.
COutPoint::GetTxId
const TxId & GetTxId() const
Definition: transaction.h:37
CoinControlDialog::copyTransactionHash
void copyTransactionHash()
Definition: coincontroldialog.cpp:286
CTxOut
An output of a transaction.
Definition: transaction.h:130
EncodeCashAddr
std::string EncodeCashAddr(const CTxDestination &dst, const CChainParams &params)
Definition: cashaddrenc.cpp:91
CoinControlDialog::contextMenuItem
QTreeWidgetItem * contextMenuItem
Definition: coincontroldialog.h:65
CoinControlDialog::clipboardAmount
void clipboardAmount()
Definition: coincontroldialog.cpp:320
CoinControlDialog::buttonBoxClicked
void buttonBoxClicked(QAbstractButton *)
Definition: coincontroldialog.cpp:191
CTxOut::scriptPubKey
CScript scriptPubKey
Definition: transaction.h:133
CoinControlDialog::clipboardAfterFee
void clipboardAfterFee()
Definition: coincontroldialog.cpp:334
interfaces::Wallet::isLockedCoin
virtual bool isLockedCoin(const COutPoint &output)=0
Return whether coin is locked.
CoinControlDialog::clipboardBytes
void clipboardBytes()
Definition: coincontroldialog.cpp:342
CoinControlDialog::~CoinControlDialog
~CoinControlDialog()
Definition: coincontroldialog.cpp:181
CoinControlDialog::updateLabelLocked
void updateLabelLocked()
Definition: coincontroldialog.cpp:431
WalletModel::getChainParams
const CChainParams & getChainParams() const
Definition: walletmodel.cpp:531
CCoinControl::UnSelectAll
void UnSelectAll()
Definition: coincontrol.h:62
BitcoinUnits::formatWithUnit
static QString formatWithUnit(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
Definition: bitcoinunits.cpp:161
base_blob::GetHex
std::string GetHex() const
Definition: uint256.cpp:16
guiutil.h
TxId
A TxId is the identifier of a transaction.
Definition: txid.h:14
Amount
Definition: amount.h:19
interfaces::WalletTxOut::txout
CTxOut txout
Definition: wallet.h:402
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:430
ExtractDestination
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:161
CoinControlDialog::lockAction
QAction * lockAction
Definition: coincontroldialog.h:67
CoinControlDialog::CoinControlDialog
CoinControlDialog(CCoinControl &coin_control, WalletModel *model, const PlatformStyle *platformStyle, QWidget *parent=nullptr)
Definition: coincontroldialog.cpp:48
CCoinControlWidgetItem::operator<
bool operator<(const QTreeWidgetItem &other) const override
Definition: coincontroldialog.cpp:37
CoinControlDialog::unlockCoin
void unlockCoin()
Definition: coincontroldialog.cpp:306
CoinControlDialog::CCoinControlWidgetItem
friend class CCoinControlWidgetItem
Definition: coincontroldialog.h:86
CPubKey::IsCompressed
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:159
platformstyle.h
interfaces::Node::getDustRelayFee
virtual CFeeRate getDustRelayFee()=0
Get dust relay fee.
PKHash
Definition: standard.h:106
ToKeyID
CKeyID ToKeyID(const PKHash &key_hash)
Definition: standard.cpp:28
CoinControlDialog::ui
Ui::CoinControlDialog * ui
Definition: coincontroldialog.h:58
CPubKey
An encapsulated public key.
Definition: pubkey.h:31
CCoinControlWidgetItem
Definition: coincontroldialog.h:31
Ui
Definition: addressbookpage.h:14
CoinControlDialog::clipboardQuantity
void clipboardQuantity()
Definition: coincontroldialog.cpp:315
interfaces::Wallet::listCoins
virtual CoinsList listCoins()=0
CoinControlDialog::TxIdRole
@ TxIdRole
Definition: coincontroldialog.h:84
CoinControlDialog::COLUMN_DATE
@ COLUMN_DATE
Definition: coincontroldialog.h:80
CoinControlDialog::payAmounts
static QList< Amount > payAmounts
Definition: coincontroldialog.h:54
OptionsModel::getDisplayUnit
int getDisplayUnit() const
Definition: optionsmodel.h:97
interfaces::Wallet::lockCoin
virtual void lockCoin(const COutPoint &output)=0
Lock coin.
CoinControlDialog::COLUMN_AMOUNT
@ COLUMN_AMOUNT
Definition: coincontroldialog.h:77
interfaces::Wallet::getPubKey
virtual bool getPubKey(const CScript &script, const CKeyID &address, CPubKey &pub_key)=0
Get public key.
CoinControlDialog::radioTreeMode
void radioTreeMode(bool)
Definition: coincontroldialog.cpp:392
CoinControlDialog::contextMenu
QMenu * contextMenu
Definition: coincontroldialog.h:64
coincontroldialog.h
CoinControlDialog::COLUMN_ADDRESS
@ COLUMN_ADDRESS
Definition: coincontroldialog.h:79
IsDust
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:34
bitcoinunits.h
CoinControlDialog::copyAddress
void copyAddress()
Definition: coincontroldialog.cpp:275
GUIUtil::dateTimeStr
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:67
CoinControlDialog::copyAmount
void copyAmount()
Definition: coincontroldialog.cpp:258
COutPoint::GetN
uint32_t GetN() const
Definition: transaction.h:38
GUIUtil::handleCloseWindowShortcut
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:396
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
optionsmodel.h
BitcoinUnits::base
@ base
Definition: bitcoinunits.h:42
coincontrol.h
CoinControlDialog::COLUMN_CHECKBOX
@ COLUMN_CHECKBOX
Definition: coincontroldialog.h:76
CoinControlDialog::sortOrder
Qt::SortOrder sortOrder
Definition: coincontroldialog.h:62
CoinControlDialog::COLUMN_LABEL
@ COLUMN_LABEL
Definition: coincontroldialog.h:78
PlatformStyle
Definition: platformstyle.h:13
CoinControlDialog::clipboardFee
void clipboardFee()
Definition: coincontroldialog.cpp:326
CoinControlDialog::VOutRole
@ VOutRole
Definition: coincontroldialog.h:84
CoinControlDialog::buildOutPoint
static COutPoint buildOutPoint(const QTreeWidgetItem *item)
Definition: coincontroldialog.cpp:647
addresstablemodel.h
interfaces::WalletTxOut::time
int64_t time
Definition: wallet.h:403
CTxDestination
boost::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:132
base_blob::data
const uint8_t * data() const
Definition: uint256.h:80
cashaddrenc.h
base_blob::SetHex
void SetHex(const char *psz)
Definition: uint256.cpp:24
CCoinControl::UnSelect
void UnSelect(const COutPoint &output)
Definition: coincontrol.h:60
interfaces::Wallet::getCoins
virtual std::vector< WalletTxOut > getCoins(const std::vector< COutPoint > &outputs)=0
Return wallet transaction output information.
CoinControlDialog::COLUMN_CONFIRMATIONS
@ COLUMN_CONFIRMATIONS
Definition: coincontroldialog.h:81