Dash Core  0.12.2.1
P2P Digital Currency
coincontroldialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Copyright (c) 2014-2017 The Dash Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "coincontroldialog.h"
7 #include "ui_coincontroldialog.h"
8 
9 #include "addresstablemodel.h"
10 #include "bitcoinunits.h"
11 #include "guiutil.h"
12 #include "optionsmodel.h"
13 #include "platformstyle.h"
14 #include "txmempool.h"
15 #include "walletmodel.h"
16 
17 #include "coincontrol.h"
18 #include "init.h"
19 #include "validation.h" // For minRelayTxFee
20 #include "wallet/wallet.h"
21 
22 #include "instantx.h"
23 #include "privatesend-client.h"
24 
25 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
26 
27 #include <QApplication>
28 #include <QCheckBox>
29 #include <QCursor>
30 #include <QDialogButtonBox>
31 #include <QFlags>
32 #include <QIcon>
33 #include <QSettings>
34 #include <QString>
35 #include <QTreeWidget>
36 #include <QTreeWidgetItem>
37 
38 QList<CAmount> CoinControlDialog::payAmounts;
41 
42 CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
43  QDialog(parent),
44  ui(new Ui::CoinControlDialog),
45  model(0),
46  platformStyle(platformStyle)
47 {
48  ui->setupUi(this);
49 
50  /* Open CSS when configured */
51  this->setStyleSheet(GUIUtil::loadStyleSheet());
52 
53  // context menu actions
54  QAction *copyAddressAction = new QAction(tr("Copy address"), this);
55  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
56  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
57  copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this
58  lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this
59  unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
60 
61  // context menu
62  contextMenu = new QMenu(this);
63  contextMenu->addAction(copyAddressAction);
64  contextMenu->addAction(copyLabelAction);
65  contextMenu->addAction(copyAmountAction);
67  contextMenu->addSeparator();
68  contextMenu->addAction(lockAction);
69  contextMenu->addAction(unlockAction);
70 
71  // context menu signals
72  connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
73  connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
74  connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
75  connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
76  connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash()));
77  connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin()));
78  connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin()));
79 
80  // clipboard actions
81  QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
82  QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
83  QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
84  QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
85  QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
86  QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
87  QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
88 
89  connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity()));
90  connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount()));
91  connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
92  connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
93  connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
94  connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
95  connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
96 
97  ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
98  ui->labelCoinControlAmount->addAction(clipboardAmountAction);
99  ui->labelCoinControlFee->addAction(clipboardFeeAction);
100  ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
101  ui->labelCoinControlBytes->addAction(clipboardBytesAction);
102  ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
103  ui->labelCoinControlChange->addAction(clipboardChangeAction);
104 
105  // toggle tree/list mode
106  connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool)));
107  connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool)));
108 
109  // click on checkbox
110  connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int)));
111 
112  // click on header
113 #if QT_VERSION < 0x050000
114  ui->treeWidget->header()->setClickable(true);
115 #else
116  ui->treeWidget->header()->setSectionsClickable(true);
117 #endif
118  connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int)));
119 
120  // ok button
121  connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*)));
122 
123  // (un)select all
124  connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
125 
126  // Toggle lock state
127  connect(ui->pushButtonToggleLock, SIGNAL(clicked()), this, SLOT(buttonToggleLockClicked()));
128 
129  // change coin control first column label due Qt4 bug.
130  // see https://github.com/bitcoin/bitcoin/issues/5716
131  ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
132 
133  ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
134  ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
135  ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
136  ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 190);
137  ui->treeWidget->setColumnWidth(COLUMN_PRIVATESEND_ROUNDS, 88);
138  ui->treeWidget->setColumnWidth(COLUMN_DATE, 80);
139  ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
140  ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
141  ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
142  ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
143  ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it
144 
145  // default view is sorted by amount desc
146  sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
147 
148  // restore list mode and sortorder as a convenience feature
149  QSettings settings;
150  if (settings.contains("nCoinControlMode") && !settings.value("nCoinControlMode").toBool())
151  ui->radioTreeMode->click();
152  if (settings.contains("nCoinControlSortColumn") && settings.contains("nCoinControlSortOrder"))
153  sortView(settings.value("nCoinControlSortColumn").toInt(), ((Qt::SortOrder)settings.value("nCoinControlSortOrder").toInt()));
154 }
155 
157 {
158  QSettings settings;
159  settings.setValue("nCoinControlMode", ui->radioListMode->isChecked());
160  settings.setValue("nCoinControlSortColumn", sortColumn);
161  settings.setValue("nCoinControlSortOrder", (int)sortOrder);
162 
163  delete ui;
164 }
165 
167 {
168  this->model = model;
169 
171  {
172  updateView();
175  }
176 }
177 
178 // helper function str_pad
179 QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
180 {
181  while (s.length() < nPadLength)
182  s = sPadding + s;
183 
184  return s;
185 }
186 
187 // ok button
188 void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
189 {
190  if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
191  done(QDialog::Accepted); // closes the dialog
192 }
193 
194 // (un)select all
196 {
197  Qt::CheckState state = Qt::Checked;
198  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
199  {
200  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked)
201  {
202  state = Qt::Unchecked;
203  break;
204  }
205  }
206  ui->treeWidget->setEnabled(false);
207  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
208  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state)
209  ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state);
210  ui->treeWidget->setEnabled(true);
211  if (state == Qt::Unchecked)
212  coinControl->UnSelectAll(); // just to be sure
214 }
215 
216 // Toggle lock state
218 {
219  QTreeWidgetItem *item;
220  QString theme = GUIUtil::getThemeName();
221  // Works in list-mode only
222  if(ui->radioListMode->isChecked()){
223  ui->treeWidget->setEnabled(false);
224  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++){
225  item = ui->treeWidget->topLevelItem(i);
226  COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
227  if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())){
228  model->unlockCoin(outpt);
229  item->setDisabled(false);
230  item->setIcon(COLUMN_CHECKBOX, QIcon());
231  }
232  else{
233  model->lockCoin(outpt);
234  item->setDisabled(true);
235  item->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/" + theme + "/lock_closed"));
236  }
238  }
239  ui->treeWidget->setEnabled(true);
241  }
242  else{
243  QMessageBox msgBox;
244  msgBox.setObjectName("lockMessageBox");
245  msgBox.setStyleSheet(GUIUtil::loadStyleSheet());
246  msgBox.setText(tr("Please switch to \"List mode\" to use this function."));
247  msgBox.exec();
248  }
249 }
250 
251 // context menu
252 void CoinControlDialog::showMenu(const QPoint &point)
253 {
254  QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
255  if(item)
256  {
257  contextMenuItem = item;
258 
259  // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu
260  if (item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode)
261  {
262  copyTransactionHashAction->setEnabled(true);
263  if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()))
264  {
265  lockAction->setEnabled(false);
266  unlockAction->setEnabled(true);
267  }
268  else
269  {
270  lockAction->setEnabled(true);
271  unlockAction->setEnabled(false);
272  }
273  }
274  else // this means click on parent node in tree mode -> disable all
275  {
276  copyTransactionHashAction->setEnabled(false);
277  lockAction->setEnabled(false);
278  unlockAction->setEnabled(false);
279  }
280 
281  // show context menu
282  contextMenu->exec(QCursor::pos());
283  }
284 }
285 
286 // context menu action: copy amount
288 {
290 }
291 
292 // context menu action: copy label
294 {
295  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent())
297  else
299 }
300 
301 // context menu action: copy address
303 {
304  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent())
306  else
308 }
309 
310 // context menu action: copy transaction id
312 {
314 }
315 
316 // context menu action: lock coin
318 {
319  QString theme = GUIUtil::getThemeName();
320  if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
321  contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
322 
323  COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
324  model->lockCoin(outpt);
325  contextMenuItem->setDisabled(true);
326  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/" + theme + "/lock_closed"));
328 }
329 
330 // context menu action: unlock coin
332 {
333  COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
334  model->unlockCoin(outpt);
335  contextMenuItem->setDisabled(false);
336  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
338 }
339 
340 // copy label "Quantity" to clipboard
342 {
344 }
345 
346 // copy label "Amount" to clipboard
348 {
349  GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
350 }
351 
352 // copy label "Fee" to clipboard
354 {
355  GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
356 }
357 
358 // copy label "After fee" to clipboard
360 {
361  GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
362 }
363 
364 // copy label "Bytes" to clipboard
366 {
368 }
369 
370 // copy label "Dust" to clipboard
372 {
374 }
375 
376 // copy label "Change" to clipboard
378 {
379  GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
380 }
381 
382 // treeview: sort
383 void CoinControlDialog::sortView(int column, Qt::SortOrder order)
384 {
385  sortColumn = column;
386  sortOrder = order;
387  ui->treeWidget->sortItems(column, order);
388  ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
389 }
390 
391 // treeview: clicked on header
393 {
394  if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
395  {
396  ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
397  }
398  else
399  {
400  logicalIndex = getMappedColumn(logicalIndex, false);
401 
402  if (sortColumn == logicalIndex)
403  sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
404  else
405  {
406  sortColumn = logicalIndex;
407  sortOrder = ((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) ? Qt::AscendingOrder : Qt::DescendingOrder); // if label or address then default => asc, else default => desc
408  }
409 
411  }
412 }
413 
414 // toggle tree mode
416 {
417  if (checked && model)
418  updateView();
419 }
420 
421 // toggle list mode
423 {
424  if (checked && model)
425  updateView();
426 }
427 
428 // checkbox clicked by user
429 void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
430 {
431  if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) // transaction hash is 64 characters (this means its a child node, so its not a parent node in tree mode)
432  {
433  COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
434 
435  if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
436  coinControl->UnSelect(outpt);
437  else if (item->isDisabled()) // locked (this happens if "check all" through parent node)
438  item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
439  else {
440  coinControl->Select(outpt);
441  int nRounds = pwalletMain->GetOutpointPrivateSendRounds(outpt);
443  QMessageBox::warning(this, windowTitle(),
444  tr("Non-anonymized input selected. <b>PrivateSend will be disabled.</b><br><br>If you still want to use PrivateSend, please deselect all non-nonymized inputs first and then check PrivateSend checkbox again."),
445  QMessageBox::Ok, QMessageBox::Ok);
446  coinControl->fUsePrivateSend = false;
447  }
448  }
449 
450  // selection changed -> update labels
451  if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all
453  }
454 
455  // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used.
456  // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473
457 #if QT_VERSION >= 0x050000
458  else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
459  {
460  if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
461  item->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
462  }
463 #endif
464 }
465 
466 // shows count of locked unspent outputs
468 {
469  std::vector<COutPoint> vOutpts;
470  model->listLockedCoins(vOutpts);
471  if (vOutpts.size() > 0)
472  {
473  ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
474  ui->labelLocked->setVisible(true);
475  }
476  else ui->labelLocked->setVisible(false);
477 }
478 
479 void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
480 {
481  if (!model)
482  return;
483 
484  // nPayAmount
485  CAmount nPayAmount = 0;
486  bool fDust = false;
487  CMutableTransaction txDummy;
488  Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts)
489  {
490  nPayAmount += amount;
491 
492  if (amount > 0)
493  {
494  CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
495  txDummy.vout.push_back(txout);
496  if (txout.IsDust(::minRelayTxFee))
497  fDust = true;
498  }
499  }
500 
501  CAmount nAmount = 0;
502  CAmount nPayFee = 0;
503  CAmount nAfterFee = 0;
504  CAmount nChange = 0;
505  unsigned int nBytes = 0;
506  unsigned int nBytesInputs = 0;
507  double dPriority = 0;
508  double dPriorityInputs = 0;
509  unsigned int nQuantity = 0;
510  int nQuantityUncompressed = 0;
511  bool fAllowFree = false;
512 
513  std::vector<COutPoint> vCoinControl;
514  std::vector<COutput> vOutputs;
515  coinControl->ListSelected(vCoinControl);
516  model->getOutputs(vCoinControl, vOutputs);
517 
518  BOOST_FOREACH(const COutput& out, vOutputs) {
519  // unselect already spent, very unlikely scenario, this could happen
520  // when selected are spent elsewhere, like rpc or another computer
521  uint256 txhash = out.tx->GetHash();
522  COutPoint outpt(txhash, out.i);
523  if (model->isSpent(outpt))
524  {
525  coinControl->UnSelect(outpt);
526  continue;
527  }
528 
529  // Quantity
530  nQuantity++;
531 
532  // Amount
533  nAmount += out.tx->vout[out.i].nValue;
534 
535  // Priority
536  dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
537 
538  // Bytes
539  CTxDestination address;
540  if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
541  {
542  CPubKey pubkey;
543  CKeyID *keyid = boost::get<CKeyID>(&address);
544  if (keyid && model->getPubKey(*keyid, pubkey))
545  {
546  nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
547  if (!pubkey.IsCompressed())
548  nQuantityUncompressed++;
549  }
550  else
551  nBytesInputs += 148; // in all error cases, simply assume 148 here
552  }
553  else nBytesInputs += 148;
554 
555  // Add inputs to calculate InstantSend Fee later
557  txDummy.vin.push_back(CTxIn());
558  }
559 
560  // calculation
561  if (nQuantity > 0)
562  {
563  // Bytes
564  nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here
565 
566  // in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate
568  if (nAmount - nPayAmount == 0)
569  nBytes -= 34;
570 
571  // Fee
572  nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
573  if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
574  nPayFee = coinControl->nMinimumTotalFee;
575 
576  // InstantSend Fee
577  if (coinControl->fUseInstantSend) nPayFee = std::max(nPayFee, CTxLockRequest(txDummy).GetMinFee());
578 
579  // Allow free? (require at least hard-coded threshold and default to that if no estimate)
580  double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
581  dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
582  double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
583  fAllowFree = (dPriority >= dPriorityNeeded);
584 
586  if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
587  nPayFee = 0;
588 
589  if (nPayAmount > 0)
590  {
591  nChange = nAmount - nPayAmount;
593  nChange -= nPayFee;
594 
595  // PrivateSend Fee = overpay
596  if(coinControl->fUsePrivateSend && nChange > 0)
597  {
598  nPayFee += nChange;
599  nChange = 0;
600  }
601  // Never create dust outputs; if we would, just add the dust to the fee.
602  if (nChange > 0 && nChange < MIN_CHANGE)
603  {
604  CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
605  if (txout.IsDust(::minRelayTxFee))
606  {
607  if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
608  nChange = txout.GetDustThreshold(::minRelayTxFee);
609  else
610  {
611  nPayFee += nChange;
612  nChange = 0;
613  }
614  }
615  }
616 
617  if (nChange == 0 && !CoinControlDialog::fSubtractFeeFromAmount)
618  nBytes -= 34;
619  }
620 
621  // after fee
622  nAfterFee = nAmount - nPayFee;
623  if (nAfterFee < 0)
624  nAfterFee = 0;
625  }
626 
627  // actually update labels
628  int nDisplayUnit = BitcoinUnits::DASH;
629  if (model && model->getOptionsModel())
630  nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
631 
632  QLabel *l1 = dialog->findChild<QLabel *>("labelCoinControlQuantity");
633  QLabel *l2 = dialog->findChild<QLabel *>("labelCoinControlAmount");
634  QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
635  QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
636  QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
637  QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
638  QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
639 
640  // enable/disable "dust" and "change"
641  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0);
642  dialog->findChild<QLabel *>("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0);
643  dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0);
644  dialog->findChild<QLabel *>("labelCoinControlChange") ->setEnabled(nPayAmount > 0);
645 
646  // stats
647  l1->setText(QString::number(nQuantity)); // Quantity
648  l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount
649  l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
650  l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
651  l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
652  l7->setText(fDust ? tr("yes") : tr("no")); // Dust
653  l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
654  if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee))
655  {
656  l3->setText(ASYMP_UTF8 + l3->text());
657  l4->setText(ASYMP_UTF8 + l4->text());
658  if (nChange > 0 && !CoinControlDialog::fSubtractFeeFromAmount)
659  l8->setText(ASYMP_UTF8 + l8->text());
660  }
661 
662  // turn label red when dust
663  l7->setStyleSheet((fDust) ? "color:red;" : "");
664 
665  // tool tips
666  QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
667 
668  // how many satoshis the estimated fee can vary per byte we guess wrong
669  double dFeeVary;
670  if (payTxFee.GetFeePerK() > 0)
671  dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
672  else {
673  dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateSmartFee(nTxConfirmTarget).GetFeePerK()) / 1000;
674  }
675  QString toolTip4 = tr("Can vary +/- %1 duff(s) per input.").arg(dFeeVary);
676 
677  l3->setToolTip(toolTip4);
678  l4->setToolTip(toolTip4);
679  l7->setToolTip(toolTipDust);
680  l8->setToolTip(toolTip4);
681  dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
682  dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
683  dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
684  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
685  dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
686 
687  // Insufficient funds
688  QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds");
689  if (label)
690  label->setVisible(nChange < 0);
691 }
692 
694 {
696  return;
697 
698  bool treeMode = ui->radioTreeMode->isChecked();
699  QString theme = GUIUtil::getThemeName();
700 
701  ui->treeWidget->clear();
702  ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
703  ui->treeWidget->setAlternatingRowColors(!treeMode);
704  QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
705  QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
706 
707  int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
708 
709  std::map<QString, std::vector<COutput> > mapCoins;
710  model->listCoins(mapCoins);
711 
712  BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
713  QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
714  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
715  QString sWalletAddress = coins.first;
716  QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
717  if (sWalletLabel.isEmpty())
718  sWalletLabel = tr("(no label)");
719 
720  if (treeMode)
721  {
722  // wallet address
723  ui->treeWidget->addTopLevelItem(itemWalletAddress);
724 
725  itemWalletAddress->setFlags(flgTristate);
726  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
727 
728  // label
729  itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel);
730  itemWalletAddress->setToolTip(COLUMN_LABEL, sWalletLabel);
731 
732  // address
733  itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress);
734  itemWalletAddress->setToolTip(COLUMN_ADDRESS, sWalletAddress);
735  }
736 
737  CAmount nSum = 0;
738  int nChildren = 0;
739  BOOST_FOREACH(const COutput& out, coins.second) {
740  nSum += out.tx->vout[out.i].nValue;
741  nChildren++;
742 
743  QTreeWidgetItem *itemOutput;
744  if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress);
745  else itemOutput = new QTreeWidgetItem(ui->treeWidget);
746  itemOutput->setFlags(flgCheckbox);
747  itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
748 
749  // address
750  CTxDestination outputAddress;
751  QString sAddress = "";
752  if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress))
753  {
754  sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
755 
756  // if listMode or change => show dash address. In tree mode, address is not shown again for direct wallet address outputs
757  if (!treeMode || (!(sAddress == sWalletAddress)))
758  itemOutput->setText(COLUMN_ADDRESS, sAddress);
759 
760  itemOutput->setToolTip(COLUMN_ADDRESS, sAddress);
761  }
762 
763  // label
764  if (!(sAddress == sWalletAddress)) // change
765  {
766  // tooltip from where the change comes from
767  itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress));
768  itemOutput->setText(COLUMN_LABEL, tr("(change)"));
769  }
770  else if (!treeMode)
771  {
772  QString sLabel = model->getAddressTableModel()->labelForAddress(sAddress);
773  if (sLabel.isEmpty())
774  sLabel = tr("(no label)");
775  itemOutput->setText(COLUMN_LABEL, sLabel);
776  }
777 
778  // amount
779  itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
780  itemOutput->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
781  itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
782 
783  // date
784  itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
785  itemOutput->setToolTip(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
786  itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " "));
787 
788 
789  // PrivateSend rounds
790  COutPoint outpoint = COutPoint(out.tx->GetHash(), out.i);
791  int nRounds = pwalletMain->GetOutpointPrivateSendRounds(outpoint);
792 
793  if (nRounds >= 0 || fDebug) itemOutput->setText(COLUMN_PRIVATESEND_ROUNDS, strPad(QString::number(nRounds), 11, " "));
794  else itemOutput->setText(COLUMN_PRIVATESEND_ROUNDS, strPad(QString(tr("n/a")), 11, " "));
795 
796 
797  // confirmations
798  itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
799 
800  // transaction hash
801  uint256 txhash = out.tx->GetHash();
802  itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
803 
804  // vout index
805  itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
806 
807  // disable locked coins
808  if (model->isLockedCoin(txhash, out.i))
809  {
810  COutPoint outpt(txhash, out.i);
811  coinControl->UnSelect(outpt); // just to be sure
812  itemOutput->setDisabled(true);
813  itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/" + theme + "/lock_closed"));
814  }
815 
816  // set checkbox
817  if (coinControl->IsSelected(COutPoint(txhash, out.i)))
818  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
819  }
820 
821  // amount
822  if (treeMode)
823  {
824  itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
825  itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
826  itemWalletAddress->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
827  itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
828  }
829  }
830 
831  // expand all partially selected
832  if (treeMode)
833  {
834  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
835  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
836  ui->treeWidget->topLevelItem(i)->setExpanded(true);
837  }
838 
839  // sort view
841  ui->treeWidget->setEnabled(true);
842 }
static QList< CAmount > payAmounts
QString loadStyleSheet()
Definition: guiutil.cpp:914
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
Definition: standard.h:69
Ui::CoinControlDialog * ui
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Definition: standard.cpp:164
static void updateLabels(WalletModel *, QDialog *)
bool IsSelected(const COutPoint &output) const
Definition: coincontrol.h:45
bool fDebug
Definition: util.cpp:124
CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks=NULL) const
Definition: txmempool.cpp:883
double AllowFreeThreshold()
Definition: txmempool.h:26
void viewItemChanged(QTreeWidgetItem *, int)
double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks=NULL) const
Definition: txmempool.cpp:893
QDialogButtonBox * buttonBox
Definition: pubkey.h:27
void Select(const COutPoint &output)
Definition: coincontrol.h:50
bool fUseInstantSend
Definition: coincontrol.h:16
CWallet * pwalletMain
std::vector< CTxIn > vin
Definition: transaction.h:306
int getMappedColumn(int column, bool fVisibleColumn=true)
void showMenu(const QPoint &)
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
#define ASYMP_UTF8
QRadioButton * radioListMode
dictionary settings
void ListSelected(std::vector< COutPoint > &vOutpoints) const
Definition: coincontrol.h:65
static const CAmount MIN_CHANGE
minimum change amount
Definition: wallet.h:64
int64_t CAmount
Definition: amount.h:14
void unlockCoin(COutPoint &output)
unsigned int nTxConfirmTarget
Definition: wallet.cpp:47
bool fSendFreeTransactions
Definition: wallet.cpp:49
void setClipboard(const QString &str)
Definition: guiutil.cpp:937
CFeeRate minRelayTxFee
Definition: validation.cpp:94
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE
Largest (in bytes) free transaction we&#39;re willing to create.
Definition: wallet.h:74
QString labelForAddress(const QString &address) const
CAmount nMinimumTotalFee
Minimum absolute fee (not per kilobyte)
Definition: coincontrol.h:22
uint256 uint256S(const char *str)
Definition: uint256.h:140
CAmount GetFeePerK() const
Definition: amount.h:47
void sortView(int, Qt::SortOrder)
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool &pool)
Definition: wallet.cpp:3596
void listLockedCoins(std::vector< COutPoint > &vOutpts)
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string.
OptionsModel * getOptionsModel()
bool getPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
WalletModel * model
void setModel(WalletModel *model)
void buttonBoxClicked(QAbstractButton *)
CoinControlTreeWidget * treeWidget
bool isSpent(const COutPoint &outpoint) const
bool isLockedCoin(uint256 hash, unsigned int n) const
std::vector< CTxOut > vout
Definition: transaction.h:307
void UnSelectAll()
Definition: coincontrol.h:60
CPrivateSendClient privateSendClient
QPushButton * pushButtonToggleLock
static bool fSubtractFeeFromAmount
QPushButton * pushButtonSelectAll
void lockCoin(COutPoint &output)
bool IsDust(const CFeeRate &minRelayTxFee) const
Definition: transaction.h:185
CTxMemPool mempool
int GetOutpointPrivateSendRounds(const COutPoint &outpoint) const
Definition: wallet.cpp:1321
void UnSelect(const COutPoint &output)
Definition: coincontrol.h:55
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:169
QString getThemeName()
Definition: guiutil.cpp:902
CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent=0)
std::string GetHex() const
Definition: uint256.cpp:21
static CCoinControl * coinControl
Qt::SortOrder sortOrder
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE)
static QString removeSpaces(QString text)
Definition: bitcoinunits.h:116
QTreeWidgetItem * contextMenuItem
Definition: pubkey.h:37
QRadioButton * radioTreeMode
static CAmount GetRequiredFee(unsigned int nTxBytes)
Definition: wallet.cpp:3591
int getDisplayUnit()
Definition: optionsmodel.h:73
QAction * copyTransactionHashAction
void setupUi(QDialog *CoinControlDialog)
AddressTableModel * getAddressTableModel()
#define PAIRTYPE(t1, t2)
bool fUsePrivateSend
Definition: coincontrol.h:15
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
Definition: transaction.h:169
QString strPad(QString, int, QString)
void getOutputs(const std::vector< COutPoint > &vOutpoints, std::vector< COutput > &vOutputs)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:87
void listCoins(std::map< QString, std::vector< COutput > > &mapCoins) const