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