Bitcoin Core  24.99.0
P2P Digital Currency
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2022 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/bitcoinunits.h>
9 #include <qt/clientmodel.h>
10 #include <qt/guiconstants.h>
11 #include <qt/guiutil.h>
12 #include <qt/optionsmodel.h>
13 #include <qt/platformstyle.h>
14 #include <qt/transactiondesc.h>
15 #include <qt/transactionrecord.h>
16 #include <qt/walletmodel.h>
17 
18 #include <core_io.h>
19 #include <interfaces/handler.h>
20 #include <uint256.h>
21 
22 #include <algorithm>
23 #include <functional>
24 
25 #include <QColor>
26 #include <QDateTime>
27 #include <QDebug>
28 #include <QIcon>
29 #include <QLatin1Char>
30 #include <QLatin1String>
31 #include <QList>
32 
33 
34 // Amount column is right-aligned it contains numbers
35 static int column_alignments[] = {
36  Qt::AlignLeft|Qt::AlignVCenter, /*status=*/
37  Qt::AlignLeft|Qt::AlignVCenter, /*watchonly=*/
38  Qt::AlignLeft|Qt::AlignVCenter, /*date=*/
39  Qt::AlignLeft|Qt::AlignVCenter, /*type=*/
40  Qt::AlignLeft|Qt::AlignVCenter, /*address=*/
41  Qt::AlignRight|Qt::AlignVCenter /* amount */
42  };
43 
44 // Comparison operator for sort/binary search of model tx list
45 struct TxLessThan
46 {
47  bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
48  {
49  return a.hash < b.hash;
50  }
51  bool operator()(const TransactionRecord &a, const uint256 &b) const
52  {
53  return a.hash < b;
54  }
55  bool operator()(const uint256 &a, const TransactionRecord &b) const
56  {
57  return a < b.hash;
58  }
59 };
60 
61 // queue notifications to show a non freezing progress dialog e.g. for rescan
63 {
64 public:
66  TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
67  hash(_hash), status(_status), showTransaction(_showTransaction) {}
68 
69  void invoke(QObject *ttm)
70  {
71  QString strHash = QString::fromStdString(hash.GetHex());
72  qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
73  bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
74  Q_ARG(QString, strHash),
75  Q_ARG(int, status),
76  Q_ARG(bool, showTransaction));
77  assert(invoked);
78  }
79 private:
83 };
84 
85 // Private implementation
87 {
88 public:
90  parent(_parent)
91  {
92  }
93 
95 
96  /* Local cache of wallet.
97  * As it is in the same order as the CWallet, by definition
98  * this is sorted by sha256.
99  */
100  QList<TransactionRecord> cachedWallet;
101 
103  bool m_loaded = false;
105  bool m_loading = false;
106  std::vector< TransactionNotification > vQueueNotifications;
107 
108  void NotifyTransactionChanged(const uint256 &hash, ChangeType status);
109  void DispatchNotifications();
110 
111  /* Query entire wallet anew from core.
112  */
114  {
115  assert(!m_loaded);
116  {
117  for (const auto& wtx : wallet.getWalletTxs()) {
120  }
121  }
122  }
123  m_loaded = true;
125  }
126 
127  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
128  with that of the core.
129 
130  Call with transaction that was added, removed or changed.
131  */
132  void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
133  {
134  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
135 
136  // Find bounds of this transaction in model
137  QList<TransactionRecord>::iterator lower = std::lower_bound(
138  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
139  QList<TransactionRecord>::iterator upper = std::upper_bound(
140  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
141  int lowerIndex = (lower - cachedWallet.begin());
142  int upperIndex = (upper - cachedWallet.begin());
143  bool inModel = (lower != upper);
144 
145  if(status == CT_UPDATED)
146  {
147  if(showTransaction && !inModel)
148  status = CT_NEW; /* Not in model, but want to show, treat as new */
149  if(!showTransaction && inModel)
150  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
151  }
152 
153  qDebug() << " inModel=" + QString::number(inModel) +
154  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
155  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
156 
157  switch(status)
158  {
159  case CT_NEW:
160  if(inModel)
161  {
162  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
163  break;
164  }
165  if(showTransaction)
166  {
167  // Find transaction in wallet
168  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
169  if(!wtx.tx)
170  {
171  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
172  break;
173  }
174  // Added -- insert at the right position
175  QList<TransactionRecord> toInsert =
177  if(!toInsert.isEmpty()) /* only if something to insert */
178  {
179  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
180  int insert_idx = lowerIndex;
181  for (const TransactionRecord &rec : toInsert)
182  {
183  cachedWallet.insert(insert_idx, rec);
184  insert_idx += 1;
185  }
186  parent->endInsertRows();
187  }
188  }
189  break;
190  case CT_DELETED:
191  if(!inModel)
192  {
193  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
194  break;
195  }
196  // Removed -- remove entire transaction from table
197  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
198  cachedWallet.erase(lower, upper);
199  parent->endRemoveRows();
200  break;
201  case CT_UPDATED:
202  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
203  // visible transactions.
204  for (int i = lowerIndex; i < upperIndex; i++) {
205  TransactionRecord *rec = &cachedWallet[i];
206  rec->status.needsUpdate = true;
207  }
208  break;
209  }
210  }
211 
212  int size()
213  {
214  return cachedWallet.size();
215  }
216 
217  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
218  {
219  if (idx >= 0 && idx < cachedWallet.size()) {
220  TransactionRecord *rec = &cachedWallet[idx];
221 
222  // If a status update is needed (blocks came in since last check),
223  // try to update the status of this transaction from the wallet.
224  // Otherwise, simply re-use the cached status.
226  int numBlocks;
227  int64_t block_time;
228  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
229  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
230  }
231  return rec;
232  }
233  return nullptr;
234  }
235 
237  {
238  return TransactionDesc::toHTML(node, wallet, rec, unit);
239  }
240 
242  {
243  auto tx = wallet.getTx(rec->hash);
244  if (tx) {
245  std::string strHex = EncodeHexTx(*tx);
246  return QString::fromStdString(strHex);
247  }
248  return QString();
249  }
250 };
251 
253  QAbstractTableModel(parent),
254  walletModel(parent),
255  priv(new TransactionTablePriv(this)),
256  platformStyle(_platformStyle)
257 {
259 
260  columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
262 
264 }
265 
267 {
269  delete priv;
270 }
271 
274 {
276  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
277 }
278 
279 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
280 {
281  uint256 updated;
282  updated.SetHex(hash.toStdString());
283 
284  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
285 }
286 
288 {
289  // Blocks came in since last poll.
290  // Invalidate status (number of confirmations) and (possibly) description
291  // for all rows. Qt is smart enough to only actually request the data for the
292  // visible rows.
293  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
294  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
295 }
296 
297 int TransactionTableModel::rowCount(const QModelIndex &parent) const
298 {
299  if (parent.isValid()) {
300  return 0;
301  }
302  return priv->size();
303 }
304 
305 int TransactionTableModel::columnCount(const QModelIndex &parent) const
306 {
307  if (parent.isValid()) {
308  return 0;
309  }
310  return columns.length();
311 }
312 
314 {
315  QString status;
316 
317  switch(wtx->status.status)
318  {
320  status = tr("Unconfirmed");
321  break;
323  status = tr("Abandoned");
324  break;
326  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
327  break;
329  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
330  break;
332  status = tr("Conflicted");
333  break;
335  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
336  break;
338  status = tr("Generated but not accepted");
339  break;
340  }
341 
342  return status;
343 }
344 
346 {
347  if(wtx->time)
348  {
349  return GUIUtil::dateTimeStr(wtx->time);
350  }
351  return QString();
352 }
353 
354 /* Look up address in address book, if found return label (address)
355  otherwise just return (address)
356  */
357 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
358 {
359  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
360  QString description;
361  if(!label.isEmpty())
362  {
363  description += label;
364  }
365  if(label.isEmpty() || tooltip)
366  {
367  description += QString(" (") + QString::fromStdString(address) + QString(")");
368  }
369  return description;
370 }
371 
373 {
374  switch(wtx->type)
375  {
377  return tr("Received with");
379  return tr("Received from");
382  return tr("Sent to");
384  return tr("Payment to yourself");
386  return tr("Mined");
387  default:
388  return QString();
389  }
390 }
391 
393 {
394  switch(wtx->type)
395  {
397  return QIcon(":/icons/tx_mined");
400  return QIcon(":/icons/tx_input");
403  return QIcon(":/icons/tx_output");
404  default:
405  return QIcon(":/icons/tx_inout");
406  }
407 }
408 
409 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
410 {
411  QString watchAddress;
412  if (tooltip && wtx->involvesWatchAddress) {
413  // Mark transactions involving watch-only addresses by adding " (watch-only)"
414  watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')');
415  }
416 
417  switch(wtx->type)
418  {
420  return QString::fromStdString(wtx->address) + watchAddress;
424  return lookupAddress(wtx->address, tooltip) + watchAddress;
426  return QString::fromStdString(wtx->address) + watchAddress;
428  return lookupAddress(wtx->address, tooltip) + watchAddress;
429  default:
430  return tr("(n/a)") + watchAddress;
431  }
432 }
433 
435 {
436  // Show addresses without label in a less visible color
437  switch(wtx->type)
438  {
442  {
443  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
444  if(label.isEmpty())
445  return COLOR_BAREADDRESS;
446  } break;
448  return COLOR_BAREADDRESS;
449  default:
450  break;
451  }
452  return QVariant();
453 }
454 
455 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
456 {
457  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
458  if(showUnconfirmed)
459  {
460  if(!wtx->status.countsForBalance)
461  {
462  str = QString("[") + str + QString("]");
463  }
464  }
465  return QString(str);
466 }
467 
469 {
470  switch(wtx->status.status)
471  {
473  return QIcon(":/icons/transaction_0");
475  return QIcon(":/icons/transaction_abandoned");
477  switch(wtx->status.depth)
478  {
479  case 1: return QIcon(":/icons/transaction_1");
480  case 2: return QIcon(":/icons/transaction_2");
481  case 3: return QIcon(":/icons/transaction_3");
482  case 4: return QIcon(":/icons/transaction_4");
483  default: return QIcon(":/icons/transaction_5");
484  };
486  return QIcon(":/icons/transaction_confirmed");
488  return QIcon(":/icons/transaction_conflicted");
490  int total = wtx->status.depth + wtx->status.matures_in;
491  int part = (wtx->status.depth * 4 / total) + 1;
492  return QIcon(QString(":/icons/transaction_%1").arg(part));
493  }
495  return QIcon(":/icons/transaction_0");
496  default:
497  return COLOR_BLACK;
498  }
499 }
500 
502 {
503  if (wtx->involvesWatchAddress)
504  return QIcon(":/icons/eye");
505  else
506  return QVariant();
507 }
508 
510 {
511  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
514  {
515  tooltip += QString(" ") + formatTxToAddress(rec, true);
516  }
517  return tooltip;
518 }
519 
520 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
521 {
522  if(!index.isValid())
523  return QVariant();
524  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
525 
526  const auto column = static_cast<ColumnIndex>(index.column());
527  switch (role) {
528  case RawDecorationRole:
529  switch (column) {
530  case Status:
531  return txStatusDecoration(rec);
532  case Watchonly:
533  return txWatchonlyDecoration(rec);
534  case Date: return {};
535  case Type: return {};
536  case ToAddress:
537  return txAddressDecoration(rec);
538  case Amount: return {};
539  } // no default case, so the compiler can warn about missing cases
540  assert(false);
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 (column) {
548  case Status: return {};
549  case Watchonly: return {};
550  case Date:
551  return formatTxDate(rec);
552  case Type:
553  return formatTxType(rec);
554  case ToAddress:
555  return formatTxToAddress(rec, false);
556  case Amount:
558  } // no default case, so the compiler can warn about missing cases
559  assert(false);
560  case Qt::EditRole:
561  // Edit role is used for sorting, so return the unformatted values
562  switch (column) {
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  } // no default case, so the compiler can warn about missing cases
576  assert(false);
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::fromSecsSinceEpoch(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::fromSecsSinceEpoch(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 (!m_loaded || m_loading)
720  {
721  vQueueNotifications.push_back(notification);
722  return;
723  }
724  notification.invoke(parent);
725 }
726 
728 {
729  if (!m_loaded || m_loading) return;
730 
731  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
732  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
733  assert(invoked);
734  }
735  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
736  {
737  if (vQueueNotifications.size() - i <= 10) {
738  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
739  assert(invoked);
740  }
741 
742  vQueueNotifications[i].invoke(parent);
743  }
744  vQueueNotifications.clear();
745 }
746 
748 {
749  // Connect signals to wallet
751  m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
752  priv->m_loading = progress < 100;
754  });
755 }
756 
758 {
759  // Disconnect signals from wallet
760  m_handler_transaction_changed->disconnect();
761  m_handler_show_progress->disconnect();
762 }
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
static QString format(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
static QString getAmountColumnTitle(Unit unit)
Gets title for amount column including current display unit if optionsModel reference available *‍/.
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
void displayUnitChanged(BitcoinUnit unit)
BitcoinUnit getDisplayUnit() const
Definition: optionsmodel.h:93
QIcon TextColorIcon(const QIcon &icon) const
Colorize an icon (given object) with the text color.
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, BitcoinUnit unit)
UI model for a transaction.
static QList< TransactionRecord > decomposeTransaction(const interfaces::WalletTx &wtx)
static const int RecommendedNumConfirmations
Number of confirmation recommended for accepting a transaction.
static bool showTransaction()
Decompose CWallet transaction to model transaction records.
TransactionStatus status
Status: can change with block chain update.
QString getTxHash() const
Return the unique identifier for this transaction (part)
bool statusUpdateNeeded(const uint256 &block_hash) const
Return whether a status update is needed.
void updateStatus(const interfaces::WalletTxStatus &wtx, const uint256 &block_hash, int numBlocks, int64_t block_time)
Update status from core wallet tx.
bool involvesWatchAddress
Whether the transaction was sent/received with a watch-only address.
UI model for the transaction table of a wallet.
QVariant txStatusDecoration(const TransactionRecord *wtx) const
TransactionTablePriv * priv
QVariant addressColor(const TransactionRecord *wtx) const
@ TxPlainTextRole
Whole transaction as plain text.
@ LabelRole
Label of address related to transaction.
@ LongDescriptionRole
Long description (HTML format)
@ TypeRole
Type of transaction.
@ StatusRole
Transaction status (TransactionRecord::Status)
@ DateRole
Date and time this transaction was created.
@ TxHashRole
Transaction hash.
@ TxHexRole
Transaction data, hex-encoded.
@ RawDecorationRole
Unprocessed icon.
@ AddressRole
Address of transaction.
@ WatchonlyDecorationRole
Watch-only icon.
@ WatchonlyRole
Watch-only boolean.
@ AmountRole
Net amount of transaction.
@ ConfirmedRole
Is transaction confirmed?
@ FormattedAmountRole
Formatted amount, without brackets when unconfirmed.
QString formatTooltip(const TransactionRecord *rec) const
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::SeparatorStyle::STANDARD) const
QVariant data(const QModelIndex &index, int role) const override
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const
void updateTransaction(const QString &hash, int status, bool showTransaction)
QString formatTxStatus(const TransactionRecord *wtx) const
std::unique_ptr< interfaces::Handler > m_handler_transaction_changed
int columnCount(const QModelIndex &parent) const override
std::unique_ptr< interfaces::Handler > m_handler_show_progress
TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent=nullptr)
int rowCount(const QModelIndex &parent) const override
void updateAmountColumnTitle()
Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table hea...
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
const PlatformStyle * platformStyle
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QString formatTxType(const TransactionRecord *wtx) const
QString lookupAddress(const std::string &address, bool tooltip) const
QVariant txAddressDecoration(const TransactionRecord *wtx) const
QString formatTxDate(const TransactionRecord *wtx) const
QString getTxHex(interfaces::Wallet &wallet, TransactionRecord *rec)
TransactionRecord * index(interfaces::Wallet &wallet, const uint256 &cur_block_hash, const int idx)
TransactionTablePriv(TransactionTableModel *_parent)
TransactionTableModel * parent
QList< TransactionRecord > cachedWallet
void refreshWallet(interfaces::Wallet &wallet)
bool m_loading
True when transactions are being notified, for instance when scanning.
void NotifyTransactionChanged(const uint256 &hash, ChangeType status)
void updateWallet(interfaces::Wallet &wallet, const uint256 &hash, int status, bool showTransaction)
std::vector< TransactionNotification > vQueueNotifications
QString describe(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, BitcoinUnit unit)
bool m_loaded
True when model finishes loading all wallet transactions on start.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:53
AddressTableModel * getAddressTableModel() const
interfaces::Wallet & wallet() const
Definition: walletmodel.h:145
OptionsModel * getOptionsModel() const
uint256 getLastBlockProcessed() const
interfaces::Node & node() const
Definition: walletmodel.h:144
void SetHex(const char *psz)
Definition: uint256.cpp:30
std::string ToString() const
Definition: uint256.cpp:64
bool IsNull() const
Definition: uint256.h:34
std::string GetHex() const
Definition: uint256.cpp:20
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
Interface for accessing a wallet.
Definition: wallet.h:58
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
virtual std::unique_ptr< Handler > handleTransactionChanged(TransactionChangedFn fn)=0
256-bit opaque blob.
Definition: uint256.h:119
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:143
#define COLOR_TX_STATUS_DANGER
Definition: guiconstants.h:37
#define COLOR_UNCONFIRMED
Definition: guiconstants.h:31
#define COLOR_NEGATIVE
Definition: guiconstants.h:33
#define COLOR_BLACK
Definition: guiconstants.h:39
#define COLOR_BAREADDRESS
Definition: guiconstants.h:35
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:86
Definition: init.h:25
Definition: node.h:39
TransactionNotification()=default
TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction)
bool countsForBalance
Transaction counts towards available balance.
@ Confirmed
Have 6 or more confirmations (normal tx) or fully mature (mined tx)
@ Unconfirmed
Normal (sent/received) transactions.
@ Immature
Generated (mined) transactions.
@ Confirming
Confirmed, but waiting for the recommended number of confirmations.
@ NotAccepted
Mined but not accepted.
@ Conflicted
Conflicts with other transaction or mempool.
@ Abandoned
Abandoned from the wallet.
std::string sortKey
Sorting key based on status.
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
bool operator()(const TransactionRecord &a, const uint256 &b) const
bool operator()(const uint256 &a, const TransactionRecord &b) const
CTransactionRef tx
Definition: wallet.h:387
Updated transaction status.
Definition: wallet.h:404
static int column_alignments[]
ChangeType
General change type (added, updated, removed).
Definition: ui_change_type.h:9
@ CT_UPDATED
@ CT_DELETED
@ CT_NEW
assert(!tx.IsCoinBase())