Skip to content

Commit a914968

Browse files
committed
Merge bitcoin#7707: [RPC][QT] UI support for abandoned transactions
8efed3b [Qt] Support for abandoned/abandoning transactions (Jonas Schnelli)
2 parents e662a76 + 8efed3b commit a914968

12 files changed

+70
-4
lines changed

src/Makefile.qt.include

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ RES_ICONS = \
268268
qt/res/icons/tx_output.png \
269269
qt/res/icons/tx_mined.png \
270270
qt/res/icons/warning.png \
271-
qt/res/icons/verify.png
271+
qt/res/icons/verify.png \
272+
qt/res/icons/transaction_abandoned.png
272273

273274
BITCOIN_QT_CPP = \
274275
qt/bantablemodel.cpp \

src/qt/bitcoin.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<file alias="fontbigger">res/icons/fontbigger.png</file>
5050
<file alias="fontsmaller">res/icons/fontsmaller.png</file>
5151
<file alias="prompticon">res/icons/chevron.png</file>
52+
<file alias="transaction_abandoned">res/icons/transaction_abandoned.png</file>
5253
</qresource>
5354
<qresource prefix="/movies">
5455
<file alias="spinner-000">res/movies/spinner-000.png</file>

src/qt/guiconstants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ static const bool DEFAULT_SPLASHSCREEN = true;
2929
#define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255)
3030
/* Transaction list -- TX status decoration - offline */
3131
#define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192)
32+
/* Transaction list -- TX status decoration - danger, tx needs attention */
33+
#define COLOR_TX_STATUS_DANGER QColor(200, 100, 100)
3234
/* Transaction list -- TX status decoration - default color */
3335
#define COLOR_BLACK QColor(0, 0, 0)
3436

1.44 KB
Loading

src/qt/transactiondesc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
3939
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
4040
return tr("%1/offline").arg(nDepth);
4141
else if (nDepth == 0)
42-
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool")));
42+
return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool"))) + (wtx.isAbandoned() ? ", "+tr("abandoned") : "");
4343
else if (nDepth < 6)
4444
return tr("%1/unconfirmed").arg(nDepth);
4545
else

src/qt/transactionrecord.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
239239
else if (status.depth == 0)
240240
{
241241
status.status = TransactionStatus::Unconfirmed;
242+
if (wtx.isAbandoned())
243+
status.status = TransactionStatus::Abandoned;
242244
}
243245
else if (status.depth < RecommendedNumConfirmations)
244246
{

src/qt/transactionrecord.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class TransactionStatus
3333
Unconfirmed, /**< Not yet mined into a block **/
3434
Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/
3535
Conflicted, /**< Conflicts with other transaction or mempool **/
36+
Abandoned, /**< Abandoned from the wallet **/
3637
/// Generated (mined) transactions
3738
Immature, /**< Mined but waiting for maturity */
3839
MaturesWarning, /**< Transaction will likely not mature because no nodes have confirmed */

src/qt/transactiontablemodel.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons
312312
case TransactionStatus::Unconfirmed:
313313
status = tr("Unconfirmed");
314314
break;
315+
case TransactionStatus::Abandoned:
316+
status = tr("Abandoned");
317+
break;
315318
case TransactionStatus::Confirming:
316319
status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
317320
break;
@@ -468,6 +471,8 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx)
468471
return COLOR_TX_STATUS_OFFLINE;
469472
case TransactionStatus::Unconfirmed:
470473
return QIcon(":/icons/transaction_0");
474+
case TransactionStatus::Abandoned:
475+
return QIcon(":/icons/transaction_abandoned");
471476
case TransactionStatus::Confirming:
472477
switch(wtx->status.depth)
473478
{
@@ -573,6 +578,11 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
573578
case Qt::TextAlignmentRole:
574579
return column_alignments[index.column()];
575580
case Qt::ForegroundRole:
581+
// Use the "danger" color for abandoned transactions
582+
if(rec->status.status == TransactionStatus::Abandoned)
583+
{
584+
return COLOR_TX_STATUS_DANGER;
585+
}
576586
// Non-confirmed (but not immature) as transactions are grey
577587
if(!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature)
578588
{

src/qt/transactionview.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
3939
QWidget(parent), model(0), transactionProxyModel(0),
40-
transactionView(0)
40+
transactionView(0), abandonAction(0)
4141
{
4242
// Build filter row
4343
setContentsMargins(0,0,0,0);
@@ -137,6 +137,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
137137
transactionView = view;
138138

139139
// Actions
140+
abandonAction = new QAction(tr("Abandon transaction"), this);
140141
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
141142
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
142143
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
@@ -153,8 +154,10 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
153154
contextMenu->addAction(copyTxIDAction);
154155
contextMenu->addAction(copyTxHexAction);
155156
contextMenu->addAction(copyTxPlainText);
156-
contextMenu->addAction(editLabelAction);
157157
contextMenu->addAction(showDetailsAction);
158+
contextMenu->addSeparator();
159+
contextMenu->addAction(abandonAction);
160+
contextMenu->addAction(editLabelAction);
158161

159162
mapperThirdPartyTxUrls = new QSignalMapper(this);
160163

@@ -170,6 +173,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
170173
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
171174
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
172175

176+
connect(abandonAction, SIGNAL(triggered()), this, SLOT(abandonTx()));
173177
connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
174178
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
175179
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
@@ -360,12 +364,37 @@ void TransactionView::exportClicked()
360364
void TransactionView::contextualMenu(const QPoint &point)
361365
{
362366
QModelIndex index = transactionView->indexAt(point);
367+
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
368+
369+
// check if transaction can be abandoned, disable context menu action in case it doesn't
370+
uint256 hash;
371+
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
372+
abandonAction->setEnabled(model->transactionCanBeAbandoned(hash));
373+
363374
if(index.isValid())
364375
{
365376
contextMenu->exec(QCursor::pos());
366377
}
367378
}
368379

380+
void TransactionView::abandonTx()
381+
{
382+
if(!transactionView || !transactionView->selectionModel())
383+
return;
384+
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
385+
386+
// get the hash from the TxHashRole (QVariant / QString)
387+
uint256 hash;
388+
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
389+
hash.SetHex(hashQStr.toStdString());
390+
391+
// Abandon the wallet transaction over the walletModel
392+
model->abandonTransaction(hash);
393+
394+
// Update the table
395+
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
396+
}
397+
369398
void TransactionView::copyAddress()
370399
{
371400
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);

src/qt/transactionview.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class TransactionView : public QWidget
7575
QFrame *dateRangeWidget;
7676
QDateTimeEdit *dateFrom;
7777
QDateTimeEdit *dateTo;
78+
QAction *abandonAction;
7879

7980
QWidget *createDateRangeWidget();
8081

@@ -97,6 +98,7 @@ private Q_SLOTS:
9798
void copyTxPlainText();
9899
void openThirdPartyTxUrl(QString url);
99100
void updateWatchOnlyColumn(bool fHaveWatchOnly);
101+
void abandonTx();
100102

101103
Q_SIGNALS:
102104
void doubleClicked(const QModelIndex&);

0 commit comments

Comments
 (0)