Raven Core  3.0.0
P2P Digital Currency
assetcontroldialog.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Copyright (c) 2017-2019 The Raven 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 "assetcontroldialog.h"
7 #include "ui_assetcontroldialog.h"
8 
9 #include "addresstablemodel.h"
10 #include "ravenunits.h"
11 #include "guiutil.h"
12 #include "optionsmodel.h"
13 #include "platformstyle.h"
14 #include "txmempool.h"
15 #include "walletmodel.h"
16 
17 #include "wallet/coincontrol.h"
18 #include "init.h"
19 #include "policy/fees.h"
20 #include "policy/policy.h"
21 #include "validation.h" // For mempool
22 #include "wallet/fees.h"
23 #include "wallet/wallet.h"
24 
25 #include <QApplication>
26 #include <QCheckBox>
27 #include <QCursor>
28 #include <QDialogButtonBox>
29 #include <QFlags>
30 #include <QIcon>
31 #include <QSettings>
32 #include <QString>
33 #include <QTreeWidget>
34 #include <QTreeWidgetItem>
35 #include <QStringListModel>
36 #include <QSortFilterProxyModel>
37 #include <QCompleter>
38 #include <QLineEdit>
39 
40 QList<CAmount> AssetControlDialog::payAmounts;
43 
44 bool CAssetControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
45  int column = treeWidget()->sortColumn();
47  return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong();
48  return QTreeWidgetItem::operator<(other);
49 }
50 
51 AssetControlDialog::AssetControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
52  QDialog(parent),
53  ui(new Ui::AssetControlDialog),
54  model(0),
55  platformStyle(_platformStyle)
56 {
57  ui->setupUi(this);
58 
59  // context menu actions
60  QAction *copyAddressAction = new QAction(tr("Copy address"), this);
61  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
62  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
63  copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this
64  lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this
65  unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
66 
67  // context menu
68  contextMenu = new QMenu(this);
69  contextMenu->addAction(copyAddressAction);
70  contextMenu->addAction(copyLabelAction);
71  contextMenu->addAction(copyAmountAction);
73  contextMenu->addSeparator();
74  contextMenu->addAction(lockAction);
75  contextMenu->addAction(unlockAction);
76 
77  // context menu signals
78  connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
79  connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
80  connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
81  connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
82  connect(copyTransactionHashAction, SIGNAL(triggered()), this, SLOT(copyTransactionHash()));
83  connect(lockAction, SIGNAL(triggered()), this, SLOT(lockCoin()));
84  connect(unlockAction, SIGNAL(triggered()), this, SLOT(unlockCoin()));
85 
86  // clipboard actions
87  QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
88  QAction *clipboardAmountAction = new QAction(tr("Copy amount"), this);
89  QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
90  QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
91  QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
92  QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
93  QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
94 
95  connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(clipboardQuantity()));
96  connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(clipboardAmount()));
97  connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
98  connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
99  connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
100  connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
101  connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
102 
103  ui->labelAssetControlQuantity->addAction(clipboardQuantityAction);
104  ui->labelAssetControlAmount->addAction(clipboardAmountAction);
105  ui->labelAssetControlFee->addAction(clipboardFeeAction);
106  ui->labelAssetControlAfterFee->addAction(clipboardAfterFeeAction);
107  ui->labelAssetControlBytes->addAction(clipboardBytesAction);
108  ui->labelAssetControlLowOutput->addAction(clipboardLowOutputAction);
109  ui->labelAssetControlChange->addAction(clipboardChangeAction);
110 
111  // toggle tree/list mode
112  connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool)));
113  connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool)));
114 
115  // click on checkbox
116  connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int)));
117 
118  // click on header
119 #if QT_VERSION < 0x050000
120  ui->treeWidget->header()->setClickable(true);
121 #else
122  ui->treeWidget->header()->setSectionsClickable(true);
123 #endif
124  connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int)));
125 
126  // ok button
127  connect(ui->buttonBox, SIGNAL(clicked( QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*)));
128 
129  // (un)select all
130  connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
131 
132  // change coin control first column label due Qt4 bug.
133  // see https://github.com/RavenProject/Ravencoin/issues/5716
134  ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
135 
136  ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
137  ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
138  ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
139  ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320);
140  ui->treeWidget->setColumnWidth(COLUMN_DATE, 130);
141  ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
142  ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
143  ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
144 
145  // default view is sorted by amount desc
146  sortView(COLUMN_AMOUNT, 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  // Add the assets into the dropdown menu
156  connect(ui->viewAdministrator, SIGNAL(clicked()), this, SLOT(viewAdministratorClicked()));
157  connect(ui->assetList, SIGNAL(currentIndexChanged(QString)), this, SLOT(onAssetSelected(QString)));
158 
160  stringModel = new QStringListModel;
161 
162  proxy = new QSortFilterProxyModel;
163  proxy->setSourceModel(stringModel);
164  proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
165 
166  ui->assetList->setModel(proxy);
167  ui->assetList->setEditable(true);
168  ui->assetList->lineEdit()->setPlaceholderText("Select an asset");
169 
170  completer = new QCompleter(proxy,this);
171  completer->setCompletionMode(QCompleter::PopupCompletion);
172  completer->setCaseSensitivity(Qt::CaseInsensitive);
173  ui->assetList->setCompleter(completer);
174 }
175 
177 {
178  QSettings settings;
179  settings.setValue("nCoinControlMode", ui->radioListMode->isChecked());
180  settings.setValue("nCoinControlSortColumn", sortColumn);
181  settings.setValue("nCoinControlSortOrder", (int)sortOrder);
182 
183  delete ui;
184 }
185 
187 {
188  this->model = _model;
189 
190  if(_model && _model->getOptionsModel() && _model->getAddressTableModel())
191  {
192  updateView();
193  updateAssetList(true);
195  AssetControlDialog::updateLabels(_model, this);
196  }
197 }
198 
199 // ok button
200 void AssetControlDialog::buttonBoxClicked(QAbstractButton* button)
201 {
202  if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
203  if (AssetControlDialog::assetControl->HasAssetSelected())
204  AssetControlDialog::assetControl->strAssetSelected = ui->assetList->currentText().toStdString();
205  done(QDialog::Accepted); // closes the dialog
206  }
207 }
208 
209 // (un)select all
211 {
212  Qt::CheckState state = Qt::Checked;
213  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
214  {
215  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked)
216  {
217  state = Qt::Unchecked;
218  break;
219  }
220  }
221  ui->treeWidget->setEnabled(false);
222  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
223  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state)
224  ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state);
225  ui->treeWidget->setEnabled(true);
226  if (state == Qt::Unchecked)
227  assetControl->UnSelectAll(); // just to be sure
229 }
230 
231 // context menu
232 void AssetControlDialog::showMenu(const QPoint &point)
233 {
234  QTreeWidgetItem *item = ui->treeWidget->itemAt(point);
235  if(item)
236  {
237  contextMenuItem = item;
238 
239  // disable some items (like Copy Transaction ID, lock, unlock) for tree roots in context menu
240  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)
241  {
242  copyTransactionHashAction->setEnabled(true);
243  if (model->isLockedCoin(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()))
244  {
245  lockAction->setEnabled(false);
246  unlockAction->setEnabled(true);
247  }
248  else
249  {
250  lockAction->setEnabled(true);
251  unlockAction->setEnabled(false);
252  }
253  }
254  else // this means click on parent node in tree mode -> disable all
255  {
256  copyTransactionHashAction->setEnabled(false);
257  lockAction->setEnabled(false);
258  unlockAction->setEnabled(false);
259  }
260 
261  // show context menu
262  contextMenu->exec(QCursor::pos());
263  }
264 }
265 
266 // context menu action: copy amount
268 {
270 }
271 
272 // context menu action: copy label
274 {
275  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_LABEL).length() == 0 && contextMenuItem->parent())
277  else
279 }
280 
281 // context menu action: copy address
283 {
284  if (ui->radioTreeMode->isChecked() && contextMenuItem->text(COLUMN_ADDRESS).length() == 0 && contextMenuItem->parent())
286  else
288 }
289 
290 // context menu action: copy transaction id
292 {
294 }
295 
296 // context menu action: lock coin
298 {
299  if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
300  contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
301 
302  COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
303  model->lockCoin(outpt);
304  contextMenuItem->setDisabled(true);
305  contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
307 }
308 
309 // context menu action: unlock coin
311 {
312  COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
313  model->unlockCoin(outpt);
314  contextMenuItem->setDisabled(false);
315  contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
317 }
318 
319 // copy label "Quantity" to clipboard
321 {
322  GUIUtil::setClipboard(ui->labelAssetControlQuantity->text());
323 }
324 
325 // copy label "Amount" to clipboard
327 {
328  GUIUtil::setClipboard(ui->labelAssetControlAmount->text().left(ui->labelAssetControlAmount->text().indexOf(" ")));
329 }
330 
331 // copy label "Fee" to clipboard
333 {
334  GUIUtil::setClipboard(ui->labelAssetControlFee->text().left(ui->labelAssetControlFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
335 }
336 
337 // copy label "After fee" to clipboard
339 {
340  GUIUtil::setClipboard(ui->labelAssetControlAfterFee->text().left(ui->labelAssetControlAfterFee->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
341 }
342 
343 // copy label "Bytes" to clipboard
345 {
346  GUIUtil::setClipboard(ui->labelAssetControlBytes->text().replace(ASYMP_UTF8, ""));
347 }
348 
349 // copy label "Dust" to clipboard
351 {
352  GUIUtil::setClipboard(ui->labelAssetControlLowOutput->text());
353 }
354 
355 // copy label "Change" to clipboard
357 {
358  GUIUtil::setClipboard(ui->labelAssetControlChange->text().left(ui->labelAssetControlChange->text().indexOf(" ")).replace(ASYMP_UTF8, ""));
359 }
360 
361 // treeview: sort
362 void AssetControlDialog::sortView(int column, Qt::SortOrder order)
363 {
364  sortColumn = column;
365  sortOrder = order;
366  ui->treeWidget->sortItems(column, order);
367  ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
368 }
369 
370 // treeview: clicked on header
372 {
373  if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing
374  {
375  ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder);
376  }
377  else
378  {
379  if (sortColumn == logicalIndex)
380  sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder);
381  else
382  {
383  sortColumn = logicalIndex;
384  sortOrder = ((sortColumn == COLUMN_LABEL || sortColumn == COLUMN_ADDRESS) ? Qt::AscendingOrder : Qt::DescendingOrder); // if label or address then default => asc, else default => desc
385  }
386 
388  }
389 }
390 
391 // toggle tree mode
393 {
394  if (checked && model)
395  updateView();
396 }
397 
398 // toggle list mode
400 {
401  if (checked && model)
402  updateView();
403 }
404 
405 // checkbox clicked by user
406 void AssetControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
407 {
408  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)
409  {
410  COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt());
411 
412  if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
413  assetControl->UnSelectAsset(outpt);
414  else if (item->isDisabled()) // locked (this happens if "check all" through parent node)
415  item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
416  else
417  assetControl->SelectAsset(outpt);
418 
419  // selection changed -> update labels
420  if (ui->treeWidget->isEnabled()) // do not update on every click for (un)select all
422  }
423 
424  // TODO: Remove this temporary qt5 fix after Qt5.3 and Qt5.4 are no longer used.
425  // Fixed in Qt5.5 and above: https://bugreports.qt.io/browse/QTBUG-43473
426 #if QT_VERSION >= 0x050000
427  else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
428  {
429  if (item->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked && item->child(0)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
430  item->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
431  }
432 #endif
433 }
434 
435 // shows count of locked unspent outputs
437 {
438  std::vector<COutPoint> vOutpts;
439  model->listLockedCoins(vOutpts);
440  if (vOutpts.size() > 0)
441  {
442  ui->labelLocked->setText(tr("(%1 locked)").arg(vOutpts.size()));
443  ui->labelLocked->setVisible(true);
444  }
445  else ui->labelLocked->setVisible(false);
446 }
447 
449 {
450  if (!model)
451  return;
452 
453  // nPayAmount
454  CAmount nPayAmount = 0;
455  bool fDust = false;
456  CMutableTransaction txDummy;
457  for (const CAmount &amount : AssetControlDialog::payAmounts)
458  {
459  nPayAmount += amount;
460 
461  if (amount > 0)
462  {
463  CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
464  txDummy.vout.push_back(txout);
465  fDust |= IsDust(txout, ::dustRelayFee);
466  }
467  }
468 
469  std::string strAssetName = "";
470  CAmount nAssetAmount = 0;
471  CAmount nAmount = 0;
472  CAmount nPayFee = 0;
473  CAmount nAfterFee = 0;
474  CAmount nChange = 0;
475  unsigned int nBytes = 0;
476  unsigned int nBytesInputs = 0;
477  unsigned int nQuantity = 0;
478  bool fWitness = false;
479 
480  std::vector<COutPoint> vCoinControl;
481  std::vector<COutput> vOutputs;
482  assetControl->ListSelectedAssets(vCoinControl);
483  model->getOutputs(vCoinControl, vOutputs);
484 
485  for (const COutput& out : vOutputs) {
486  // unselect already spent, very unlikely scenario, this could happen
487  // when selected are spent elsewhere, like rpc or another computer
488  uint256 txhash = out.tx->GetHash();
489  COutPoint outpt(txhash, out.i);
490  if (model->isSpent(outpt))
491  {
492  assetControl->UnSelectAsset(outpt);
493  continue;
494  }
495 
496  // Quantity
497  nQuantity++;
498 
499  // Amount
500  CAmount nCoinAmount;
501  GetAssetInfoFromScript(out.tx->tx->vout[out.i].scriptPubKey, strAssetName, nCoinAmount);
502  nAssetAmount += nCoinAmount;
503 
504  // Bytes
505  CTxDestination address;
506  int witnessversion = 0;
507  std::vector<unsigned char> witnessprogram;
508  if (out.tx->tx->vout[out.i].scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram))
509  {
510  nBytesInputs += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
511  fWitness = true;
512  }
513  else if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address))
514  {
515  CPubKey pubkey;
516  CKeyID *keyid = boost::get<CKeyID>(&address);
517  if (keyid && model->getPubKey(*keyid, pubkey))
518  {
519  nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
520  }
521  else
522  nBytesInputs += 148; // in all error cases, simply assume 148 here
523  }
524  else nBytesInputs += 148;
525  }
526 
527  // calculation
528  if (nQuantity > 0)
529  {
530  // Bytes
531  nBytes = nBytesInputs + ((AssetControlDialog::payAmounts.size() > 0 ? AssetControlDialog::payAmounts.size() + 1 : 2) * 34) + 10; // always assume +1 output for change here
532  if (fWitness)
533  {
534  // there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact.
535  // usually, the result will be an overestimate within a couple of satoshis so that the confirmation dialog ends up displaying a slightly smaller fee.
536  // also, the witness stack size value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.
537  nBytes += 2; // account for the serialized marker and flag bytes
538  nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
539  }
540 
541  // 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
543  if (nAmount - nPayAmount == 0)
544  nBytes -= 34;
545 
546  // Fee
547  nPayFee = GetMinimumFee(nBytes, *assetControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
548 
549  if (nPayAmount > 0)
550  {
551  nChange = nAssetAmount - nPayAmount;
552 
553  if (nChange == 0 && !AssetControlDialog::fSubtractFeeFromAmount)
554  nBytes -= 34;
555  }
556 
557  // after fee
558  nAfterFee = std::max<CAmount>(nPayFee, 0);
559  }
560 
561  // actually update labels
562  int nDisplayUnit = RavenUnits::RVN;
563  if (model && model->getOptionsModel())
564  nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
565 
566  QLabel *l1 = dialog->findChild<QLabel *>("labelAssetControlQuantity");
567  QLabel *l2 = dialog->findChild<QLabel *>("labelAssetControlAmount");
568  QLabel *l3 = dialog->findChild<QLabel *>("labelAssetControlFee");
569  QLabel *l4 = dialog->findChild<QLabel *>("labelAssetControlAfterFee");
570  QLabel *l5 = dialog->findChild<QLabel *>("labelAssetControlBytes");
571  QLabel *l7 = dialog->findChild<QLabel *>("labelAssetControlLowOutput");
572  QLabel *l8 = dialog->findChild<QLabel *>("labelAssetControlChange");
573 
574  // enable/disable "dust" and "change"
575  dialog->findChild<QLabel *>("labelAssetControlLowOutputText")->setEnabled(nPayAmount > 0);
576  dialog->findChild<QLabel *>("labelAssetControlLowOutput") ->setEnabled(nPayAmount > 0);
577  dialog->findChild<QLabel *>("labelAssetControlChangeText") ->setEnabled(nPayAmount > 0);
578  dialog->findChild<QLabel *>("labelAssetControlChange") ->setEnabled(nPayAmount > 0);
579 
580  // stats
581  l1->setText(QString::number(nQuantity)); // Quantity
582  l2->setText(RavenUnits::formatWithCustomName(QString::fromStdString(strAssetName), nAssetAmount)); // Amount
583  l3->setText(RavenUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
584  l4->setText(RavenUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
585  l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
586  l7->setText(fDust ? tr("yes") : tr("no")); // Dust
587  l8->setText(RavenUnits::formatWithCustomName(QString::fromStdString(strAssetName), nChange)); // Change
588  if (nPayFee > 0)
589  {
590  l3->setText(ASYMP_UTF8 + l3->text());
591  l4->setText(ASYMP_UTF8 + l4->text());
592  }
593 
594  // turn label red when dust
595  l7->setStyleSheet((fDust) ? "color:red;" : "");
596 
597  // tool tips
598  QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
599 
600  // how many satoshis the estimated fee can vary per byte we guess wrong
601  double dFeeVary = (nBytes != 0) ? (double)nPayFee / nBytes : 0;
602 
603  QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
604 
605  l3->setToolTip(toolTip4);
606  l4->setToolTip(toolTip4);
607  l7->setToolTip(toolTipDust);
608  l8->setToolTip(toolTip4);
609  dialog->findChild<QLabel *>("labelAssetControlFeeText") ->setToolTip(l3->toolTip());
610  dialog->findChild<QLabel *>("labelAssetControlAfterFeeText") ->setToolTip(l4->toolTip());
611  dialog->findChild<QLabel *>("labelAssetControlBytesText") ->setToolTip(l5->toolTip());
612  dialog->findChild<QLabel *>("labelAssetControlLowOutputText")->setToolTip(l7->toolTip());
613  dialog->findChild<QLabel *>("labelAssetControlChangeText") ->setToolTip(l8->toolTip());
614 
615  // Insufficient funds
616  QLabel *label = dialog->findChild<QLabel *>("labelAssetControlInsuffFunds");
617  if (label)
618  label->setVisible(nChange < 0);
619 }
620 
622 {
624  return;
625 
626  bool treeMode = ui->radioTreeMode->isChecked();
627 
628  ui->treeWidget->clear();
629  ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
630  ui->treeWidget->setAlternatingRowColors(!treeMode);
631  QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
632  QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
633 
634  int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
635 
636  std::map<QString, std::map<QString, std::vector<COutput> > > mapCoins;
637  model->listAssets(mapCoins);
638 
639  QString assetToDisplay = ui->assetList->currentText();
640 
641  // Double check to make sure that the asset selected has coins in the map
642  if (!mapCoins.count(assetToDisplay))
643  return;
644 
645  // For now we only support for one assets coins being shown at a time
646  // So we only loop through coins for that specific asset
647  auto mapAssetCoins = mapCoins.at(assetToDisplay);
648 
649  for (const std::pair<QString, std::vector<COutput>> &coins : mapAssetCoins) {
650  CAssetControlWidgetItem *itemWalletAddress = new CAssetControlWidgetItem();
651  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
652  QString sWalletAddress = coins.first;
653  QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress);
654  if (sWalletLabel.isEmpty())
655  sWalletLabel = tr("(no label)");
656 
657  if (treeMode) {
658  // wallet address
659  ui->treeWidget->addTopLevelItem(itemWalletAddress);
660 
661  itemWalletAddress->setFlags(flgTristate);
662  itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
663 
664  // label
665  itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel);
666 
667  // address
668  itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress);
669 
670  // asset name
671  itemWalletAddress->setText(COLUMN_ASSET_NAME, assetToDisplay);
672  }
673 
674  CAmount nSum = 0;
675  int nChildren = 0;
676  for (const COutput &out : coins.second) {
677  std::string strAssetName;
678  CAmount nAmount;
679  if (!GetAssetInfoFromScript(out.tx->tx->vout[out.i].scriptPubKey, strAssetName, nAmount))
680  continue;
681 
682  if (strAssetName != assetToDisplay.toStdString())
683  continue;
684 
685  nSum += nAmount;
686  nChildren++;
687 
688  CAssetControlWidgetItem *itemOutput;
689  if (treeMode) itemOutput = new CAssetControlWidgetItem(itemWalletAddress);
690  else itemOutput = new CAssetControlWidgetItem(ui->treeWidget);
691  itemOutput->setFlags(flgCheckbox);
692  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
693 
694  // address
695  CTxDestination outputAddress;
696  QString sAddress = "";
697  if (ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress)) {
698  sAddress = QString::fromStdString(EncodeDestination(outputAddress));
699 
700  // if listMode or change => show raven address. In tree mode, address is not shown again for direct wallet address outputs
701  if (!treeMode || (!(sAddress == sWalletAddress))) {
702  itemOutput->setText(COLUMN_ADDRESS, sAddress);
703  // asset name
704  itemOutput->setText(COLUMN_ASSET_NAME, QString::fromStdString(strAssetName));
705  }
706  }
707 
708  // label
709  if (!(sAddress == sWalletAddress)) // change
710  {
711  // tooltip from where the change comes from
712  itemOutput->setToolTip(COLUMN_LABEL,
713  tr("change from %1 (%2)").arg(sWalletLabel).arg(sWalletAddress));
714  itemOutput->setText(COLUMN_LABEL, tr("(change)"));
715  } else if (!treeMode) {
716  QString sLabel = model->getAddressTableModel()->labelForAddress(sAddress);
717  if (sLabel.isEmpty())
718  sLabel = tr("(no label)");
719  itemOutput->setText(COLUMN_LABEL, sLabel);
720  }
721 
722  // amount
723  itemOutput->setText(COLUMN_AMOUNT, RavenUnits::format(nDisplayUnit, nAmount));
724  itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole,
725  QVariant((qlonglong) nAmount)); // padding so that sorting works correctly
726 
727  // date
728  itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime()));
729  itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong) out.tx->GetTxTime()));
730 
731  // confirmations
732  itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth));
733  itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong) out.nDepth));
734 
735  // transaction hash
736  uint256 txhash = out.tx->GetHash();
737  itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
738 
739  // vout index
740  itemOutput->setText(COLUMN_VOUT_INDEX, QString::number(out.i));
741 
742  // disable locked coins
743  if (model->isLockedCoin(txhash, out.i)) {
744  COutPoint outpt(txhash, out.i);
745  assetControl->UnSelectAsset(outpt); // just to be sure
746  itemOutput->setDisabled(true);
747  itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
748  }
749 
750  // set checkbox
751  if (assetControl->IsAssetSelected(COutPoint(txhash, out.i)))
752  itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked);
753  }
754 
755  // amount
756  if (treeMode) {
757  itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
758  itemWalletAddress->setText(COLUMN_AMOUNT, RavenUnits::format(nDisplayUnit, nSum));
759  itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong) nSum));
760  }
761  }
762 
763  // expand all partially selected
764  if (treeMode)
765  {
766  for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
767  if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) == Qt::PartiallyChecked)
768  ui->treeWidget->topLevelItem(i)->setExpanded(true);
769  }
770 
771  // sort view
773  ui->treeWidget->setEnabled(true);
774 }
775 
777 {
780  updateAssetList();
781 }
782 
784 {
786  return;
787 
788  bool showAdministrator = ui->viewAdministrator->isChecked();
789  if (fSetOnStart) {
790  showAdministrator = IsAssetNameAnOwner(assetControl->strAssetSelected);
791  ui->viewAdministrator->setChecked(showAdministrator);
792  }
793  // Get the assets
794  std::vector<std::string> assets;
795  if (showAdministrator)
797  else
798  GetAllMyAssets(model->getWallet(), assets, 0);
799 
800  QStringList list;
801  list << "";
802  for (auto name : assets) {
803  list << QString::fromStdString(name);
804  }
805 
806  stringModel->setStringList(list);
807 
808  int index = ui->assetList->findText(QString::fromStdString(assetControl->strAssetSelected));
809  if (index != -1 ) { // -1 for not found
810  fOnStartUp = fSetOnStart;
811  ui->assetList->setCurrentIndex(index);
812  }
813 
814  updateView();
815 }
816 
818 {
819  if (fOnStartUp) {
820  fOnStartUp = false;
821  } else {
823  }
824 
826  updateView();
827 }
AssetControlDialog(const PlatformStyle *platformStyle, QWidget *parent=0)
bool isLockedCoin(uint256 hash, unsigned int n) const
RVN END.
CTxMemPool mempool
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard, const int nAssetUnit=MIN_ASSET_UNITS - 1)
Format as string.
Definition: ravenunits.cpp:101
void getOutputs(const std::vector< COutPoint > &vOutpoints, std::vector< COutput > &vOutputs)
int i
Definition: wallet.h:532
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:89
void onAssetSelected(QString name)
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:210
void lockCoin(COutPoint &output)
void buttonBoxClicked(QAbstractButton *)
void sortView(int, Qt::SortOrder)
std::string strAssetSelected
RVN START.
Definition: coincontrol.h:38
const uint256 & GetHash() const
Definition: wallet.h:277
QTreeWidgetItem * contextMenuItem
void updateAssetList(bool fSetOnStart=false)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:158
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
static bool fSubtractFeeFromAmount
AddressTableModel * getAddressTableModel()
Coin Control Features.
Definition: coincontrol.h:17
int getDisplayUnit() const
Definition: optionsmodel.h:68
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
bool IsAssetSelected(const COutPoint &output) const
Definition: coincontrol.h:76
CBlockPolicyEstimator feeEstimator
Definition: validation.cpp:109
void GetAllMyAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf, bool fIncludeAdministrator, bool fOnlyAdministrator)
Definition: assets.cpp:3507
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
Definition: ravenunits.cpp:146
bool getPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
void showMenu(const QPoint &)
int nDepth
Definition: wallet.h:533
static CCoinControl * assetControl
CTransactionRef tx
Definition: wallet.h:211
void setClipboard(const QString &str)
Definition: guiutil.cpp:945
uint256 uint256S(const char *str)
Definition: uint256.h:150
An encapsulated public key.
Definition: pubkey.h:40
static QString removeSpaces(QString text)
Definition: ravenunits.h:121
QString labelForAddress(const QString &address) const
void setModel(WalletModel *model)
bool GetAssetInfoFromScript(const CScript &scriptPubKey, std::string &strName, CAmount &nAmount)
Definition: assets.cpp:3423
bool isSpent(const COutPoint &outpoint) const
static QList< CAmount > payAmounts
An output of a transaction.
Definition: transaction.h:137
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
void viewItemChanged(QTreeWidgetItem *, int)
static void updateLabels(WalletModel *, QDialog *)
std::vector< CTxOut > vout
Definition: transaction.h:392
friend class CAssetControlWidgetItem
void UnSelectAll()
Definition: coincontrol.h:106
void GetAllAdministrativeAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf)
Definition: assets.cpp:3499
bool operator<(const CNetAddr &a, const CNetAddr &b)
Definition: netaddress.cpp:303
Qt::SortOrder sortOrder
void ListSelectedAssets(std::vector< COutPoint > &vOutpoints) const
Definition: coincontrol.h:118
256-bit opaque blob.
Definition: uint256.h:123
#define ASYMP_UTF8
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:326
const PlatformStyle * platformStyle
void listLockedCoins(std::vector< COutPoint > &vOutpts)
int64_t GetTxTime() const
Definition: wallet.cpp:1458
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:396
Interface to Raven wallet from Qt view code.
Definition: walletmodel.h:165
Ui::AssetControlDialog * ui
void unlockCoin(COutPoint &output)
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:30
const CWalletTx * tx
Definition: wallet.h:531
std::string GetHex() const
Definition: uint256.cpp:22
QSortFilterProxyModel * proxy
QStringListModel * stringModel
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:53
A mutable version of CTransaction.
Definition: transaction.h:389
QAction * copyTransactionHashAction
void listAssets(std::map< QString, std::map< QString, std::vector< COutput > > > &mapCoins) const
RVN START.
bool operator<(const QTreeWidgetItem &other) const
CWallet * getWallet() const
static QString formatWithCustomName(QString customName, const CAmount &amount, int unit=MAX_ASSET_UNITS, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with custom name)
Definition: ravenunits.cpp:151
void UnSelectAsset(const COutPoint &output)
Definition: coincontrol.h:99
void SelectAsset(const COutPoint &output)
Definition: coincontrol.h:86
CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl &coin_control, const CTxMemPool &pool, const CBlockPolicyEstimator &estimator, FeeCalculation *feeCalc)
Estimate the minimum fee considering user set parameters and the required fee.
Definition: fees.cpp:23
OptionsModel * getOptionsModel()
bool IsAssetNameAnOwner(const std::string &name)
Check if an asset is an owner.
Definition: assets.cpp:296
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:168
CFeeRate dustRelayFee
Definition: policy.cpp:263