Bitcoin Core  27.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 <tinyformat.h>
21 #include <uint256.h>
22 
23 #include <algorithm>
24 #include <functional>
25 
26 #include <QColor>
27 #include <QDateTime>
28 #include <QDebug>
29 #include <QIcon>
30 #include <QLatin1Char>
31 #include <QLatin1String>
32 #include <QList>
33 
34 
35 // Amount column is right-aligned it contains numbers
36 static int column_alignments[] = {
37  Qt::AlignLeft|Qt::AlignVCenter, /*status=*/
38  Qt::AlignLeft|Qt::AlignVCenter, /*watchonly=*/
39  Qt::AlignLeft|Qt::AlignVCenter, /*date=*/
40  Qt::AlignLeft|Qt::AlignVCenter, /*type=*/
41  Qt::AlignLeft|Qt::AlignVCenter, /*address=*/
42  Qt::AlignRight|Qt::AlignVCenter /* amount */
43  };
44 
45 // Comparison operator for sort/binary search of model tx list
46 struct TxLessThan
47 {
48  bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
49  {
50  return a.hash < b.hash;
51  }
52  bool operator()(const TransactionRecord &a, const uint256 &b) const
53  {
54  return a.hash < b;
55  }
56  bool operator()(const uint256 &a, const TransactionRecord &b) const
57  {
58  return a < b.hash;
59  }
60 };
61 
62 // queue notifications to show a non freezing progress dialog e.g. for rescan
64 {
65 public:
67  TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
68  hash(_hash), status(_status), showTransaction(_showTransaction) {}
69 
70  void invoke(QObject *ttm)
71  {
72  QString strHash = QString::fromStdString(hash.GetHex());
73  qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
74  bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
75  Q_ARG(QString, strHash),
76  Q_ARG(int, status),
77  Q_ARG(bool, showTransaction));
78  assert(invoked);
79  }
80 private:
84 };
85 
86 // Private implementation
88 {
89 public:
91  parent(_parent)
92  {
93  }
94 
96 
98  QList<TransactionRecord> cachedWallet;
99 
101  bool m_loaded = false;
103  bool m_loading = false;
104  std::vector< TransactionNotification > vQueueNotifications;
105 
106  void NotifyTransactionChanged(const uint256 &hash, ChangeType status);
107  void DispatchNotifications();
108 
109  /* Query entire wallet anew from core.
110  */
112  {
113  assert(!m_loaded);
114  {
115  for (const auto& wtx : wallet.getWalletTxs()) {
118  }
119  }
120  }
121  m_loaded = true;
123  }
124 
125  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
126  with that of the core.
127 
128  Call with transaction that was added, removed or changed.
129  */
130  void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
131  {
132  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
133 
134  // Find bounds of this transaction in model
135  QList<TransactionRecord>::iterator lower = std::lower_bound(
136  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
137  QList<TransactionRecord>::iterator upper = std::upper_bound(
138  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
139  int lowerIndex = (lower - cachedWallet.begin());
140  int upperIndex = (upper - cachedWallet.begin());
141  bool inModel = (lower != upper);
142 
143  if(status == CT_UPDATED)
144  {
145  if(showTransaction && !inModel)
146  status = CT_NEW; /* Not in model, but want to show, treat as new */
147  if(!showTransaction && inModel)
148  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
149  }
150 
151  qDebug() << " inModel=" + QString::number(inModel) +
152  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
153  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
154 
155  switch(status)
156  {
157  case CT_NEW:
158  if(inModel)
159  {
160  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
161  break;
162  }
163  if(showTransaction)
164  {
165  // Find transaction in wallet
166  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
167  if(!wtx.tx)
168  {
169  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
170  break;
171  }
172  // Added -- insert at the right position
173  QList<TransactionRecord> toInsert =
175  if(!toInsert.isEmpty()) /* only if something to insert */
176  {
177  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
178  int insert_idx = lowerIndex;
179  for (const TransactionRecord &rec : toInsert)
180  {
181  cachedWallet.insert(insert_idx, rec);
182  insert_idx += 1;
183  }
184  parent->endInsertRows();
185  }
186  }
187  break;
188  case CT_DELETED:
189  if(!inModel)
190  {
191  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
192  break;
193  }
194  // Removed -- remove entire transaction from table
195  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
196  cachedWallet.erase(lower, upper);
197  parent->endRemoveRows();
198  break;
199  case CT_UPDATED:
200  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
201  // visible transactions.
202  for (int i = lowerIndex; i < upperIndex; i++) {
203  TransactionRecord *rec = &cachedWallet[i];
204  rec->status.needsUpdate = true;
205  }
206  break;
207  }
208  }
209 
210  int size()
211  {
212  return cachedWallet.size();
213  }
214 
215  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
216  {
217  if (idx >= 0 && idx < cachedWallet.size()) {
218  TransactionRecord *rec = &cachedWallet[idx];
219 
220  // If a status update is needed (blocks came in since last check),
221  // try to update the status of this transaction from the wallet.
222  // Otherwise, simply reuse the cached status.
224  int numBlocks;
225  int64_t block_time;
226  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
227  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
228  }
229  return rec;
230  }
231  return nullptr;
232  }
233 
235  {
236  return TransactionDesc::toHTML(node, wallet, rec, unit);
237  }
238 
240  {
241  auto tx = wallet.getTx(rec->hash);
242  if (tx) {
243  std::string strHex = EncodeHexTx(*tx);
244  return QString::fromStdString(strHex);
245  }
246  return QString();
247  }
248 };
249 
251  QAbstractTableModel(parent),
252  walletModel(parent),
253  priv(new TransactionTablePriv(this)),
254  platformStyle(_platformStyle)
255 {
257 
258  columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
260 
262 }
263 
265 {
267  delete priv;
268 }
269 
272 {
274  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
275 }
276 
277 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
278 {
279  uint256 updated;
280  updated.SetHex(hash.toStdString());
281 
282  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
283 }
284 
286 {
287  // Blocks came in since last poll.
288  // Invalidate status (number of confirmations) and (possibly) description
289  // for all rows. Qt is smart enough to only actually request the data for the
290  // visible rows.
291  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
292  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
293 }
294 
295 int TransactionTableModel::rowCount(const QModelIndex &parent) const
296 {
297  if (parent.isValid()) {
298  return 0;
299  }
300  return priv->size();
301 }
302 
303 int TransactionTableModel::columnCount(const QModelIndex &parent) const
304 {
305  if (parent.isValid()) {
306  return 0;
307  }
308  return columns.length();
309 }
310 
312 {
313  QString status;
314 
315  switch(wtx->status.status)
316  {
318  status = tr("Unconfirmed");
319  break;
321  status = tr("Abandoned");
322  break;
324  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
325  break;
327  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
328  break;
330  status = tr("Conflicted");
331  break;
333  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
334  break;
336  status = tr("Generated but not accepted");
337  break;
338  }
339 
340  return status;
341 }
342 
344 {
345  if(wtx->time)
346  {
347  return GUIUtil::dateTimeStr(wtx->time);
348  }
349  return QString();
350 }
351 
352 /* Look up address in address book, if found return label (address)
353  otherwise just return (address)
354  */
355 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
356 {
357  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
358  QString description;
359  if(!label.isEmpty())
360  {
361  description += label;
362  }
363  if(label.isEmpty() || tooltip)
364  {
365  description += QString(" (") + QString::fromStdString(address) + QString(")");
366  }
367  return description;
368 }
369 
371 {
372  switch(wtx->type)
373  {
375  return tr("Received with");
377  return tr("Received from");
380  return tr("Sent to");
382  return tr("Mined");
383  default:
384  return QString();
385  }
386 }
387 
389 {
390  switch(wtx->type)
391  {
393  return QIcon(":/icons/tx_mined");
396  return QIcon(":/icons/tx_input");
399  return QIcon(":/icons/tx_output");
400  default:
401  return QIcon(":/icons/tx_inout");
402  }
403 }
404 
405 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
406 {
407  QString watchAddress;
408  if (tooltip && wtx->involvesWatchAddress) {
409  // Mark transactions involving watch-only addresses by adding " (watch-only)"
410  watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')');
411  }
412 
413  switch(wtx->type)
414  {
416  return QString::fromStdString(wtx->address) + watchAddress;
420  return lookupAddress(wtx->address, tooltip) + watchAddress;
422  return QString::fromStdString(wtx->address) + watchAddress;
423  default:
424  return tr("(n/a)") + watchAddress;
425  }
426 }
427 
429 {
430  // Show addresses without label in a less visible color
431  switch(wtx->type)
432  {
436  {
437  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
438  if(label.isEmpty())
439  return COLOR_BAREADDRESS;
440  } break;
441  default:
442  break;
443  }
444  return QVariant();
445 }
446 
447 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
448 {
449  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
450  if(showUnconfirmed)
451  {
452  if(!wtx->status.countsForBalance)
453  {
454  str = QString("[") + str + QString("]");
455  }
456  }
457  return QString(str);
458 }
459 
461 {
462  switch(wtx->status.status)
463  {
465  return QIcon(":/icons/transaction_0");
467  return QIcon(":/icons/transaction_abandoned");
469  switch(wtx->status.depth)
470  {
471  case 1: return QIcon(":/icons/transaction_1");
472  case 2: return QIcon(":/icons/transaction_2");
473  case 3: return QIcon(":/icons/transaction_3");
474  case 4: return QIcon(":/icons/transaction_4");
475  default: return QIcon(":/icons/transaction_5");
476  };
478  return QIcon(":/icons/transaction_confirmed");
480  return QIcon(":/icons/transaction_conflicted");
482  int total = wtx->status.depth + wtx->status.matures_in;
483  int part = (wtx->status.depth * 4 / total) + 1;
484  return QIcon(QString(":/icons/transaction_%1").arg(part));
485  }
487  return QIcon(":/icons/transaction_0");
488  default:
489  return COLOR_BLACK;
490  }
491 }
492 
494 {
495  if (wtx->involvesWatchAddress)
496  return QIcon(":/icons/eye");
497  else
498  return QVariant();
499 }
500 
502 {
503  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
506  {
507  tooltip += QString(" ") + formatTxToAddress(rec, true);
508  }
509  return tooltip;
510 }
511 
512 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
513 {
514  if(!index.isValid())
515  return QVariant();
516  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
517 
518  const auto column = static_cast<ColumnIndex>(index.column());
519  switch (role) {
520  case RawDecorationRole:
521  switch (column) {
522  case Status:
523  return txStatusDecoration(rec);
524  case Watchonly:
525  return txWatchonlyDecoration(rec);
526  case Date: return {};
527  case Type: return {};
528  case ToAddress:
529  return txAddressDecoration(rec);
530  case Amount: return {};
531  } // no default case, so the compiler can warn about missing cases
532  assert(false);
533  case Qt::DecorationRole:
534  {
535  QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
536  return platformStyle->TextColorIcon(icon);
537  }
538  case Qt::DisplayRole:
539  switch (column) {
540  case Status: return {};
541  case Watchonly: return {};
542  case Date:
543  return formatTxDate(rec);
544  case Type:
545  return formatTxType(rec);
546  case ToAddress:
547  return formatTxToAddress(rec, false);
548  case Amount:
550  } // no default case, so the compiler can warn about missing cases
551  assert(false);
552  case Qt::EditRole:
553  // Edit role is used for sorting, so return the unformatted values
554  switch (column) {
555  case Status:
556  return QString::fromStdString(rec->status.sortKey);
557  case Date:
558  return QString::fromStdString(strprintf("%020s-%s", rec->time, rec->status.sortKey));
559  case Type:
560  return formatTxType(rec);
561  case Watchonly:
562  return (rec->involvesWatchAddress ? 1 : 0);
563  case ToAddress:
564  return formatTxToAddress(rec, true);
565  case Amount:
566  return qint64(rec->credit + rec->debit);
567  } // no default case, so the compiler can warn about missing cases
568  assert(false);
569  case Qt::ToolTipRole:
570  return formatTooltip(rec);
571  case Qt::TextAlignmentRole:
572  return column_alignments[index.column()];
573  case Qt::ForegroundRole:
574  // Use the "danger" color for abandoned transactions
576  {
577  return COLOR_TX_STATUS_DANGER;
578  }
579  // Non-confirmed (but not immature) as transactions are grey
581  {
582  return COLOR_UNCONFIRMED;
583  }
584  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
585  {
586  return COLOR_NEGATIVE;
587  }
588  if(index.column() == ToAddress)
589  {
590  return addressColor(rec);
591  }
592  break;
593  case TypeRole:
594  return rec->type;
595  case DateRole:
596  return QDateTime::fromSecsSinceEpoch(rec->time);
597  case WatchonlyRole:
598  return rec->involvesWatchAddress;
600  return txWatchonlyDecoration(rec);
601  case LongDescriptionRole:
603  case AddressRole:
604  return QString::fromStdString(rec->address);
605  case LabelRole:
606  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
607  case AmountRole:
608  return qint64(rec->credit + rec->debit);
609  case TxHashRole:
610  return rec->getTxHash();
611  case TxHexRole:
612  return priv->getTxHex(walletModel->wallet(), rec);
613  case TxPlainTextRole:
614  {
615  QString details;
616  QDateTime date = QDateTime::fromSecsSinceEpoch(rec->time);
617  QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
618 
619  details.append(date.toString("M/d/yy HH:mm"));
620  details.append(" ");
621  details.append(formatTxStatus(rec));
622  details.append(". ");
623  if(!formatTxType(rec).isEmpty()) {
624  details.append(formatTxType(rec));
625  details.append(" ");
626  }
627  if(!rec->address.empty()) {
628  if(txLabel.isEmpty())
629  details.append(tr("(no label)") + " ");
630  else {
631  details.append("(");
632  details.append(txLabel);
633  details.append(") ");
634  }
635  details.append(QString::fromStdString(rec->address));
636  details.append(" ");
637  }
638  details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
639  return details;
640  }
641  case ConfirmedRole:
642  return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
643  case FormattedAmountRole:
644  // Used for copy/export, so don't include separators
646  case StatusRole:
647  return rec->status.status;
648  }
649  return QVariant();
650 }
651 
652 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
653 {
654  if(orientation == Qt::Horizontal)
655  {
656  if(role == Qt::DisplayRole)
657  {
658  return columns[section];
659  }
660  else if (role == Qt::TextAlignmentRole)
661  {
662  return column_alignments[section];
663  } else if (role == Qt::ToolTipRole)
664  {
665  switch(section)
666  {
667  case Status:
668  return tr("Transaction status. Hover over this field to show number of confirmations.");
669  case Date:
670  return tr("Date and time that the transaction was received.");
671  case Type:
672  return tr("Type of transaction.");
673  case Watchonly:
674  return tr("Whether or not a watch-only address is involved in this transaction.");
675  case ToAddress:
676  return tr("User-defined intent/purpose of the transaction.");
677  case Amount:
678  return tr("Amount removed from or added to balance.");
679  }
680  }
681  }
682  return QVariant();
683 }
684 
685 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
686 {
687  Q_UNUSED(parent);
689  if(data)
690  {
691  return createIndex(row, column, data);
692  }
693  return QModelIndex();
694 }
695 
697 {
698  // emit dataChanged to update Amount column with the current unit
700  Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
701 }
702 
704 {
705  // Find transaction in wallet
706  // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
707  bool showTransaction = TransactionRecord::showTransaction();
708 
709  TransactionNotification notification(hash, status, showTransaction);
710 
711  if (!m_loaded || m_loading)
712  {
713  vQueueNotifications.push_back(notification);
714  return;
715  }
716  notification.invoke(parent);
717 }
718 
720 {
721  if (!m_loaded || m_loading) return;
722 
723  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
724  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
725  assert(invoked);
726  }
727  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
728  {
729  if (vQueueNotifications.size() - i <= 10) {
730  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
731  assert(invoked);
732  }
733 
734  vQueueNotifications[i].invoke(parent);
735  }
736  vQueueNotifications.clear();
737 }
738 
740 {
741  // Connect signals to wallet
743  m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
744  priv->m_loading = progress < 100;
746  });
747 }
748 
750 {
751  // Disconnect signals from wallet
752  m_handler_transaction_changed->disconnect();
753  m_handler_show_progress->disconnect();
754 }
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:104
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
Local cache of wallet sorted by transaction hash.
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:48
AddressTableModel * getAddressTableModel() const
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
OptionsModel * getOptionsModel() const
uint256 getLastBlockProcessed() const
interfaces::Node & node() const
Definition: walletmodel.h:137
constexpr bool IsNull() const
Definition: uint256.h:42
void SetHex(const char *psz)
Definition: uint256.cpp:21
std::string ToString() const
Definition: uint256.cpp:55
std::string GetHex() const
Definition: uint256.cpp:11
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:70
Interface for accessing a wallet.
Definition: wallet.h:61
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:106
std::string EncodeHexTx(const CTransaction &tx)
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:94
Definition: init.h:25
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:393
Updated transaction status.
Definition: wallet.h:411
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
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())