Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
coincontroldialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2013 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "coincontroldialog.h"
6 #include "ui_coincontroldialog.h"
7 
8 #include "addresstablemodel.h"
9 #include "bitcoinunits.h"
10 #include "guiutil.h"
11 #include "init.h"
12 #include "optionsmodel.h"
13 #include "walletmodel.h"
14 
15 #include "coincontrol.h"
16 #include "main.h"
17 #include "wallet.h"
18 
19 #include <QApplication>
20 #include <QCheckBox>
21 #include <QCursor>
22 #include <QDialogButtonBox>
23 #include <QFlags>
24 #include <QIcon>
25 #include <QString>
26 #include <QTreeWidget>
27 #include <QTreeWidgetItem>
28 
29 using namespace std;
30 QList<qint64> CoinControlDialog::payAmounts;
32 
34  QDialog(parent),
35  ui(new Ui::CoinControlDialog),
36  model(0)
37 {
38  ui->setupUi(this);
39 
40  // context menu actions
41  QAction *copyAddressAction = new QAction(tr("Copy address"), this);
42  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
43  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
44  copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this
45  lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this
46  unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
47 
48  // context menu
49  contextMenu = new QMenu();
50  contextMenu->addAction(copyAddressAction);
51  contextMenu->addAction(copyLabelAction);
52  contextMenu->addAction(copyAmountAction);
54  contextMenu->addSeparator();
55  contextMenu->addAction(lockAction);
56  contextMenu->addAction(unlockAction);
57 
58  // context menu signals
59  connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
60  connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
61  connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
62  connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
63  connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash()));
64  connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin()));
65  connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin()));
66 
67  // clipboard actions
68  QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
69  QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
70  QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
71  QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
72  QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
73  QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
74  QAction *clipboardLowOutputAction = new QAction(tr("Copy low output"), this);
75  QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
76 
77  connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity()));
78  connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount()));
79  connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
80  connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
81  connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
82  connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority()));
83  connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
84  connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
85 
86  ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
87  ui->labelCoinControlAmount->addAction(clipboardAmountAction);
88  ui->labelCoinControlFee->addAction(clipboardFeeAction);
89  ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
90  ui->labelCoinControlBytes->addAction(clipboardBytesAction);
91  ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
92  ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
93  ui->labelCoinControlChange->addAction(clipboardChangeAction);
94 
95  // toggle tree/list mode
96  connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool)));
97  connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool)));
98 
99  // click on checkbox
100  connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int)));
101 
102  // click on header
103 #if QT_VERSION < 0x050000
104  ui->treeWidget->header()->setClickable(true);
105 #else
106  ui->treeWidget->header()->setSectionsClickable(true);
107 #endif
108  connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int)));
109 
110  // ok button
111  connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*)));
112 
113  // (un)select all
114  connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
115 
116  ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
117  ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
118  ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
119  ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290);
120  ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
121  ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
122  ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
123  ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it
124  ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it
125  ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but dont show it
126  ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but dont show it
127  ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but dont show it
128 
129  // default view is sorted by amount desc
130  sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder);
131 }
132 
134 {
135  delete ui;
136 }
137 
139 {
140  this->model = model;
141 
142  if(model && model->getOptionsModel() && model->getAddressTableModel())
143  {
144  updateView();
146  CoinControlDialog::updateLabels(model, this);
147  }
148 }
149 
150 // helper function str_pad
151 QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding)
152 {
153  while (s.length() < nPadLength)
154  s = sPadding + s;
155 
156  return s;
157 }
158 
159 // ok button
160 void CoinControlDialog::buttonBoxClicked(QAbstractButton* button)
161 {
162  if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
163  done(QDialog::Accepted); // closes the dialog
164 }
165 
166 // (un)select all
168 {
169  Qt::CheckState state = Qt::Checked;
170  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
171  {
172  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked)
173  {
174  state = Qt::Unchecked;
175  break;
176  }
177  }
178  ui->treeWidget->setEnabled(false);
179  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
180  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state)
181  ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state);
182  ui->treeWidget->setEnabled(true);
183  if (state == Qt::Unchecked)
184  coinControl->UnSelectAll(); // just to be sure
186 }
187 
188 // context menu
189 void CoinControlDialog::showMenu(const QPoint &point)
190 {
191  QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
192  if(item)
193  {
194  contextMenuItem = item;
195 
196  // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu
197  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)
198  {
199  copyTransactionHashAction->setEnabled(true);
200  if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()))
201  {
202  lockAction->setEnabled(false);
203  unlockAction->setEnabled(true);
204  }
205  else
206  {
207  lockAction->setEnabled(true);
208  unlockAction->setEnabled(false);
209  }
210  }
211  else // this means click on parent node in tree mode -> disable all
212  {
213  copyTransactionHashAction->setEnabled(false);
214  lockAction->setEnabled(false);
215  unlockAction->setEnabled(false);
216  }
217 
218  // show context menu
219  contextMenu->exec(QCursor::pos());
220  }
221 }
222 
223 // context menu action: copy amount
225 {
227 }
228 
229 // context menu action: copy label
231 {
232  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent())
234  else
236 }
237 
238 // context menu action: copy address
240 {
241  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent())
243  else
245 }
246 
247 // context menu action: copy transaction id
249 {
251 }
252 
253 // context menu action: lock coin
255 {
256  if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
257  contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
258 
259  COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
260  model->lockCoin(outpt);
261  contextMenuItem->setDisabled(true);
262  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
264 }
265 
266 // context menu action: unlock coin
268 {
269  COutPoint outpt(uint256(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
270  model->unlockCoin(outpt);
271  contextMenuItem->setDisabled(false);
272  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
274 }
275 
276 // copy label "Quantity" to clipboard
278 {
280 }
281 
282 // copy label "Amount" to clipboard
284 {
285  GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" ")));
286 }
287 
288 // copy label "Fee" to clipboard
290 {
291  GUIUtil::setClipboard(ui->labelCoinControlFee->text().left(ui->labelCoinControlFee->text().indexOf(" ")));
292 }
293 
294 // copy label "After fee" to clipboard
296 {
297  GUIUtil::setClipboard(ui->labelCoinControlAfterFee->text().left(ui->labelCoinControlAfterFee->text().indexOf(" ")));
298 }
299 
300 // copy label "Bytes" to clipboard
302 {
304 }
305 
306 // copy label "Priority" to clipboard
308 {
310 }
311 
312 // copy label "Low output" to clipboard
314 {
316 }
317 
318 // copy label "Change" to clipboard
320 {
321  GUIUtil::setClipboard(ui->labelCoinControlChange->text().left(ui->labelCoinControlChange->text().indexOf(" ")));
322 }
323 
324 // treeview: sort
325 void CoinControlDialog::sortView(int column, Qt::SortOrder order)
326 {
327  sortColumn = column;
328  sortOrder = order;
329  ui->treeWidget->sortItems(column, order);
330  ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
331 }
332 
333 // treeview: clicked on header
335 {
336  if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
337  {
338  ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder);
339  }
340  else
341  {
342  logicalIndex = getMappedColumn(logicalIndex, false);
343 
344  if (sortColumn == logicalIndex)
345  sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
346  else
347  {
348  sortColumn = logicalIndex;
349  sortOrder = ((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) ? Qt::AscendingOrder : Qt::DescendingOrder); // if label or address then default => asc, else default => desc
350  }
351 
353  }
354 }
355 
356 // toggle tree mode
358 {
359  if (checked && model)
360  updateView();
361 }
362 
363 // toggle list mode
365 {
366  if (checked && model)
367  updateView();
368 }
369 
370 // checkbox clicked by user
371 void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
372 {
373  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)
374  {
375  COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
376 
377  if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
378  coinControl->UnSelect(outpt);
379  else if (item->isDisabled()) // locked (this happens if "check all" through parent node)
380  item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
381  else
382  coinControl->Select(outpt);
383 
384  // selection changed -> update labels
385  if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all
387  }
388 
389  // todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node
390  // including all childs are partially selected. But the parent node should be fully selected
391  // as well as the childs. Childs should never be partially selected in the first place.
392  // Please remove this ugly fix, once the bug is solved upstream.
393 #if QT_VERSION >= 0x050000
394  else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
395  {
396  if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
397  item->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
398  }
399 #endif
400 }
401 
402 // return human readable label for priority number
403 QString CoinControlDialog::getPriorityLabel(double dPriority)
404 {
405  if (AllowFree(dPriority)) // at least medium
406  {
407  if (AllowFree(dPriority / 1000000)) return tr("highest");
408  else if (AllowFree(dPriority / 100000)) return tr("higher");
409  else if (AllowFree(dPriority / 10000)) return tr("high");
410  else if (AllowFree(dPriority / 1000)) return tr("medium-high");
411  else return tr("medium");
412  }
413  else
414  {
415  if (AllowFree(dPriority * 10)) return tr("low-medium");
416  else if (AllowFree(dPriority * 100)) return tr("low");
417  else if (AllowFree(dPriority * 1000)) return tr("lower");
418  else return tr("lowest");
419  }
420 }
421 
422 // shows count of locked unspent outputs
424 {
425  vector<COutPoint> vOutpts;
426  model->listLockedCoins(vOutpts);
427  if (vOutpts.size() > 0)
428  {
429  ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
430  ui->labelLocked->setVisible(true);
431  }
432  else ui->labelLocked->setVisible(false);
433 }
434 
436 {
437  if (!model)
438  return;
439 
440  // nPayAmount
441  qint64 nPayAmount = 0;
442  bool fLowOutput = false;
443  bool fDust = false;
444  CTransaction txDummy;
445  foreach(const qint64 &amount, CoinControlDialog::payAmounts)
446  {
447  nPayAmount += amount;
448 
449  if (amount > 0)
450  {
451  if (amount < CENT)
452  fLowOutput = true;
453 
454  CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0));
455  txDummy.vout.push_back(txout);
457  fDust = true;
458  }
459  }
460 
461  QString sPriorityLabel = tr("none");
462  int64_t nAmount = 0;
463  int64_t nPayFee = 0;
464  int64_t nAfterFee = 0;
465  int64_t nChange = 0;
466  unsigned int nBytes = 0;
467  unsigned int nBytesInputs = 0;
468  double dPriority = 0;
469  double dPriorityInputs = 0;
470  unsigned int nQuantity = 0;
471  int nQuantityUncompressed = 0;
472 
473  vector<COutPoint> vCoinControl;
474  vector<COutput> vOutputs;
475  coinControl->ListSelected(vCoinControl);
476  model->getOutputs(vCoinControl, vOutputs);
477 
478  BOOST_FOREACH(const COutput& out, vOutputs)
479  {
480  // unselect already spent, very unlikely scenario, this could happen
481  // when selected are spent elsewhere, like rpc or another computer
482  uint256 txhash = out.tx->GetHash();
483  COutPoint outpt(txhash, out.i);
484  if (model->isSpent(outpt))
485  {
486  coinControl->UnSelect(outpt);
487  continue;
488  }
489 
490  // Quantity
491  nQuantity++;
492 
493  // Amount
494  nAmount += out.tx->vout[out.i].nValue;
495 
496  // Priority
497  dPriorityInputs += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
498 
499  // Bytes
500  CTxDestination address;
501  if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
502  {
503  CPubKey pubkey;
504  CKeyID *keyid = boost::get<CKeyID>(&address);
505  if (keyid && model->getPubKey(*keyid, pubkey))
506  {
507  nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
508  if (!pubkey.IsCompressed())
509  nQuantityUncompressed++;
510  }
511  else
512  nBytesInputs += 148; // in all error cases, simply assume 148 here
513  }
514  else nBytesInputs += 148;
515  }
516 
517  // calculation
518  if (nQuantity > 0)
519  {
520  // Bytes
521  nBytes = nBytesInputs + ((CoinControlDialog::payAmounts.size() > 0 ? CoinControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here
522 
523  // Priority
524  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)
525  sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority);
526 
527  // Fee
528  int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
529 
530  // Min Fee
531  int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND);
532 
533  nPayFee = max(nFee, nMinFee);
534 
535  if (nPayAmount > 0)
536  {
537  nChange = nAmount - nPayFee - nPayAmount;
538 
539  // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee
540  if (nPayFee < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT)
541  {
542  if (nChange < CTransaction::nMinTxFee) // change < 0.0001 => simply move all change to fees
543  {
544  nPayFee += nChange;
545  nChange = 0;
546  }
547  else
548  {
549  nChange = nChange + nPayFee - CTransaction::nMinTxFee;
550  nPayFee = CTransaction::nMinTxFee;
551  }
552  }
553 
554  // Never create dust outputs; if we would, just add the dust to the fee.
555  if (nChange > 0 && nChange < CENT)
556  {
557  CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0));
559  {
560  nPayFee += nChange;
561  nChange = 0;
562  }
563  }
564 
565  if (nChange == 0)
566  nBytes -= 34;
567  }
568 
569  // after fee
570  nAfterFee = nAmount - nPayFee;
571  if (nAfterFee < 0)
572  nAfterFee = 0;
573  }
574 
575  // actually update labels
576  int nDisplayUnit = BitcoinUnits::BTC;
577  if (model && model->getOptionsModel())
578  nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
579 
580  QLabel *l1 = dialog->findChild<QLabel *>("labelCoinControlQuantity");
581  QLabel *l2 = dialog->findChild<QLabel *>("labelCoinControlAmount");
582  QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
583  QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
584  QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
585  QLabel *l6 = dialog->findChild<QLabel *>("labelCoinControlPriority");
586  QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
587  QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
588 
589  // enable/disable "low output" and "change"
590  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setEnabled(nPayAmount > 0);
591  dialog->findChild<QLabel *>("labelCoinControlLowOutput") ->setEnabled(nPayAmount > 0);
592  dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setEnabled(nPayAmount > 0);
593  dialog->findChild<QLabel *>("labelCoinControlChange") ->setEnabled(nPayAmount > 0);
594 
595  // stats
596  l1->setText(QString::number(nQuantity)); // Quantity
597  l2->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAmount)); // Amount
598  l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
599  l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
600  l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes
601  l6->setText(sPriorityLabel); // Priority
602  l7->setText((fLowOutput ? (fDust ? tr("Dust") : tr("yes")) : tr("no"))); // Low Output / Dust
603  l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
604 
605  // turn labels "red"
606  l5->setStyleSheet((nBytes >= 1000) ? "color:red;" : ""); // Bytes >= 1000
607  l6->setStyleSheet((dPriority > 0 && !AllowFree(dPriority)) ? "color:red;" : ""); // Priority < "medium"
608  l7->setStyleSheet((fLowOutput) ? "color:red;" : ""); // Low Output = "yes"
609  l8->setStyleSheet((nChange > 0 && nChange < CENT) ? "color:red;" : ""); // Change < 0.01BTC
610 
611  // tool tips
612  QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />";
613  toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
614  toolTip1 += tr("Can vary +/- 1 byte per input.");
615 
616  QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
617  toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\".") + "<br /><br />";
618  toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
619 
620  QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
621  toolTip3 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />";
622  toolTip3 += tr("Amounts below 0.546 times the minimum relay fee are shown as dust.");
623 
624  QString toolTip4 = tr("This label turns red, if the change is smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CENT)) + "<br /><br />";
625  toolTip4 += tr("This means a fee of at least %1 is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee));
626 
627  l5->setToolTip(toolTip1);
628  l6->setToolTip(toolTip2);
629  l7->setToolTip(toolTip3);
630  l8->setToolTip(toolTip4);
631  dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
632  dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
633  dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
634  dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
635 
636  // Insufficient funds
637  QLabel *label = dialog->findChild<QLabel *>("labelCoinControlInsuffFunds");
638  if (label)
639  label->setVisible(nChange < 0);
640 }
641 
643 {
645  return;
646 
647  bool treeMode = ui->radioTreeMode->isChecked();
648 
649  ui->treeWidget->clear();
650  ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
651  ui->treeWidget->setAlternatingRowColors(!treeMode);
652  QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
653  QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
654 
655  int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
656 
657  map<QString, vector<COutput> > mapCoins;
658  model->listCoins(mapCoins);
659 
660  BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins)
661  {
662  QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
663  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
664  QString sWalletAddress = coins.first;
665  QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
666  if (sWalletLabel.isEmpty())
667  sWalletLabel = tr("(no label)");
668 
669  if (treeMode)
670  {
671  // wallet address
672  ui->treeWidget->addTopLevelItem(itemWalletAddress);
673 
674  itemWalletAddress->setFlags(flgTristate);
675  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
676 
677  // label
678  itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel);
679 
680  // address
681  itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress);
682  }
683 
684  int64_t nSum = 0;
685  double dPrioritySum = 0;
686  int nChildren = 0;
687  int nInputSum = 0;
688  BOOST_FOREACH(const COutput& out, coins.second)
689  {
690  int nInputSize = 0;
691  nSum += out.tx->vout[out.i].nValue;
692  nChildren++;
693 
694  QTreeWidgetItem *itemOutput;
695  if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress);
696  else itemOutput = new QTreeWidgetItem(ui->treeWidget);
697  itemOutput->setFlags(flgCheckbox);
698  itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked);
699 
700  // address
701  CTxDestination outputAddress;
702  QString sAddress = "";
703  if(ExtractDestination(out.tx->vout[out.i].scriptPubKey, outputAddress))
704  {
705  sAddress = CBitcoinAddress(outputAddress).ToString().c_str();
706 
707  // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
708  if (!treeMode || (!(sAddress == sWalletAddress)))
709  itemOutput->setText(COLUMN_ADDRESS, sAddress);
710 
711  CPubKey pubkey;
712  CKeyID *keyid = boost::get<CKeyID>(&outputAddress);
713  if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed())
714  nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes)
715  }
716 
717  // label
718  if (!(sAddress == sWalletAddress)) // change
719  {
720  // tooltip from where the change comes from
721  itemOutput->setToolTip(COLUMN_LABEL, tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress));
722  itemOutput->setText(COLUMN_LABEL, tr("(change)"));
723  }
724  else if (!treeMode)
725  {
726  QString sLabel = model->getAddressTableModel()->labelForAddress(sAddress);
727  if (sLabel.isEmpty())
728  sLabel = tr("(no label)");
729  itemOutput->setText(COLUMN_LABEL, sLabel);
730  }
731 
732  // amount
733  itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue));
734  itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly
735 
736  // date
737  itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
738  itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " "));
739 
740  // confirmations
741  itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
742 
743  // priority
744  double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
745  itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority));
746  itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
747  dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
748  nInputSum += nInputSize;
749 
750  // transaction hash
751  uint256 txhash = out.tx->GetHash();
752  itemOutput->setText(COLUMN_TXHASH, txhash.GetHex().c_str());
753 
754  // vout index
755  itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
756 
757  // disable locked coins
758  if (model->isLockedCoin(txhash, out.i))
759  {
760  COutPoint outpt(txhash, out.i);
761  coinControl->UnSelect(outpt); // just to be sure
762  itemOutput->setDisabled(true);
763  itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed"));
764  }
765 
766  // set checkbox
767  if (coinControl->IsSelected(txhash, out.i))
768  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
769  }
770 
771  // amount
772  if (treeMode)
773  {
774  dPrioritySum = dPrioritySum / (nInputSum + 78);
775  itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
776  itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
777  itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
778  itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum));
779  itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
780  }
781  }
782 
783  // expand all partially selected
784  if (treeMode)
785  {
786  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
787  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
788  ui->treeWidget->topLevelItem(i)->setExpanded(true);
789  }
790 
791  // sort view
793  ui->treeWidget->setEnabled(true);
794 }
void viewItemChanged(QTreeWidgetItem *, int)
bool IsDust(int64_t nMinRelayTxFee) const
Definition: core.h:151
void getOutputs(const std::vector< COutPoint > &vOutpoints, std::vector< COutput > &vOutputs)
int i
Definition: wallet.h:713
void lockCoin(COutPoint &output)
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false)
Format as string (with unit)
static CCoinControl * coinControl
int getMappedColumn(int column, bool fVisibleColumn=true)
#define PAIRTYPE(t1, t2)
Definition: util.h:48
QRadioButton * radioTreeMode
void setupUi(QDialog *CoinControlDialog)
bool isLockedCoin(uint256 hash, unsigned int n) const
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:73
uint256 GetHash() const
Definition: core.cpp:75
bool IsSelected(const uint256 &hash, unsigned int n) const
Definition: coincontrol.h:32
int64_t GetMinFee(const CTransaction &tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode)
Definition: main.cpp:817
STL namespace.
base58-encoded Bitcoin addresses.
Definition: base58.h:101
bool AllowFree(double dPriority)
Definition: main.h:299
AddressTableModel * getAddressTableModel()
static int64_t nMinTxFee
Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) ...
Definition: core.h:186
Coin Control Features.
Definition: coincontrol.h:11
QPushButton * pushButtonSelectAll
QAction * copyTransactionHashAction
int nDepth
Definition: wallet.h:714
int64_t nTransactionFee
Definition: wallet.cpp:19
bool isSpent(const COutPoint &outpoint) const
Ui::CoinControlDialog * ui
void setClipboard(const QString &str)
Definition: guiutil.cpp:755
std::vector< CTxOut > vout
Definition: core.h:191
CoinControlTreeWidget * treeWidget
An encapsulated public key.
Definition: key.h:42
bool getPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
static QString getPriorityLabel(double)
CoinControlDialog(QWidget *parent=0)
std::string ToString() const
Definition: base58.cpp:174
static void updateLabels(WalletModel *, QDialog *)
An output of a transaction.
Definition: core.h:119
int getDisplayUnit()
Definition: optionsmodel.h:58
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: core.h:22
std::string GetHex() const
Definition: uint256.h:297
void UnSelectAll()
Definition: coincontrol.h:48
int64_t GetTxTime() const
Definition: wallet.cpp:705
bool IsCompressed() const
Definition: key.h:151
256-bit unsigned integer
Definition: uint256.h:531
void setModel(WalletModel *model)
QTreeWidgetItem * contextMenuItem
QString labelForAddress(const QString &address) const
void listLockedCoins(std::vector< COutPoint > &vOutpts)
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:401
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:96
void Select(COutPoint &output)
Definition: coincontrol.h:38
void unlockCoin(COutPoint &output)
A reference to a CKey: the Hash160 of its serialized public key.
Definition: key.h:26
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Definition: script.cpp:1493
const CWalletTx * tx
Definition: wallet.h:712
void sortView(int, Qt::SortOrder)
static QList< qint64 > payAmounts
Qt::SortOrder sortOrder
static int64_t nMinRelayTxFee
Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) ...
Definition: core.h:187
static const int64_t CENT
Definition: util.h:39
QString strPad(QString, int, QString)
void ListSelected(std::vector< COutPoint > &vOutpoints)
Definition: coincontrol.h:53
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: script.h:218
void buttonBoxClicked(QAbstractButton *)
void UnSelect(COutPoint &output)
Definition: coincontrol.h:43
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: core.h:183
QRadioButton * radioListMode
WalletModel * model
void showMenu(const QPoint &)
QDialogButtonBox * buttonBox
void listCoins(std::map< QString, std::vector< COutput > > &mapCoins) const
static QString format(int unit, qint64 amount, bool plussign=false)
Format as string.
Definition: main.h:261
OptionsModel * getOptionsModel()