Bitcoin Core 29.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
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>
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
36static 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
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{
65public:
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 }
80private:
84};
85
86// Private implementation
88{
89public:
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);
108
109 /* Query entire wallet anew from core.
110 */
112 {
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++) {
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
277void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
278{
279 Txid updated = Txid::FromHex(hash.toStdString()).value();
280
281 priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
282}
283
285{
286 // Blocks came in since last poll.
287 // Invalidate status (number of confirmations) and (possibly) description
288 // for all rows. Qt is smart enough to only actually request the data for the
289 // visible rows.
290 Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
291 Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
292}
293
294int TransactionTableModel::rowCount(const QModelIndex &parent) const
295{
296 if (parent.isValid()) {
297 return 0;
298 }
299 return priv->size();
300}
301
302int TransactionTableModel::columnCount(const QModelIndex &parent) const
303{
304 if (parent.isValid()) {
305 return 0;
306 }
307 return columns.length();
308}
309
311{
312 QString status;
313
314 switch(wtx->status.status)
315 {
317 status = tr("Unconfirmed");
318 break;
320 status = tr("Abandoned");
321 break;
323 status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
324 break;
326 status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
327 break;
329 status = tr("Conflicted");
330 break;
332 status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
333 break;
335 status = tr("Generated but not accepted");
336 break;
337 }
338
339 return status;
340}
341
343{
344 if(wtx->time)
345 {
346 return GUIUtil::dateTimeStr(wtx->time);
347 }
348 return QString();
349}
350
351/* Look up address in address book, if found return label (address)
352 otherwise just return (address)
353 */
354QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
355{
356 QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
357 QString description;
358 if(!label.isEmpty())
359 {
360 description += label;
361 }
362 if(label.isEmpty() || tooltip)
363 {
364 description += QString(" (") + QString::fromStdString(address) + QString(")");
365 }
366 return description;
367}
368
370{
371 switch(wtx->type)
372 {
374 return tr("Received with");
376 return tr("Received from");
379 return tr("Sent to");
381 return tr("Mined");
382 default:
383 return QString();
384 }
385}
386
388{
389 switch(wtx->type)
390 {
392 return QIcon(":/icons/tx_mined");
395 return QIcon(":/icons/tx_input");
398 return QIcon(":/icons/tx_output");
399 default:
400 return QIcon(":/icons/tx_inout");
401 }
402}
403
404QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
405{
406 QString watchAddress;
407 if (tooltip && wtx->involvesWatchAddress) {
408 // Mark transactions involving watch-only addresses by adding " (watch-only)"
409 watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')');
410 }
411
412 switch(wtx->type)
413 {
415 return QString::fromStdString(wtx->address) + watchAddress;
419 return lookupAddress(wtx->address, tooltip) + watchAddress;
421 return QString::fromStdString(wtx->address) + watchAddress;
422 default:
423 return tr("(n/a)") + watchAddress;
424 }
425}
426
428{
429 // Show addresses without label in a less visible color
430 switch(wtx->type)
431 {
435 {
436 QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
437 if(label.isEmpty())
438 return COLOR_BAREADDRESS;
439 } break;
440 default:
441 break;
442 }
443 return QVariant();
444}
445
446QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
447{
448 QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
449 if(showUnconfirmed)
450 {
451 if(!wtx->status.countsForBalance)
452 {
453 str = QString("[") + str + QString("]");
454 }
455 }
456 return QString(str);
457}
458
460{
461 switch(wtx->status.status)
462 {
464 return QIcon(":/icons/transaction_0");
466 return QIcon(":/icons/transaction_abandoned");
468 switch(wtx->status.depth)
469 {
470 case 1: return QIcon(":/icons/transaction_1");
471 case 2: return QIcon(":/icons/transaction_2");
472 case 3: return QIcon(":/icons/transaction_3");
473 case 4: return QIcon(":/icons/transaction_4");
474 default: return QIcon(":/icons/transaction_5");
475 };
477 return QIcon(":/icons/transaction_confirmed");
479 return QIcon(":/icons/transaction_conflicted");
481 int total = wtx->status.depth + wtx->status.matures_in;
482 int part = (wtx->status.depth * 4 / total) + 1;
483 return QIcon(QString(":/icons/transaction_%1").arg(part));
484 }
486 return QIcon(":/icons/transaction_0");
487 default:
488 return COLOR_BLACK;
489 }
490}
491
493{
494 if (wtx->involvesWatchAddress)
495 return QIcon(":/icons/eye");
496 else
497 return QVariant();
498}
499
501{
502 QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
505 {
506 tooltip += QString(" ") + formatTxToAddress(rec, true);
507 }
508 return tooltip;
509}
510
511QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
512{
513 if(!index.isValid())
514 return QVariant();
515 TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
516
517 const auto column = static_cast<ColumnIndex>(index.column());
518 switch (role) {
520 switch (column) {
521 case Status:
522 return txStatusDecoration(rec);
523 case Watchonly:
524 return txWatchonlyDecoration(rec);
525 case Date: return {};
526 case Type: return {};
527 case ToAddress:
528 return txAddressDecoration(rec);
529 case Amount: return {};
530 } // no default case, so the compiler can warn about missing cases
531 assert(false);
532 case Qt::DecorationRole:
533 {
534 QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
535 return platformStyle->TextColorIcon(icon);
536 }
537 case Qt::DisplayRole:
538 switch (column) {
539 case Status: return {};
540 case Watchonly: return {};
541 case Date:
542 return formatTxDate(rec);
543 case Type:
544 return formatTxType(rec);
545 case ToAddress:
546 return formatTxToAddress(rec, false);
547 case Amount:
549 } // no default case, so the compiler can warn about missing cases
550 assert(false);
551 case Qt::EditRole:
552 // Edit role is used for sorting, so return the unformatted values
553 switch (column) {
554 case Status:
555 return QString::fromStdString(rec->status.sortKey);
556 case Date:
557 return QString::fromStdString(strprintf("%020s-%s", rec->time, rec->status.sortKey));
558 case Type:
559 return formatTxType(rec);
560 case Watchonly:
561 return (rec->involvesWatchAddress ? 1 : 0);
562 case ToAddress:
563 return formatTxToAddress(rec, true);
564 case Amount:
565 return qint64(rec->credit + rec->debit);
566 } // no default case, so the compiler can warn about missing cases
567 assert(false);
568 case Qt::ToolTipRole:
569 return formatTooltip(rec);
570 case Qt::TextAlignmentRole:
571 return column_alignments[index.column()];
572 case Qt::ForegroundRole:
573 // Use the "danger" color for abandoned transactions
575 {
577 }
578 // Non-confirmed (but not immature) as transactions are grey
580 {
581 return COLOR_UNCONFIRMED;
582 }
583 if(index.column() == Amount && (rec->credit+rec->debit) < 0)
584 {
585 return COLOR_NEGATIVE;
586 }
587 if(index.column() == ToAddress)
588 {
589 return addressColor(rec);
590 }
591 break;
592 case TypeRole:
593 return rec->type;
594 case DateRole:
595 return QDateTime::fromSecsSinceEpoch(rec->time);
596 case WatchonlyRole:
597 return rec->involvesWatchAddress;
599 return txWatchonlyDecoration(rec);
602 case AddressRole:
603 return QString::fromStdString(rec->address);
604 case LabelRole:
605 return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
606 case AmountRole:
607 return qint64(rec->credit + rec->debit);
608 case TxHashRole:
609 return rec->getTxHash();
610 case TxHexRole:
611 return priv->getTxHex(walletModel->wallet(), rec);
612 case TxPlainTextRole:
613 {
614 QString details;
615 QDateTime date = QDateTime::fromSecsSinceEpoch(rec->time);
616 QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
617
618 details.append(date.toString("M/d/yy HH:mm"));
619 details.append(" ");
620 details.append(formatTxStatus(rec));
621 details.append(". ");
622 if(!formatTxType(rec).isEmpty()) {
623 details.append(formatTxType(rec));
624 details.append(" ");
625 }
626 if(!rec->address.empty()) {
627 if(txLabel.isEmpty())
628 details.append(tr("(no label)") + " ");
629 else {
630 details.append("(");
631 details.append(txLabel);
632 details.append(") ");
633 }
634 details.append(QString::fromStdString(rec->address));
635 details.append(" ");
636 }
637 details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
638 return details;
639 }
640 case ConfirmedRole:
641 return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
643 // Used for copy/export, so don't include separators
645 case StatusRole:
646 return rec->status.status;
647 }
648 return QVariant();
649}
650
651QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
652{
653 if(orientation == Qt::Horizontal)
654 {
655 if(role == Qt::DisplayRole)
656 {
657 return columns[section];
658 }
659 else if (role == Qt::TextAlignmentRole)
660 {
661 return column_alignments[section];
662 } else if (role == Qt::ToolTipRole)
663 {
664 switch(section)
665 {
666 case Status:
667 return tr("Transaction status. Hover over this field to show number of confirmations.");
668 case Date:
669 return tr("Date and time that the transaction was received.");
670 case Type:
671 return tr("Type of transaction.");
672 case Watchonly:
673 return tr("Whether or not a watch-only address is involved in this transaction.");
674 case ToAddress:
675 return tr("User-defined intent/purpose of the transaction.");
676 case Amount:
677 return tr("Amount removed from or added to balance.");
678 }
679 }
680 }
681 return QVariant();
682}
683
684QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
685{
686 Q_UNUSED(parent);
688 if(data)
689 {
690 return createIndex(row, column, data);
691 }
692 return QModelIndex();
693}
694
696{
697 // emit dataChanged to update Amount column with the current unit
699 Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
700}
701
703{
704 // Find transaction in wallet
705 // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
706 bool showTransaction = TransactionRecord::showTransaction();
707
708 TransactionNotification notification(hash, status, showTransaction);
709
710 if (!m_loaded || m_loading)
711 {
712 vQueueNotifications.push_back(notification);
713 return;
714 }
715 notification.invoke(parent);
716}
717
719{
720 if (!m_loaded || m_loading) return;
721
722 if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
723 bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
724 assert(invoked);
725 }
726 for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
727 {
728 if (vQueueNotifications.size() - i <= 10) {
729 bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
730 assert(invoked);
731 }
732
733 vQueueNotifications[i].invoke(parent);
734 }
735 vQueueNotifications.clear();
736}
737
739{
740 // Connect signals to wallet
742 m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
743 priv->m_loading = progress < 100;
745 });
746}
747
749{
750 // Disconnect signals from wallet
751 m_handler_transaction_changed->disconnect();
752 m_handler_show_progress->disconnect();
753}
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:103
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)
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)
TransactionRecord * index(interfaces::Wallet &wallet, const uint256 &cur_block_hash, const int idx)
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
interfaces::Node & node() const
Definition: walletmodel.h:137
AddressTableModel * getAddressTableModel() const
interfaces::Wallet & wallet() const
Definition: walletmodel.h:138
OptionsModel * getOptionsModel() const
uint256 getLastBlockProcessed() const
constexpr bool IsNull() const
Definition: uint256.h:48
std::string ToString() const
Definition: uint256.cpp:21
std::string GetHex() const
Definition: uint256.cpp:11
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:71
Interface for accessing a wallet.
Definition: wallet.h:66
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
virtual std::unique_ptr< Handler > handleTransactionChanged(TransactionChangedFn fn)=0
static std::optional< transaction_identifier > FromHex(std::string_view hex)
256-bit opaque blob.
Definition: uint256.h:196
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:90
Definition: messages.h:20
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:401
Updated transaction status.
Definition: wallet.h:419
#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[]
ChangeType
General change type (added, updated, removed).
Definition: ui_change_type.h:9
@ CT_UPDATED
@ CT_DELETED
@ CT_NEW
assert(!tx.IsCoinBase())