Bitcoin Core  0.20.99
P2P Digital Currency
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2019 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 // Private implementation
59 {
60 public:
62  parent(_parent)
63  {
64  }
65 
67 
68  /* Local cache of wallet.
69  * As it is in the same order as the CWallet, by definition
70  * this is sorted by sha256.
71  */
72  QList<TransactionRecord> cachedWallet;
73 
74  /* Query entire wallet anew from core.
75  */
77  {
78  qDebug() << "TransactionTablePriv::refreshWallet";
79  cachedWallet.clear();
80  {
81  for (const auto& wtx : wallet.getWalletTxs()) {
83  cachedWallet.append(TransactionRecord::decomposeTransaction(wtx));
84  }
85  }
86  }
87  }
88 
89  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
90  with that of the core.
91 
92  Call with transaction that was added, removed or changed.
93  */
94  void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
95  {
96  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
97 
98  // Find bounds of this transaction in model
99  QList<TransactionRecord>::iterator lower = std::lower_bound(
100  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
101  QList<TransactionRecord>::iterator upper = std::upper_bound(
102  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
103  int lowerIndex = (lower - cachedWallet.begin());
104  int upperIndex = (upper - cachedWallet.begin());
105  bool inModel = (lower != upper);
106 
107  if(status == CT_UPDATED)
108  {
109  if(showTransaction && !inModel)
110  status = CT_NEW; /* Not in model, but want to show, treat as new */
111  if(!showTransaction && inModel)
112  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
113  }
114 
115  qDebug() << " inModel=" + QString::number(inModel) +
116  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
117  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
118 
119  switch(status)
120  {
121  case CT_NEW:
122  if(inModel)
123  {
124  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
125  break;
126  }
127  if(showTransaction)
128  {
129  // Find transaction in wallet
130  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
131  if(!wtx.tx)
132  {
133  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
134  break;
135  }
136  // Added -- insert at the right position
137  QList<TransactionRecord> toInsert =
139  if(!toInsert.isEmpty()) /* only if something to insert */
140  {
141  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
142  int insert_idx = lowerIndex;
143  for (const TransactionRecord &rec : toInsert)
144  {
145  cachedWallet.insert(insert_idx, rec);
146  insert_idx += 1;
147  }
148  parent->endInsertRows();
149  }
150  }
151  break;
152  case CT_DELETED:
153  if(!inModel)
154  {
155  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
156  break;
157  }
158  // Removed -- remove entire transaction from table
159  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
160  cachedWallet.erase(lower, upper);
161  parent->endRemoveRows();
162  break;
163  case CT_UPDATED:
164  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
165  // visible transactions.
166  for (int i = lowerIndex; i < upperIndex; i++) {
167  TransactionRecord *rec = &cachedWallet[i];
168  rec->status.needsUpdate = true;
169  }
170  break;
171  }
172  }
173 
174  int size()
175  {
176  return cachedWallet.size();
177  }
178 
179  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
180  {
181  if (idx >= 0 && idx < cachedWallet.size()) {
182  TransactionRecord *rec = &cachedWallet[idx];
183 
184  // If a status update is needed (blocks came in since last check),
185  // try to update the status of this transaction from the wallet.
186  // Otherwise, simply re-use the cached status.
188  int numBlocks;
189  int64_t block_time;
190  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
191  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
192  }
193  return rec;
194  }
195  return nullptr;
196  }
197 
198  QString describe(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
199  {
200  return TransactionDesc::toHTML(node, wallet, rec, unit);
201  }
202 
204  {
205  auto tx = wallet.getTx(rec->hash);
206  if (tx) {
207  std::string strHex = EncodeHexTx(*tx);
208  return QString::fromStdString(strHex);
209  }
210  return QString();
211  }
212 };
213 
215  QAbstractTableModel(parent),
216  walletModel(parent),
217  priv(new TransactionTablePriv(this)),
218  fProcessingQueuedTransactions(false),
219  platformStyle(_platformStyle)
220 {
221  columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
223 
225 
227 }
228 
230 {
232  delete priv;
233 }
234 
237 {
239  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
240 }
241 
242 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
243 {
244  uint256 updated;
245  updated.SetHex(hash.toStdString());
246 
247  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
248 }
249 
251 {
252  // Blocks came in since last poll.
253  // Invalidate status (number of confirmations) and (possibly) description
254  // for all rows. Qt is smart enough to only actually request the data for the
255  // visible rows.
256  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
257  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
258 }
259 
260 int TransactionTableModel::rowCount(const QModelIndex &parent) const
261 {
262  Q_UNUSED(parent);
263  return priv->size();
264 }
265 
266 int TransactionTableModel::columnCount(const QModelIndex &parent) const
267 {
268  Q_UNUSED(parent);
269  return columns.length();
270 }
271 
273 {
274  QString status;
275 
276  switch(wtx->status.status)
277  {
279  status = tr("Open for %n more block(s)","",wtx->status.open_for);
280  break;
282  status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
283  break;
285  status = tr("Unconfirmed");
286  break;
288  status = tr("Abandoned");
289  break;
291  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
292  break;
294  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
295  break;
297  status = tr("Conflicted");
298  break;
300  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
301  break;
303  status = tr("Generated but not accepted");
304  break;
305  }
306 
307  return status;
308 }
309 
311 {
312  if(wtx->time)
313  {
314  return GUIUtil::dateTimeStr(wtx->time);
315  }
316  return QString();
317 }
318 
319 /* Look up address in address book, if found return label (address)
320  otherwise just return (address)
321  */
322 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
323 {
324  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
325  QString description;
326  if(!label.isEmpty())
327  {
328  description += label;
329  }
330  if(label.isEmpty() || tooltip)
331  {
332  description += QString(" (") + QString::fromStdString(address) + QString(")");
333  }
334  return description;
335 }
336 
338 {
339  switch(wtx->type)
340  {
342  return tr("Received with");
344  return tr("Received from");
347  return tr("Sent to");
349  return tr("Payment to yourself");
351  return tr("Mined");
352  default:
353  return QString();
354  }
355 }
356 
358 {
359  switch(wtx->type)
360  {
362  return QIcon(":/icons/tx_mined");
365  return QIcon(":/icons/tx_input");
368  return QIcon(":/icons/tx_output");
369  default:
370  return QIcon(":/icons/tx_inout");
371  }
372 }
373 
374 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
375 {
376  QString watchAddress;
377  if (tooltip) {
378  // Mark transactions involving watch-only addresses by adding " (watch-only)"
379  watchAddress = wtx->involvesWatchAddress ? QString(" (") + tr("watch-only") + QString(")") : "";
380  }
381 
382  switch(wtx->type)
383  {
385  return QString::fromStdString(wtx->address) + watchAddress;
389  return lookupAddress(wtx->address, tooltip) + watchAddress;
391  return QString::fromStdString(wtx->address) + watchAddress;
393  return lookupAddress(wtx->address, tooltip) + watchAddress;
394  default:
395  return tr("(n/a)") + watchAddress;
396  }
397 }
398 
400 {
401  // Show addresses without label in a less visible color
402  switch(wtx->type)
403  {
407  {
408  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
409  if(label.isEmpty())
410  return COLOR_BAREADDRESS;
411  } break;
413  return COLOR_BAREADDRESS;
414  default:
415  break;
416  }
417  return QVariant();
418 }
419 
420 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
421 {
422  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
423  if(showUnconfirmed)
424  {
425  if(!wtx->status.countsForBalance)
426  {
427  str = QString("[") + str + QString("]");
428  }
429  }
430  return QString(str);
431 }
432 
434 {
435  switch(wtx->status.status)
436  {
441  return QIcon(":/icons/transaction_0");
443  return QIcon(":/icons/transaction_abandoned");
445  switch(wtx->status.depth)
446  {
447  case 1: return QIcon(":/icons/transaction_1");
448  case 2: return QIcon(":/icons/transaction_2");
449  case 3: return QIcon(":/icons/transaction_3");
450  case 4: return QIcon(":/icons/transaction_4");
451  default: return QIcon(":/icons/transaction_5");
452  };
454  return QIcon(":/icons/transaction_confirmed");
456  return QIcon(":/icons/transaction_conflicted");
458  int total = wtx->status.depth + wtx->status.matures_in;
459  int part = (wtx->status.depth * 4 / total) + 1;
460  return QIcon(QString(":/icons/transaction_%1").arg(part));
461  }
463  return QIcon(":/icons/transaction_0");
464  default:
465  return COLOR_BLACK;
466  }
467 }
468 
470 {
471  if (wtx->involvesWatchAddress)
472  return QIcon(":/icons/eye");
473  else
474  return QVariant();
475 }
476 
478 {
479  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
482  {
483  tooltip += QString(" ") + formatTxToAddress(rec, true);
484  }
485  return tooltip;
486 }
487 
488 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
489 {
490  if(!index.isValid())
491  return QVariant();
492  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
493 
494  switch(role)
495  {
496  case RawDecorationRole:
497  switch(index.column())
498  {
499  case Status:
500  return txStatusDecoration(rec);
501  case Watchonly:
502  return txWatchonlyDecoration(rec);
503  case ToAddress:
504  return txAddressDecoration(rec);
505  }
506  break;
507  case Qt::DecorationRole:
508  {
509  QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
510  return platformStyle->TextColorIcon(icon);
511  }
512  case Qt::DisplayRole:
513  switch(index.column())
514  {
515  case Date:
516  return formatTxDate(rec);
517  case Type:
518  return formatTxType(rec);
519  case ToAddress:
520  return formatTxToAddress(rec, false);
521  case Amount:
523  }
524  break;
525  case Qt::EditRole:
526  // Edit role is used for sorting, so return the unformatted values
527  switch(index.column())
528  {
529  case Status:
530  return QString::fromStdString(rec->status.sortKey);
531  case Date:
532  return rec->time;
533  case Type:
534  return formatTxType(rec);
535  case Watchonly:
536  return (rec->involvesWatchAddress ? 1 : 0);
537  case ToAddress:
538  return formatTxToAddress(rec, true);
539  case Amount:
540  return qint64(rec->credit + rec->debit);
541  }
542  break;
543  case Qt::ToolTipRole:
544  return formatTooltip(rec);
545  case Qt::TextAlignmentRole:
546  return column_alignments[index.column()];
547  case Qt::ForegroundRole:
548  // Use the "danger" color for abandoned transactions
550  {
551  return COLOR_TX_STATUS_DANGER;
552  }
553  // Non-confirmed (but not immature) as transactions are grey
555  {
556  return COLOR_UNCONFIRMED;
557  }
558  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
559  {
560  return COLOR_NEGATIVE;
561  }
562  if(index.column() == ToAddress)
563  {
564  return addressColor(rec);
565  }
566  break;
567  case TypeRole:
568  return rec->type;
569  case DateRole:
570  return QDateTime::fromTime_t(static_cast<uint>(rec->time));
571  case WatchonlyRole:
572  return rec->involvesWatchAddress;
574  return txWatchonlyDecoration(rec);
575  case LongDescriptionRole:
577  case AddressRole:
578  return QString::fromStdString(rec->address);
579  case LabelRole:
580  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
581  case AmountRole:
582  return qint64(rec->credit + rec->debit);
583  case TxHashRole:
584  return rec->getTxHash();
585  case TxHexRole:
586  return priv->getTxHex(walletModel->wallet(), rec);
587  case TxPlainTextRole:
588  {
589  QString details;
590  QDateTime date = QDateTime::fromTime_t(static_cast<uint>(rec->time));
591  QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
592 
593  details.append(date.toString("M/d/yy HH:mm"));
594  details.append(" ");
595  details.append(formatTxStatus(rec));
596  details.append(". ");
597  if(!formatTxType(rec).isEmpty()) {
598  details.append(formatTxType(rec));
599  details.append(" ");
600  }
601  if(!rec->address.empty()) {
602  if(txLabel.isEmpty())
603  details.append(tr("(no label)") + " ");
604  else {
605  details.append("(");
606  details.append(txLabel);
607  details.append(") ");
608  }
609  details.append(QString::fromStdString(rec->address));
610  details.append(" ");
611  }
612  details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
613  return details;
614  }
615  case ConfirmedRole:
616  return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
617  case FormattedAmountRole:
618  // Used for copy/export, so don't include separators
620  case StatusRole:
621  return rec->status.status;
622  }
623  return QVariant();
624 }
625 
626 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
627 {
628  if(orientation == Qt::Horizontal)
629  {
630  if(role == Qt::DisplayRole)
631  {
632  return columns[section];
633  }
634  else if (role == Qt::TextAlignmentRole)
635  {
636  return column_alignments[section];
637  } else if (role == Qt::ToolTipRole)
638  {
639  switch(section)
640  {
641  case Status:
642  return tr("Transaction status. Hover over this field to show number of confirmations.");
643  case Date:
644  return tr("Date and time that the transaction was received.");
645  case Type:
646  return tr("Type of transaction.");
647  case Watchonly:
648  return tr("Whether or not a watch-only address is involved in this transaction.");
649  case ToAddress:
650  return tr("User-defined intent/purpose of the transaction.");
651  case Amount:
652  return tr("Amount removed from or added to balance.");
653  }
654  }
655  }
656  return QVariant();
657 }
658 
659 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
660 {
661  Q_UNUSED(parent);
663  if(data)
664  {
665  return createIndex(row, column, data);
666  }
667  return QModelIndex();
668 }
669 
671 {
672  // emit dataChanged to update Amount column with the current unit
674  Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
675 }
676 
677 // queue notifications to show a non freezing progress dialog e.g. for rescan
679 {
680 public:
682  TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
683  hash(_hash), status(_status), showTransaction(_showTransaction) {}
684 
685  void invoke(QObject *ttm)
686  {
687  QString strHash = QString::fromStdString(hash.GetHex());
688  qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
689  bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
690  Q_ARG(QString, strHash),
691  Q_ARG(int, status),
692  Q_ARG(bool, showTransaction));
693  assert(invoked);
694  }
695 private:
699 };
700 
701 static bool fQueueNotifications = false;
702 static std::vector< TransactionNotification > vQueueNotifications;
703 
704 static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 &hash, ChangeType status)
705 {
706  // Find transaction in wallet
707  // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
708  bool showTransaction = TransactionRecord::showTransaction();
709 
710  TransactionNotification notification(hash, status, showTransaction);
711 
713  {
714  vQueueNotifications.push_back(notification);
715  return;
716  }
717  notification.invoke(ttm);
718 }
719 
720 static void ShowProgress(TransactionTableModel *ttm, const std::string &title, int nProgress)
721 {
722  if (nProgress == 0)
723  fQueueNotifications = true;
724 
725  if (nProgress == 100)
726  {
727  fQueueNotifications = false;
728  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
729  bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
730  assert(invoked);
731  }
732  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
733  {
734  if (vQueueNotifications.size() - i <= 10) {
735  bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
736  assert(invoked);
737  }
738 
739  vQueueNotifications[i].invoke(ttm);
740  }
741  std::vector<TransactionNotification >().swap(vQueueNotifications); // clear
742  }
743 }
744 
746 {
747  // Connect signals to wallet
748  m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
749  m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
750 }
751 
753 {
754  // Disconnect signals from wallet
755  m_handler_transaction_changed->disconnect();
756  m_handler_show_progress->disconnect();
757 }
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
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)
static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 &hash, ChangeType status)
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)
QString describe(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:68
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
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:84
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
static void ShowProgress(TransactionTableModel *ttm, const std::string &title, int nProgress)
#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
static std::vector< TransactionNotification > vQueueNotifications
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.
QString getTxHex(interfaces::Wallet &wallet, TransactionRecord *rec)
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:132
Label of address related to transaction.
QString formatTxStatus(const TransactionRecord *wtx) const
static bool fQueueNotifications
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