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