Bitcoin Core  31.0.0
P2P Digital Currency
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-present 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, /*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 Txid &b) const
52  {
53  return a.hash < b;
54  }
55  bool operator()(const Txid &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:
65  TransactionNotification() = default;
66  TransactionNotification(Txid _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 
97  QList<TransactionRecord> cachedWallet;
98 
100  bool m_loaded = false;
102  bool m_loading = false;
103  std::vector< TransactionNotification > vQueueNotifications;
104 
105  void NotifyTransactionChanged(const Txid& hash, ChangeType status);
106  void DispatchNotifications();
107 
108  /* Query entire wallet anew from core.
109  */
111  {
112  assert(!m_loaded);
113  {
114  for (const auto& wtx : wallet.getWalletTxs()) {
117  }
118  }
119  }
120  m_loaded = true;
122  }
123 
124  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
125  with that of the core.
126 
127  Call with transaction that was added, removed or changed.
128  */
129  void updateWallet(interfaces::Wallet& wallet, const Txid& hash, int status, bool showTransaction)
130  {
131  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
132 
133  // Find bounds of this transaction in model
134  QList<TransactionRecord>::iterator lower = std::lower_bound(
135  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
136  QList<TransactionRecord>::iterator upper = std::upper_bound(
137  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
138  int lowerIndex = (lower - cachedWallet.begin());
139  int upperIndex = (upper - cachedWallet.begin());
140  bool inModel = (lower != upper);
141 
142  if(status == CT_UPDATED)
143  {
144  if(showTransaction && !inModel)
145  status = CT_NEW; /* Not in model, but want to show, treat as new */
146  if(!showTransaction && inModel)
147  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
148  }
149 
150  qDebug() << " inModel=" + QString::number(inModel) +
151  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
152  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
153 
154  switch(status)
155  {
156  case CT_NEW:
157  if(inModel)
158  {
159  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
160  break;
161  }
162  if(showTransaction)
163  {
164  // Find transaction in wallet
165  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
166  if(!wtx.tx)
167  {
168  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
169  break;
170  }
171  // Added -- insert at the right position
172  QList<TransactionRecord> toInsert =
174  if(!toInsert.isEmpty()) /* only if something to insert */
175  {
176  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
177  int insert_idx = lowerIndex;
178  for (const TransactionRecord &rec : toInsert)
179  {
180  cachedWallet.insert(insert_idx, rec);
181  insert_idx += 1;
182  }
183  parent->endInsertRows();
184  }
185  }
186  break;
187  case CT_DELETED:
188  if(!inModel)
189  {
190  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
191  break;
192  }
193  // Removed -- remove entire transaction from table
194  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
195  cachedWallet.erase(lower, upper);
196  parent->endRemoveRows();
197  break;
198  case CT_UPDATED:
199  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
200  // visible transactions.
201  for (int i = lowerIndex; i < upperIndex; i++) {
202  TransactionRecord *rec = &cachedWallet[i];
203  rec->status.needsUpdate = true;
204  }
205  break;
206  }
207  }
208 
209  int size()
210  {
211  return cachedWallet.size();
212  }
213 
214  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
215  {
216  if (idx >= 0 && idx < cachedWallet.size()) {
217  TransactionRecord *rec = &cachedWallet[idx];
218 
219  // If a status update is needed (blocks came in since last check),
220  // try to update the status of this transaction from the wallet.
221  // Otherwise, simply reuse the cached status.
223  int numBlocks;
224  int64_t block_time;
225  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
226  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
227  }
228  return rec;
229  }
230  return nullptr;
231  }
232 
234  {
235  return TransactionDesc::toHTML(node, wallet, rec, unit);
236  }
237 
239  {
240  auto tx = wallet.getTx(rec->hash);
241  if (tx) {
242  std::string strHex = EncodeHexTx(*tx);
243  return QString::fromStdString(strHex);
244  }
245  return QString();
246  }
247 };
248 
250  QAbstractTableModel(parent),
251  walletModel(parent),
252  priv(new TransactionTablePriv(this)),
253  platformStyle(_platformStyle)
254 {
256 
257  columns << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
259 
261 }
262 
264 {
266  delete priv;
267 }
268 
271 {
273  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
274 }
275 
276 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
277 {
278  Txid updated = Txid::FromHex(hash.toStdString()).value();
279 
280  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
281 }
282 
284 {
285  // Blocks came in since last poll.
286  // Invalidate status (number of confirmations) and (possibly) description
287  // for all rows. Qt is smart enough to only actually request the data for the
288  // visible rows.
289  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
290  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
291 }
292 
293 int TransactionTableModel::rowCount(const QModelIndex &parent) const
294 {
295  if (parent.isValid()) {
296  return 0;
297  }
298  return priv->size();
299 }
300 
301 int TransactionTableModel::columnCount(const QModelIndex &parent) const
302 {
303  if (parent.isValid()) {
304  return 0;
305  }
306  return columns.length();
307 }
308 
310 {
311  QString status;
312 
313  switch(wtx->status.status)
314  {
316  status = tr("Unconfirmed");
317  break;
319  status = tr("Abandoned");
320  break;
322  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
323  break;
325  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
326  break;
328  status = tr("Conflicted");
329  break;
331  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
332  break;
334  status = tr("Generated but not accepted");
335  break;
336  }
337 
338  return status;
339 }
340 
342 {
343  if(wtx->time)
344  {
345  return GUIUtil::dateTimeStr(wtx->time);
346  }
347  return QString();
348 }
349 
350 /* Look up address in address book, if found return label (address)
351  otherwise just return (address)
352  */
353 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
354 {
355  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
356  QString description;
357  if(!label.isEmpty())
358  {
359  description += label;
360  }
361  if(label.isEmpty() || tooltip)
362  {
363  description += QString(" (") + QString::fromStdString(address) + QString(")");
364  }
365  return description;
366 }
367 
369 {
370  switch(wtx->type)
371  {
373  return tr("Received with");
375  return tr("Received from");
378  return tr("Sent to");
380  return tr("Mined");
381  default:
382  return QString();
383  }
384 }
385 
387 {
388  switch(wtx->type)
389  {
391  return QIcon(":/icons/tx_mined");
394  return QIcon(":/icons/tx_input");
397  return QIcon(":/icons/tx_output");
398  default:
399  return QIcon(":/icons/tx_inout");
400  }
401 }
402 
403 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
404 {
405  switch(wtx->type)
406  {
408  return QString::fromStdString(wtx->address);
412  return lookupAddress(wtx->address, tooltip);
414  return QString::fromStdString(wtx->address);
415  default:
416  return tr("(n/a)");
417  }
418 }
419 
421 {
422  // Show addresses without label in a less visible color
423  switch(wtx->type)
424  {
428  {
429  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
430  if(label.isEmpty())
431  return COLOR_BAREADDRESS;
432  } break;
433  default:
434  break;
435  }
436  return QVariant();
437 }
438 
439 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
440 {
441  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
442  if(showUnconfirmed)
443  {
444  if(!wtx->status.countsForBalance)
445  {
446  str = QString("[") + str + QString("]");
447  }
448  }
449  return QString(str);
450 }
451 
453 {
454  switch(wtx->status.status)
455  {
457  return QIcon(":/icons/transaction_0");
459  return QIcon(":/icons/transaction_abandoned");
461  switch(wtx->status.depth)
462  {
463  case 1: return QIcon(":/icons/transaction_1");
464  case 2: return QIcon(":/icons/transaction_2");
465  case 3: return QIcon(":/icons/transaction_3");
466  case 4: return QIcon(":/icons/transaction_4");
467  default: return QIcon(":/icons/transaction_5");
468  };
470  return QIcon(":/icons/transaction_confirmed");
472  return QIcon(":/icons/transaction_conflicted");
474  int total = wtx->status.depth + wtx->status.matures_in;
475  int part = (wtx->status.depth * 4 / total) + 1;
476  return QIcon(QString(":/icons/transaction_%1").arg(part));
477  }
479  return QIcon(":/icons/transaction_0");
480  default:
481  return COLOR_BLACK;
482  }
483 }
484 
486 {
487  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
490  {
491  tooltip += QString(" ") + formatTxToAddress(rec, true);
492  }
493  return tooltip;
494 }
495 
496 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
497 {
498  if(!index.isValid())
499  return QVariant();
500  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
501 
502  const auto column = static_cast<ColumnIndex>(index.column());
503  switch (role) {
504  case RawDecorationRole:
505  switch (column) {
506  case Status:
507  return txStatusDecoration(rec);
508  case Date: return {};
509  case Type: return {};
510  case ToAddress:
511  return txAddressDecoration(rec);
512  case Amount: return {};
513  } // no default case, so the compiler can warn about missing cases
514  assert(false);
515  case Qt::DecorationRole:
516  {
517  QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
518  return platformStyle->TextColorIcon(icon);
519  }
520  case Qt::DisplayRole:
521  switch (column) {
522  case Status: return {};
523  case Date:
524  return formatTxDate(rec);
525  case Type:
526  return formatTxType(rec);
527  case ToAddress:
528  return formatTxToAddress(rec, false);
529  case Amount:
531  } // no default case, so the compiler can warn about missing cases
532  assert(false);
533  case Qt::EditRole:
534  // Edit role is used for sorting, so return the unformatted values
535  switch (column) {
536  case Status:
537  return QString::fromStdString(rec->status.sortKey);
538  case Date:
539  return QString::fromStdString(strprintf("%020s-%s", rec->time, rec->status.sortKey));
540  case Type:
541  return formatTxType(rec);
542  case ToAddress:
543  return formatTxToAddress(rec, true);
544  case Amount:
545  return qint64(rec->credit + rec->debit);
546  } // no default case, so the compiler can warn about missing cases
547  assert(false);
548  case Qt::ToolTipRole:
549  return formatTooltip(rec);
550  case Qt::TextAlignmentRole:
551  return column_alignments[index.column()];
552  case Qt::ForegroundRole:
553  // Use the "danger" color for abandoned transactions
555  {
556  return COLOR_TX_STATUS_DANGER;
557  }
558  // Non-confirmed (but not immature) as transactions are grey
560  {
561  return COLOR_UNCONFIRMED;
562  }
563  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
564  {
565  return COLOR_NEGATIVE;
566  }
567  if(index.column() == ToAddress)
568  {
569  return addressColor(rec);
570  }
571  break;
572  case TypeRole:
573  return rec->type;
574  case DateRole:
575  return QDateTime::fromSecsSinceEpoch(rec->time);
576  case LongDescriptionRole:
578  case AddressRole:
579  return QString::fromStdString(rec->address);
580  case LabelRole:
581  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
582  case AmountRole:
583  return qint64(rec->credit + rec->debit);
584  case TxHashRole:
585  return rec->getTxHash();
586  case TxHexRole:
587  return priv->getTxHex(walletModel->wallet(), rec);
588  case TxPlainTextRole:
589  {
590  QString details;
591  QDateTime date = QDateTime::fromSecsSinceEpoch(rec->time);
592  QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
593 
594  details.append(date.toString("M/d/yy HH:mm"));
595  details.append(" ");
596  details.append(formatTxStatus(rec));
597  details.append(". ");
598  if(!formatTxType(rec).isEmpty()) {
599  details.append(formatTxType(rec));
600  details.append(" ");
601  }
602  if(!rec->address.empty()) {
603  if(txLabel.isEmpty())
604  details.append(tr("(no label)") + " ");
605  else {
606  details.append("(");
607  details.append(txLabel);
608  details.append(") ");
609  }
610  details.append(QString::fromStdString(rec->address));
611  details.append(" ");
612  }
613  details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
614  return details;
615  }
616  case ConfirmedRole:
617  return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
618  case FormattedAmountRole:
619  // Used for copy/export, so don't include separators
621  case StatusRole:
622  return rec->status.status;
623  }
624  return QVariant();
625 }
626 
627 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
628 {
629  if(orientation == Qt::Horizontal)
630  {
631  if(role == Qt::DisplayRole)
632  {
633  return columns[section];
634  }
635  else if (role == Qt::TextAlignmentRole)
636  {
637  return column_alignments[section];
638  } else if (role == Qt::ToolTipRole)
639  {
640  switch(section)
641  {
642  case Status:
643  return tr("Transaction status. Hover over this field to show number of confirmations.");
644  case Date:
645  return tr("Date and time that the transaction was received.");
646  case Type:
647  return tr("Type of transaction.");
648  case ToAddress:
649  return tr("User-defined intent/purpose of the transaction.");
650  case Amount:
651  return tr("Amount removed from or added to balance.");
652  }
653  }
654  }
655  return QVariant();
656 }
657 
658 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
659 {
660  Q_UNUSED(parent);
662  if(data)
663  {
664  return createIndex(row, column, data);
665  }
666  return QModelIndex();
667 }
668 
670 {
671  // emit dataChanged to update Amount column with the current unit
673  Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
674 }
675 
677 {
678  // Find transaction in wallet
679  // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
680  bool showTransaction = TransactionRecord::showTransaction();
681 
682  TransactionNotification notification(hash, status, showTransaction);
683 
684  if (!m_loaded || m_loading)
685  {
686  vQueueNotifications.push_back(notification);
687  return;
688  }
689  notification.invoke(parent);
690 }
691 
693 {
694  if (!m_loaded || m_loading) return;
695 
696  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
697  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
698  assert(invoked);
699  }
700  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
701  {
702  if (vQueueNotifications.size() - i <= 10) {
703  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
704  assert(invoked);
705  }
706 
707  vQueueNotifications[i].invoke(parent);
708  }
709  vQueueNotifications.clear();
710 }
711 
713 {
714  // Connect signals to wallet
716  priv->NotifyTransactionChanged(hash, status);
717  });
718  m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
719  priv->m_loading = progress < 100;
721  });
722 }
723 
725 {
726  // Disconnect signals from wallet
727  m_handler_transaction_changed->disconnect();
728  m_handler_show_progress->disconnect();
729 }
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...
std::string GetHex() const
TransactionRecord * index(interfaces::Wallet &wallet, const uint256 &cur_block_hash, const int idx)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
OptionsModel * getOptionsModel() const
Unit
Bitcoin units.
Definition: bitcoinunits.h:42
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
Transaction status (TransactionRecord::Status)
Generated (mined) transactions.
assert(!tx.IsCoinBase())
TransactionNotification()=default
QString getTxHash() const
Return the unique identifier for this transaction (part)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
static int column_alignments[]
QString formatTooltip(const TransactionRecord *rec) const
void updateTransaction(const QString &hash, int status, bool showTransaction)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:90
Mined but not accepted.
TransactionTablePriv(TransactionTableModel *_parent)
static QList< TransactionRecord > decomposeTransaction(const interfaces::WalletTx &wtx)
QVariant txStatusDecoration(const TransactionRecord *wtx) const
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
BitcoinUnit getDisplayUnit() const
Definition: optionsmodel.h:103
int columnCount(const QModelIndex &parent) const override
CTransactionRef tx
Definition: wallet.h:383
QIcon TextColorIcon(const QIcon &icon) const
Colorize an icon (given object) with the text color.
Transaction data, hex-encoded.
TransactionTableModel * parent
QString describe(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, BitcoinUnit unit)
int rowCount(const QModelIndex &parent) const override
TransactionTablePriv * priv
bool operator()(const TransactionRecord &a, const Txid &b) const
void updateStatus(const interfaces::WalletTxStatus &wtx, const uint256 &block_hash, int numBlocks, int64_t block_time)
Update status from core wallet tx.
QList< TransactionRecord > cachedWallet
Local cache of wallet sorted by transaction hash.
std::string sortKey
Sorting key based on status.
uint256 getLastBlockProcessed() const
void displayUnitChanged(BitcoinUnit unit)
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
static QString format(Unit unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
std::vector< TransactionNotification > vQueueNotifications
#define COLOR_TX_STATUS_DANGER
Definition: guiconstants.h:37
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:65
std::string ToString() const
Have 6 or more confirmations (normal tx) or fully mature (mined tx)
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.
#define COLOR_BLACK
Definition: guiconstants.h:39
interfaces::Node & node() const
Definition: walletmodel.h:137
UI model for the transaction table of a wallet.
#define COLOR_UNCONFIRMED
Definition: guiconstants.h:31
constexpr bool IsNull() const
Definition: uint256.h:48
void refreshWallet(interfaces::Wallet &wallet)
bool operator()(const Txid &a, const TransactionRecord &b) const
QString lookupAddress(const std::string &address, bool tooltip) const
Definition: messages.h:21
void NotifyTransactionChanged(const Txid &hash, ChangeType status)
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:195
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
bool m_loading
True when transactions are being notified, for instance when scanning.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:48
std::string EncodeHexTx(const CTransaction &tx)
Definition: core_io.cpp:402
bool countsForBalance
Transaction counts towards available balance.
QString getTxHex(interfaces::Wallet &wallet, TransactionRecord *rec)
Label of address related to transaction.
bool m_loaded
True when model finishes loading all wallet transactions on start.
static QString getAmountColumnTitle(Unit unit)
Gets title for amount column including current display unit if optionsModel reference available */...
QString formatTxStatus(const TransactionRecord *wtx) const
AddressTableModel * getAddressTableModel() const
Normal (sent/received) transactions.
QVariant addressColor(const TransactionRecord *wtx) const
void updateWallet(interfaces::Wallet &wallet, const Txid &hash, int status, bool showTransaction)
QVariant txAddressDecoration(const TransactionRecord *wtx) const
Confirmed, but waiting for the recommended number of confirmations.
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
Abandoned from the wallet.
TransactionNotification(Txid _hash, ChangeType _status, bool _showTransaction)
#define COLOR_BAREADDRESS
Definition: guiconstants.h:35
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:69
const PlatformStyle * platformStyle
Updated transaction status.
Definition: wallet.h:400
Conflicts with other transaction or mempool.
#define COLOR_NEGATIVE
Definition: guiconstants.h:33
static std::optional< transaction_identifier > FromHex(std::string_view hex)
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
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, BitcoinUnit unit)
QString formatTxDate(const TransactionRecord *wtx) const