Bitcoin Core  21.99.0
P2P Digital Currency
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 
7 #include <qt/addresstablemodel.h>
8 #include <qt/clientmodel.h>
9 #include <qt/guiconstants.h>
10 #include <qt/guiutil.h>
11 #include <qt/optionsmodel.h>
12 #include <qt/platformstyle.h>
13 #include <qt/transactiondesc.h>
14 #include <qt/transactionrecord.h>
15 #include <qt/walletmodel.h>
16 
17 #include <core_io.h>
18 #include <interfaces/handler.h>
19 #include <uint256.h>
20 
21 #include <algorithm>
22 
23 #include <QColor>
24 #include <QDateTime>
25 #include <QDebug>
26 #include <QIcon>
27 #include <QList>
28 
29 
30 // Amount column is right-aligned it contains numbers
31 static int column_alignments[] = {
32  Qt::AlignLeft|Qt::AlignVCenter, /* status */
33  Qt::AlignLeft|Qt::AlignVCenter, /* watchonly */
34  Qt::AlignLeft|Qt::AlignVCenter, /* date */
35  Qt::AlignLeft|Qt::AlignVCenter, /* type */
36  Qt::AlignLeft|Qt::AlignVCenter, /* address */
37  Qt::AlignRight|Qt::AlignVCenter /* amount */
38  };
39 
40 // Comparison operator for sort/binary search of model tx list
41 struct TxLessThan
42 {
43  bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
44  {
45  return a.hash < b.hash;
46  }
47  bool operator()(const TransactionRecord &a, const uint256 &b) const
48  {
49  return a.hash < b;
50  }
51  bool operator()(const uint256 &a, const TransactionRecord &b) const
52  {
53  return a < b.hash;
54  }
55 };
56 
57 // queue notifications to show a non freezing progress dialog e.g. for rescan
59 {
60 public:
62  TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
63  hash(_hash), status(_status), showTransaction(_showTransaction) {}
64 
65  void invoke(QObject *ttm)
66  {
67  QString strHash = QString::fromStdString(hash.GetHex());
68  qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
69  bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
70  Q_ARG(QString, strHash),
71  Q_ARG(int, status),
72  Q_ARG(bool, showTransaction));
73  assert(invoked);
74  }
75 private:
79 };
80 
81 // Private implementation
83 {
84 public:
86  parent(_parent)
87  {
88  }
89 
91 
92  /* Local cache of wallet.
93  * As it is in the same order as the CWallet, by definition
94  * this is sorted by sha256.
95  */
96  QList<TransactionRecord> cachedWallet;
97 
98  bool fQueueNotifications = false;
99  std::vector< TransactionNotification > vQueueNotifications;
100 
101  void NotifyTransactionChanged(const uint256 &hash, ChangeType status);
102  void ShowProgress(const std::string &title, int nProgress);
103 
104  /* Query entire wallet anew from core.
105  */
107  {
108  qDebug() << "TransactionTablePriv::refreshWallet";
109  cachedWallet.clear();
110  {
111  for (const auto& wtx : wallet.getWalletTxs()) {
113  cachedWallet.append(TransactionRecord::decomposeTransaction(wtx));
114  }
115  }
116  }
117  }
118 
119  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
120  with that of the core.
121 
122  Call with transaction that was added, removed or changed.
123  */
124  void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
125  {
126  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
127 
128  // Find bounds of this transaction in model
129  QList<TransactionRecord>::iterator lower = std::lower_bound(
130  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
131  QList<TransactionRecord>::iterator upper = std::upper_bound(
132  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
133  int lowerIndex = (lower - cachedWallet.begin());
134  int upperIndex = (upper - cachedWallet.begin());
135  bool inModel = (lower != upper);
136 
137  if(status == CT_UPDATED)
138  {
139  if(showTransaction && !inModel)
140  status = CT_NEW; /* Not in model, but want to show, treat as new */
141  if(!showTransaction && inModel)
142  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
143  }
144 
145  qDebug() << " inModel=" + QString::number(inModel) +
146  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
147  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
148 
149  switch(status)
150  {
151  case CT_NEW:
152  if(inModel)
153  {
154  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
155  break;
156  }
157  if(showTransaction)
158  {
159  // Find transaction in wallet
160  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
161  if(!wtx.tx)
162  {
163  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
164  break;
165  }
166  // Added -- insert at the right position
167  QList<TransactionRecord> toInsert =
169  if(!toInsert.isEmpty()) /* only if something to insert */
170  {
171  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
172  int insert_idx = lowerIndex;
173  for (const TransactionRecord &rec : toInsert)
174  {
175  cachedWallet.insert(insert_idx, rec);
176  insert_idx += 1;
177  }
178  parent->endInsertRows();
179  }
180  }
181  break;
182  case CT_DELETED:
183  if(!inModel)
184  {
185  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
186  break;
187  }
188  // Removed -- remove entire transaction from table
189  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
190  cachedWallet.erase(lower, upper);
191  parent->endRemoveRows();
192  break;
193  case CT_UPDATED:
194  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
195  // visible transactions.
196  for (int i = lowerIndex; i < upperIndex; i++) {
197  TransactionRecord *rec = &cachedWallet[i];
198  rec->status.needsUpdate = true;
199  }
200  break;
201  }
202  }
203 
204  int size()
205  {
206  return cachedWallet.size();
207  }
208 
209  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
210  {
211  if (idx >= 0 && idx < cachedWallet.size()) {
212  TransactionRecord *rec = &cachedWallet[idx];
213 
214  // If a status update is needed (blocks came in since last check),
215  // try to update the status of this transaction from the wallet.
216  // Otherwise, simply re-use the cached status.
218  int numBlocks;
219  int64_t block_time;
220  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
221  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
222  }
223  return rec;
224  }
225  return nullptr;
226  }
227 
229  {
230  return TransactionDesc::toHTML(node, wallet, rec, unit);
231  }
232 
234  {
235  auto tx = wallet.getTx(rec->hash);
236  if (tx) {
237  std::string strHex = EncodeHexTx(*tx);
238  return QString::fromStdString(strHex);
239  }
240  return QString();
241  }
242 };
243 
245  QAbstractTableModel(parent),
246  walletModel(parent),
247  priv(new TransactionTablePriv(this)),
248  fProcessingQueuedTransactions(false),
249  platformStyle(_platformStyle)
250 {
251  columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
253 
255 
257 }
258 
260 {
262  delete priv;
263 }
264 
267 {
269  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
270 }
271 
272 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
273 {
274  uint256 updated;
275  updated.SetHex(hash.toStdString());
276 
277  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
278 }
279 
281 {
282  // Blocks came in since last poll.
283  // Invalidate status (number of confirmations) and (possibly) description
284  // for all rows. Qt is smart enough to only actually request the data for the
285  // visible rows.
286  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
287  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
288 }
289 
290 int TransactionTableModel::rowCount(const QModelIndex &parent) const
291 {
292  if (parent.isValid()) {
293  return 0;
294  }
295  return priv->size();
296 }
297 
298 int TransactionTableModel::columnCount(const QModelIndex &parent) const
299 {
300  if (parent.isValid()) {
301  return 0;
302  }
303  return columns.length();
304 }
305 
307 {
308  QString status;
309 
310  switch(wtx->status.status)
311  {
313  status = tr("Open for %n more block(s)","",wtx->status.open_for);
314  break;
316  status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
317  break;
319  status = tr("Unconfirmed");
320  break;
322  status = tr("Abandoned");
323  break;
325  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
326  break;
328  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
329  break;
331  status = tr("Conflicted");
332  break;
334  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
335  break;
337  status = tr("Generated but not accepted");
338  break;
339  }
340 
341  return status;
342 }
343 
345 {
346  if(wtx->time)
347  {
348  return GUIUtil::dateTimeStr(wtx->time);
349  }
350  return QString();
351 }
352 
353 /* Look up address in address book, if found return label (address)
354  otherwise just return (address)
355  */
356 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
357 {
358  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
359  QString description;
360  if(!label.isEmpty())
361  {
362  description += label;
363  }
364  if(label.isEmpty() || tooltip)
365  {
366  description += QString(" (") + QString::fromStdString(address) + QString(")");
367  }
368  return description;
369 }
370 
372 {
373  switch(wtx->type)
374  {
376  return tr("Received with");
378  return tr("Received from");
381  return tr("Sent to");
383  return tr("Payment to yourself");
385  return tr("Mined");
386  default:
387  return QString();
388  }
389 }
390 
392 {
393  switch(wtx->type)
394  {
396  return QIcon(":/icons/tx_mined");
399  return QIcon(":/icons/tx_input");
402  return QIcon(":/icons/tx_output");
403  default:
404  return QIcon(":/icons/tx_inout");
405  }
406 }
407 
408 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
409 {
410  QString watchAddress;
411  if (tooltip) {
412  // Mark transactions involving watch-only addresses by adding " (watch-only)"
413  watchAddress = wtx->involvesWatchAddress ? QString(" (") + tr("watch-only") + QString(")") : "";
414  }
415 
416  switch(wtx->type)
417  {
419  return QString::fromStdString(wtx->address) + watchAddress;
423  return lookupAddress(wtx->address, tooltip) + watchAddress;
425  return QString::fromStdString(wtx->address) + watchAddress;
427  return lookupAddress(wtx->address, tooltip) + watchAddress;
428  default:
429  return tr("(n/a)") + watchAddress;
430  }
431 }
432 
434 {
435  // Show addresses without label in a less visible color
436  switch(wtx->type)
437  {
441  {
442  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
443  if(label.isEmpty())
444  return COLOR_BAREADDRESS;
445  } break;
447  return COLOR_BAREADDRESS;
448  default:
449  break;
450  }
451  return QVariant();
452 }
453 
454 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
455 {
456  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
457  if(showUnconfirmed)
458  {
459  if(!wtx->status.countsForBalance)
460  {
461  str = QString("[") + str + QString("]");
462  }
463  }
464  return QString(str);
465 }
466 
468 {
469  switch(wtx->status.status)
470  {
475  return QIcon(":/icons/transaction_0");
477  return QIcon(":/icons/transaction_abandoned");
479  switch(wtx->status.depth)
480  {
481  case 1: return QIcon(":/icons/transaction_1");
482  case 2: return QIcon(":/icons/transaction_2");
483  case 3: return QIcon(":/icons/transaction_3");
484  case 4: return QIcon(":/icons/transaction_4");
485  default: return QIcon(":/icons/transaction_5");
486  };
488  return QIcon(":/icons/transaction_confirmed");
490  return QIcon(":/icons/transaction_conflicted");
492  int total = wtx->status.depth + wtx->status.matures_in;
493  int part = (wtx->status.depth * 4 / total) + 1;
494  return QIcon(QString(":/icons/transaction_%1").arg(part));
495  }
497  return QIcon(":/icons/transaction_0");
498  default:
499  return COLOR_BLACK;
500  }
501 }
502 
504 {
505  if (wtx->involvesWatchAddress)
506  return QIcon(":/icons/eye");
507  else
508  return QVariant();
509 }
510 
512 {
513  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
516  {
517  tooltip += QString(" ") + formatTxToAddress(rec, true);
518  }
519  return tooltip;
520 }
521 
522 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
523 {
524  if(!index.isValid())
525  return QVariant();
526  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
527 
528  switch(role)
529  {
530  case RawDecorationRole:
531  switch(index.column())
532  {
533  case Status:
534  return txStatusDecoration(rec);
535  case Watchonly:
536  return txWatchonlyDecoration(rec);
537  case ToAddress:
538  return txAddressDecoration(rec);
539  }
540  break;
541  case Qt::DecorationRole:
542  {
543  QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
544  return platformStyle->TextColorIcon(icon);
545  }
546  case Qt::DisplayRole:
547  switch(index.column())
548  {
549  case Date:
550  return formatTxDate(rec);
551  case Type:
552  return formatTxType(rec);
553  case ToAddress:
554  return formatTxToAddress(rec, false);
555  case Amount:
557  }
558  break;
559  case Qt::EditRole:
560  // Edit role is used for sorting, so return the unformatted values
561  switch(index.column())
562  {
563  case Status:
564  return QString::fromStdString(rec->status.sortKey);
565  case Date:
566  return rec->time;
567  case Type:
568  return formatTxType(rec);
569  case Watchonly:
570  return (rec->involvesWatchAddress ? 1 : 0);
571  case ToAddress:
572  return formatTxToAddress(rec, true);
573  case Amount:
574  return qint64(rec->credit + rec->debit);
575  }
576  break;
577  case Qt::ToolTipRole:
578  return formatTooltip(rec);
579  case Qt::TextAlignmentRole:
580  return column_alignments[index.column()];
581  case Qt::ForegroundRole:
582  // Use the "danger" color for abandoned transactions
584  {
585  return COLOR_TX_STATUS_DANGER;
586  }
587  // Non-confirmed (but not immature) as transactions are grey
589  {
590  return COLOR_UNCONFIRMED;
591  }
592  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
593  {
594  return COLOR_NEGATIVE;
595  }
596  if(index.column() == ToAddress)
597  {
598  return addressColor(rec);
599  }
600  break;
601  case TypeRole:
602  return rec->type;
603  case DateRole:
604  return QDateTime::fromTime_t(static_cast<uint>(rec->time));
605  case WatchonlyRole:
606  return rec->involvesWatchAddress;
608  return txWatchonlyDecoration(rec);
609  case LongDescriptionRole:
611  case AddressRole:
612  return QString::fromStdString(rec->address);
613  case LabelRole:
614  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
615  case AmountRole:
616  return qint64(rec->credit + rec->debit);
617  case TxHashRole:
618  return rec->getTxHash();
619  case TxHexRole:
620  return priv->getTxHex(walletModel->wallet(), rec);
621  case TxPlainTextRole:
622  {
623  QString details;
624  QDateTime date = QDateTime::fromTime_t(static_cast<uint>(rec->time));
625  QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
626 
627  details.append(date.toString("M/d/yy HH:mm"));
628  details.append(" ");
629  details.append(formatTxStatus(rec));
630  details.append(". ");
631  if(!formatTxType(rec).isEmpty()) {
632  details.append(formatTxType(rec));
633  details.append(" ");
634  }
635  if(!rec->address.empty()) {
636  if(txLabel.isEmpty())
637  details.append(tr("(no label)") + " ");
638  else {
639  details.append("(");
640  details.append(txLabel);
641  details.append(") ");
642  }
643  details.append(QString::fromStdString(rec->address));
644  details.append(" ");
645  }
646  details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
647  return details;
648  }
649  case ConfirmedRole:
650  return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
651  case FormattedAmountRole:
652  // Used for copy/export, so don't include separators
654  case StatusRole:
655  return rec->status.status;
656  }
657  return QVariant();
658 }
659 
660 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
661 {
662  if(orientation == Qt::Horizontal)
663  {
664  if(role == Qt::DisplayRole)
665  {
666  return columns[section];
667  }
668  else if (role == Qt::TextAlignmentRole)
669  {
670  return column_alignments[section];
671  } else if (role == Qt::ToolTipRole)
672  {
673  switch(section)
674  {
675  case Status:
676  return tr("Transaction status. Hover over this field to show number of confirmations.");
677  case Date:
678  return tr("Date and time that the transaction was received.");
679  case Type:
680  return tr("Type of transaction.");
681  case Watchonly:
682  return tr("Whether or not a watch-only address is involved in this transaction.");
683  case ToAddress:
684  return tr("User-defined intent/purpose of the transaction.");
685  case Amount:
686  return tr("Amount removed from or added to balance.");
687  }
688  }
689  }
690  return QVariant();
691 }
692 
693 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
694 {
695  Q_UNUSED(parent);
697  if(data)
698  {
699  return createIndex(row, column, data);
700  }
701  return QModelIndex();
702 }
703 
705 {
706  // emit dataChanged to update Amount column with the current unit
708  Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
709 }
710 
712 {
713  // Find transaction in wallet
714  // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
715  bool showTransaction = TransactionRecord::showTransaction();
716 
717  TransactionNotification notification(hash, status, showTransaction);
718 
719  if (fQueueNotifications)
720  {
721  vQueueNotifications.push_back(notification);
722  return;
723  }
724  notification.invoke(parent);
725 }
726 
727 void TransactionTablePriv::ShowProgress(const std::string &title, int nProgress)
728 {
729  if (nProgress == 0)
730  fQueueNotifications = true;
731 
732  if (nProgress == 100)
733  {
734  fQueueNotifications = false;
735  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
736  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
737  assert(invoked);
738  }
739  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
740  {
741  if (vQueueNotifications.size() - i <= 10) {
742  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
743  assert(invoked);
744  }
745 
746  vQueueNotifications[i].invoke(parent);
747  }
748  vQueueNotifications.clear();
749  }
750 }
751 
753 {
754  // Connect signals to wallet
756  m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(&TransactionTablePriv::ShowProgress, priv, std::placeholders::_1, std::placeholders::_2));
757 }
758 
760 {
761  // Disconnect signals from wallet
762  m_handler_transaction_changed->disconnect();
763  m_handler_show_progress->disconnect();
764 }
void updateWallet(interfaces::Wallet &wallet, const uint256 &hash, int status, bool showTransaction)
bool statusUpdateNeeded(const uint256 &block_hash) const
Return whether a status update is needed.
void updateAmountColumnTitle()
Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table hea...
TransactionRecord * index(interfaces::Wallet &wallet, const uint256 &cur_block_hash, const int idx)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
void ShowProgress(const std::string &title, int nProgress)
Confirmed, but waiting for the recommended number of confirmations.
interfaces::Wallet & wallet() const
Definition: walletmodel.h:146
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const
Transaction not yet final, waiting for block.
Transaction status (TransactionRecord::Status)
assert(!tx.IsCoinBase())
QString getTxHash() const
Return the unique identifier for this transaction (part)
Generated (mined) transactions.
static int column_alignments[]
QString formatTooltip(const TransactionRecord *rec) const
virtual CTransactionRef getTx(const uint256 &txid)=0
Get a transaction.
Have 6 or more confirmations (normal tx) or fully mature (mined tx)
std::string sortKey
Sorting key based on status.
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
void updateTransaction(const QString &hash, int status, bool showTransaction)
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
QString describe(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:69
TransactionTablePriv(TransactionTableModel *_parent)
static QList< TransactionRecord > decomposeTransaction(const interfaces::WalletTx &wtx)
QVariant txStatusDecoration(const TransactionRecord *wtx) const
void NotifyTransactionChanged(const uint256 &hash, ChangeType status)
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
Mined but not accepted.
Not yet mined into a block.
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
int columnCount(const QModelIndex &parent) const override
CTransactionRef tx
Definition: wallet.h:371
QIcon TextColorIcon(const QIcon &icon) const
Colorize an icon (given object) with the text color.
AddressTableModel * getAddressTableModel()
Transaction data, hex-encoded.
TransactionTableModel * parent
bool IsNull() const
Definition: uint256.h:31
int rowCount(const QModelIndex &parent) const override
TransactionTablePriv * priv
virtual WalletTx getWalletTx(const uint256 &txid)=0
Get transaction information.
void updateStatus(const interfaces::WalletTxStatus &wtx, const uint256 &block_hash, int numBlocks, int64_t block_time)
Update status from core wallet tx.
int getDisplayUnit() const
Definition: optionsmodel.h:85
static QString getAmountColumnTitle(int unit)
Gets title for amount column including current display unit if optionsModel reference available */...
bool operator()(const uint256 &a, const TransactionRecord &b) const
QList< TransactionRecord > cachedWallet
bool operator()(const TransactionRecord &a, const uint256 &b) const
uint256 getLastBlockProcessed() const
virtual std::unique_ptr< Handler > handleTransactionChanged(TransactionChangedFn fn)=0
UI model for a transaction.
TransactionStatus status
Status: can change with block chain update.
QString formatTxType(const TransactionRecord *wtx) const
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
Whole transaction as plain text.
std::unique_ptr< interfaces::Handler > m_handler_transaction_changed
std::vector< TransactionNotification > vQueueNotifications
#define COLOR_TX_STATUS_DANGER
Definition: guiconstants.h:33
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
Interface for accessing a wallet.
Definition: wallet.h:52
TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction)
bool countsForBalance
Transaction counts towards available balance.
virtual bool tryGetTxStatus(const uint256 &txid, WalletTxStatus &tx_status, int &num_blocks, int64_t &block_time)=0
Try to get updated status for a particular transaction, if possible without blocking.
TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent=nullptr)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Date and time this transaction was created.
std::string ToString() const
Definition: uint256.cpp:64
#define COLOR_BLACK
Definition: guiconstants.h:35
interfaces::Node & node() const
Definition: walletmodel.h:145
void displayUnitChanged(int unit)
UI model for the transaction table of a wallet.
#define COLOR_UNCONFIRMED
Definition: guiconstants.h:25
void refreshWallet(interfaces::Wallet &wallet)
Normal (sent/received) transactions.
QString lookupAddress(const std::string &address, bool tooltip) const
std::unique_ptr< interfaces::Handler > m_handler_show_progress
static bool showTransaction()
Decompose CWallet transaction to model transaction records.
256-bit opaque blob.
Definition: uint256.h:124
virtual std::vector< WalletTx > getWalletTxs()=0
Get list of all wallet transactions.
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
Conflicts with other transaction or mempool.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:51
bool involvesWatchAddress
Whether the transaction was sent/received with a watch-only address.
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
QString getTxHex(interfaces::Wallet &wallet, TransactionRecord *rec)
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:134
Label of address related to transaction.
QString formatTxStatus(const TransactionRecord *wtx) const
QVariant addressColor(const TransactionRecord *wtx) const
#define COLOR_TX_STATUS_OPENUNTILDATE
Definition: guiconstants.h:31
qint64 open_for
Timestamp if status==OpenUntilDate, otherwise number of additional blocks that need to be mined befor...
QVariant txAddressDecoration(const TransactionRecord *wtx) const
Formatted amount, without brackets when unconfirmed.
QVariant data(const QModelIndex &index, int role) const override
ChangeType
General change type (added, updated, removed).
Definition: ui_change_type.h:9
void SetHex(const char *psz)
Definition: uint256.cpp:30
Abandoned from the wallet.
#define COLOR_BAREADDRESS
Definition: guiconstants.h:29
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:52
const PlatformStyle * platformStyle
Updated transaction status.
Definition: wallet.h:385
#define COLOR_NEGATIVE
Definition: guiconstants.h:27
static const int RecommendedNumConfirmations
Number of confirmation recommended for accepting a transaction.
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::SeparatorStyle::STANDARD) const
OptionsModel * getOptionsModel()
QString formatTxDate(const TransactionRecord *wtx) const