]> Git Repo - VerusCoin.git/blame - src/qt/transactiontablemodel.cpp
Remove translation for -help-debug options
[VerusCoin.git] / src / qt / transactiontablemodel.cpp
CommitLineData
f914f1a7 1// Copyright (c) 2011-2014 The Bitcoin Core developers
78253fcb 2// Distributed under the MIT software license, see the accompanying
e592d43f
WL
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
0fd01780 5#include "transactiontablemodel.h"
32af5266 6
51ed9ec9 7#include "addresstablemodel.h"
63760fa1 8#include "guiconstants.h"
51ed9ec9
BD
9#include "guiutil.h"
10#include "optionsmodel.h"
9b7d3fb1 11#include "scicon.h"
66d536ed 12#include "transactiondesc.h"
51ed9ec9 13#include "transactionrecord.h"
ebff5c40 14#include "walletmodel.h"
4d27c960 15
51ed9ec9
BD
16#include "main.h"
17#include "sync.h"
18#include "uint256.h"
19#include "util.h"
50c72f23 20#include "wallet/wallet.h"
e8ef3da7 21
f488e735 22#include <QColor>
ceb6d4e1 23#include <QDateTime>
42018eff 24#include <QDebug>
51ed9ec9
BD
25#include <QIcon>
26#include <QList>
af943776 27
b0849613 28// Amount column is right-aligned it contains numbers
34fa1782 29static int column_alignments[] = {
dcd0b077 30 Qt::AlignLeft|Qt::AlignVCenter, /* status */
1c5f0af0 31 Qt::AlignLeft|Qt::AlignVCenter, /* watchonly */
dcd0b077
WL
32 Qt::AlignLeft|Qt::AlignVCenter, /* date */
33 Qt::AlignLeft|Qt::AlignVCenter, /* type */
34 Qt::AlignLeft|Qt::AlignVCenter, /* address */
35 Qt::AlignRight|Qt::AlignVCenter /* amount */
34fa1782
WL
36 };
37
0f3981be 38// Comparison operator for sort/binary search of model tx list
9d9a4e87
WL
39struct TxLessThan
40{
41 bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
42 {
43 return a.hash < b.hash;
44 }
45 bool operator()(const TransactionRecord &a, const uint256 &b) const
46 {
47 return a.hash < b;
48 }
49 bool operator()(const uint256 &a, const TransactionRecord &b) const
50 {
51 return a < b.hash;
52 }
53};
54
0f3981be 55// Private implementation
87207a2e 56class TransactionTablePriv
213f7636 57{
87207a2e 58public:
bdd0c59a
PK
59 TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent) :
60 wallet(wallet),
61 parent(parent)
9d9a4e87
WL
62 {
63 }
bdd0c59a 64
e8ef3da7 65 CWallet *wallet;
9d9a4e87
WL
66 TransactionTableModel *parent;
67
63760fa1
WL
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 */
213f7636
WL
72 QList<TransactionRecord> cachedWallet;
73
0f3981be
WL
74 /* Query entire wallet anew from core.
75 */
63760fa1 76 void refreshWallet()
213f7636 77 {
42018eff 78 qDebug() << "TransactionTablePriv::refreshWallet";
8c937da5 79 cachedWallet.clear();
213f7636 80 {
55a1db4f 81 LOCK2(cs_main, wallet->cs_wallet);
e8ef3da7 82 for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
213f7636 83 {
fe4a6550
WL
84 if(TransactionRecord::showTransaction(it->second))
85 cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
213f7636
WL
86 }
87 }
213f7636
WL
88 }
89
0f3981be
WL
90 /* Update our model of the wallet incrementally, to synchronize our model of the wallet
91 with that of the core.
92
fe4a6550 93 Call with transaction that was added, removed or changed.
63760fa1 94 */
023e63df 95 void updateWallet(const uint256 &hash, int status, bool showTransaction)
63760fa1 96 {
5262fde0 97 qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
fe4a6550 98
023e63df
WL
99 // Find bounds of this transaction in model
100 QList<TransactionRecord>::iterator lower = qLowerBound(
101 cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
102 QList<TransactionRecord>::iterator upper = qUpperBound(
103 cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
104 int lowerIndex = (lower - cachedWallet.begin());
105 int upperIndex = (upper - cachedWallet.begin());
106 bool inModel = (lower != upper);
fe4a6550 107
023e63df
WL
108 if(status == CT_UPDATED)
109 {
110 if(showTransaction && !inModel)
111 status = CT_NEW; /* Not in model, but want to show, treat as new */
112 if(!showTransaction && inModel)
113 status = CT_DELETED; /* In model, but want to hide, treat as deleted */
114 }
fe4a6550 115
023e63df
WL
116 qDebug() << " inModel=" + QString::number(inModel) +
117 " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
118 " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
fe4a6550 119
023e63df
WL
120 switch(status)
121 {
122 case CT_NEW:
123 if(inModel)
9d9a4e87 124 {
5262fde0 125 qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
023e63df 126 break;
fe4a6550 127 }
023e63df 128 if(showTransaction)
fe4a6550 129 {
023e63df
WL
130 LOCK2(cs_main, wallet->cs_wallet);
131 // Find transaction in wallet
132 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
133 if(mi == wallet->mapWallet.end())
fe4a6550 134 {
5262fde0 135 qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
fe4a6550
WL
136 break;
137 }
023e63df
WL
138 // Added -- insert at the right position
139 QList<TransactionRecord> toInsert =
140 TransactionRecord::decomposeTransaction(wallet, mi->second);
141 if(!toInsert.isEmpty()) /* only if something to insert */
9d9a4e87 142 {
023e63df
WL
143 parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
144 int insert_idx = lowerIndex;
145 foreach(const TransactionRecord &rec, toInsert)
9d9a4e87 146 {
023e63df
WL
147 cachedWallet.insert(insert_idx, rec);
148 insert_idx += 1;
9d9a4e87 149 }
023e63df 150 parent->endInsertRows();
8e86dca2 151 }
023e63df
WL
152 }
153 break;
154 case CT_DELETED:
155 if(!inModel)
156 {
5262fde0 157 qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
fe4a6550 158 break;
9d9a4e87 159 }
023e63df
WL
160 // Removed -- remove entire transaction from table
161 parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
162 cachedWallet.erase(lower, upper);
163 parent->endRemoveRows();
164 break;
165 case CT_UPDATED:
166 // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
167 // visible transactions.
168 break;
63760fa1 169 }
63760fa1
WL
170 }
171
213f7636
WL
172 int size()
173 {
174 return cachedWallet.size();
175 }
176
177 TransactionRecord *index(int idx)
178 {
179 if(idx >= 0 && idx < cachedWallet.size())
180 {
64bca50d
WL
181 TransactionRecord *rec = &cachedWallet[idx];
182
41106a50
WL
183 // Get required locks upfront. This avoids the GUI from getting
184 // stuck if the core is holding the locks for a longer time - for
185 // example, during a wallet rescan.
186 //
3015e0bc
WL
187 // If a status update is needed (blocks came in since last check),
188 // update the status of this transaction from the wallet. Otherwise,
0f3981be 189 // simply re-use the cached status.
41106a50
WL
190 TRY_LOCK(cs_main, lockMain);
191 if(lockMain)
64bca50d 192 {
41106a50 193 TRY_LOCK(wallet->cs_wallet, lockWallet);
3015e0bc 194 if(lockWallet && rec->statusUpdateNeeded())
55a1db4f 195 {
41106a50
WL
196 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
197
198 if(mi != wallet->mapWallet.end())
199 {
200 rec->updateStatus(mi->second);
201 }
64bca50d
WL
202 }
203 }
204 return rec;
8e86dca2 205 }
bbad6832 206 return 0;
213f7636 207 }
63760fa1 208
bdd0c59a 209 QString describe(TransactionRecord *rec, int unit)
66d536ed 210 {
66d536ed 211 {
55a1db4f 212 LOCK2(cs_main, wallet->cs_wallet);
e8ef3da7
WL
213 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
214 if(mi != wallet->mapWallet.end())
66d536ed 215 {
b90711ca 216 return TransactionDesc::toHTML(wallet, mi->second, rec, unit);
66d536ed
WL
217 }
218 }
bbad6832 219 return QString();
66d536ed 220 }
213f7636
WL
221};
222
ebff5c40 223TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *parent):
213f7636 224 QAbstractTableModel(parent),
e8ef3da7 225 wallet(wallet),
ebff5c40 226 walletModel(parent),
023e63df
WL
227 priv(new TransactionTablePriv(wallet, this)),
228 fProcessingQueuedTransactions(false)
4d27c960 229{
e96028c7 230 columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
5d5990dc 231 priv->refreshWallet();
63760fa1 232
229c34f8 233 connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
023e63df
WL
234
235 subscribeToCoreSignals();
213f7636
WL
236}
237
238TransactionTableModel::~TransactionTableModel()
239{
023e63df 240 unsubscribeFromCoreSignals();
5d5990dc 241 delete priv;
4d27c960
WL
242}
243
8969828d 244/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
245void TransactionTableModel::updateAmountColumnTitle()
246{
247 columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
248 emit headerDataChanged(Qt::Horizontal,Amount,Amount);
249}
250
023e63df 251void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
dd8e82f7 252{
fe4a6550
WL
253 uint256 updated;
254 updated.SetHex(hash.toStdString());
63760fa1 255
023e63df 256 priv->updateWallet(updated, status, showTransaction);
fe4a6550 257}
63760fa1 258
fe4a6550
WL
259void TransactionTableModel::updateConfirmations()
260{
55a1db4f
WL
261 // Blocks came in since last poll.
262 // Invalidate status (number of confirmations) and (possibly) description
263 // for all rows. Qt is smart enough to only actually request the data for the
264 // visible rows.
265 emit dataChanged(index(0, Status), index(priv->size()-1, Status));
266 emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
dd8e82f7 267}
213f7636 268
4d27c960
WL
269int TransactionTableModel::rowCount(const QModelIndex &parent) const
270{
271 Q_UNUSED(parent);
5d5990dc 272 return priv->size();
4d27c960
WL
273}
274
275int TransactionTableModel::columnCount(const QModelIndex &parent) const
276{
277 Q_UNUSED(parent);
278 return columns.length();
279}
280
126185aa 281QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) const
213f7636 282{
0856c1a0 283 QString status;
f79efbab 284
f642fd9d 285 switch(wtx->status.status)
e5992468 286 {
f642fd9d
WL
287 case TransactionStatus::OpenUntilBlock:
288 status = tr("Open for %n more block(s)","",wtx->status.open_for);
289 break;
290 case TransactionStatus::OpenUntilDate:
291 status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
292 break;
293 case TransactionStatus::Offline:
294 status = tr("Offline");
295 break;
296 case TransactionStatus::Unconfirmed:
297 status = tr("Unconfirmed");
298 break;
299 case TransactionStatus::Confirming:
300 status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
301 break;
302 case TransactionStatus::Confirmed:
303 status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
304 break;
305 case TransactionStatus::Conflicted:
306 status = tr("Conflicted");
307 break;
308 case TransactionStatus::Immature:
309 status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
310 break;
311 case TransactionStatus::MaturesWarning:
312 status = tr("This block was not received by any other nodes and will probably not be accepted!");
313 break;
314 case TransactionStatus::NotAccepted:
315 status = tr("Generated but not accepted");
316 break;
e5992468 317 }
0856c1a0 318
126185aa 319 return status;
213f7636
WL
320}
321
126185aa 322QString TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const
213f7636 323{
0856c1a0
WL
324 if(wtx->time)
325 {
b0849613 326 return GUIUtil::dateTimeStr(wtx->time);
8e86dca2 327 }
bbad6832 328 return QString();
213f7636
WL
329}
330
2f5d3809
WL
331/* Look up address in address book, if found return label (address)
332 otherwise just return (address)
ceb6d4e1 333 */
2f5d3809 334QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
ceb6d4e1 335{
51d7cc07 336 QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
ceb6d4e1 337 QString description;
2f5d3809 338 if(!label.isEmpty())
ceb6d4e1 339 {
bbad6832 340 description += label;
ceb6d4e1 341 }
bdba2dd0 342 if(label.isEmpty() || tooltip)
ceb6d4e1 343 {
bbad6832 344 description += QString(" (") + QString::fromStdString(address) + QString(")");
ceb6d4e1 345 }
f79efbab
WL
346 return description;
347}
348
05bcf708 349QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
213f7636 350{
f488e735
WL
351 switch(wtx->type)
352 {
8c937da5 353 case TransactionRecord::RecvWithAddress:
05bcf708 354 return tr("Received with");
56c6e369
WL
355 case TransactionRecord::RecvFromOther:
356 return tr("Received from");
f488e735 357 case TransactionRecord::SendToAddress:
56c6e369 358 case TransactionRecord::SendToOther:
05bcf708 359 return tr("Sent to");
f488e735 360 case TransactionRecord::SendToSelf:
05bcf708 361 return tr("Payment to yourself");
34fa1782 362 case TransactionRecord::Generated:
05bcf708
WL
363 return tr("Mined");
364 default:
365 return QString();
34fa1782 366 }
34fa1782
WL
367}
368
05bcf708 369QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx) const
34fa1782 370{
05bcf708
WL
371 switch(wtx->type)
372 {
373 case TransactionRecord::Generated:
374 return QIcon(":/icons/tx_mined");
375 case TransactionRecord::RecvWithAddress:
56c6e369 376 case TransactionRecord::RecvFromOther:
05bcf708
WL
377 return QIcon(":/icons/tx_input");
378 case TransactionRecord::SendToAddress:
56c6e369 379 case TransactionRecord::SendToOther:
05bcf708
WL
380 return QIcon(":/icons/tx_output");
381 default:
382 return QIcon(":/icons/tx_inout");
383 }
05bcf708 384}
34fa1782 385
05bcf708
WL
386QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
387{
fbe0fcae
PK
388 QString watchAddress;
389 if (tooltip) {
390 // Mark transactions involving watch-only addresses by adding " (watch-only)"
391 watchAddress = wtx->involvesWatchAddress ? QString(" (") + tr("watch-only") + QString(")") : "";
392 }
393
34fa1782
WL
394 switch(wtx->type)
395 {
56c6e369 396 case TransactionRecord::RecvFromOther:
fbe0fcae 397 return QString::fromStdString(wtx->address) + watchAddress;
2f5d3809 398 case TransactionRecord::RecvWithAddress:
34fa1782 399 case TransactionRecord::SendToAddress:
e07c8e91 400 case TransactionRecord::Generated:
fbe0fcae 401 return lookupAddress(wtx->address, tooltip) + watchAddress;
56c6e369 402 case TransactionRecord::SendToOther:
fbe0fcae 403 return QString::fromStdString(wtx->address) + watchAddress;
34fa1782 404 case TransactionRecord::SendToSelf:
05bcf708 405 default:
fbe0fcae 406 return tr("(n/a)") + watchAddress;
f488e735 407 }
213f7636
WL
408}
409
2f5d3809
WL
410QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
411{
412 // Show addresses without label in a less visible color
413 switch(wtx->type)
414 {
415 case TransactionRecord::RecvWithAddress:
416 case TransactionRecord::SendToAddress:
e07c8e91 417 case TransactionRecord::Generated:
2f5d3809
WL
418 {
419 QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
420 if(label.isEmpty())
421 return COLOR_BAREADDRESS;
422 } break;
d8f5c59a 423 case TransactionRecord::SendToSelf:
d8f5c59a 424 return COLOR_BAREADDRESS;
2f5d3809
WL
425 default:
426 break;
427 }
428 return QVariant();
429}
430
f7d70c60 431QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
213f7636 432{
f7d70c60 433 QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
fbaee7a8 434 if(showUnconfirmed)
0856c1a0 435 {
f642fd9d 436 if(!wtx->status.countsForBalance)
fbaee7a8
WL
437 {
438 str = QString("[") + str + QString("]");
439 }
0856c1a0 440 }
126185aa 441 return QString(str);
213f7636
WL
442}
443
126185aa 444QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) const
249300ae 445{
f642fd9d 446 switch(wtx->status.status)
e5992468 447 {
f642fd9d
WL
448 case TransactionStatus::OpenUntilBlock:
449 case TransactionStatus::OpenUntilDate:
21f15164 450 return COLOR_TX_STATUS_OPENUNTILDATE;
f642fd9d 451 case TransactionStatus::Offline:
21f15164 452 return COLOR_TX_STATUS_OFFLINE;
f642fd9d
WL
453 case TransactionStatus::Unconfirmed:
454 return QIcon(":/icons/transaction_0");
455 case TransactionStatus::Confirming:
456 switch(wtx->status.depth)
e5992468 457 {
f642fd9d
WL
458 case 1: return QIcon(":/icons/transaction_1");
459 case 2: return QIcon(":/icons/transaction_2");
460 case 3: return QIcon(":/icons/transaction_3");
461 case 4: return QIcon(":/icons/transaction_4");
462 default: return QIcon(":/icons/transaction_5");
463 };
464 case TransactionStatus::Confirmed:
465 return QIcon(":/icons/transaction_confirmed");
466 case TransactionStatus::Conflicted:
467 return QIcon(":/icons/transaction_conflicted");
468 case TransactionStatus::Immature: {
469 int total = wtx->status.depth + wtx->status.matures_in;
470 int part = (wtx->status.depth * 4 / total) + 1;
471 return QIcon(QString(":/icons/transaction_%1").arg(part));
e5992468 472 }
f642fd9d
WL
473 case TransactionStatus::MaturesWarning:
474 case TransactionStatus::NotAccepted:
475 return QIcon(":/icons/transaction_0");
21f15164
PK
476 default:
477 return COLOR_BLACK;
249300ae 478 }
249300ae
WL
479}
480
1c5f0af0
CL
481QVariant TransactionTableModel::txWatchonlyDecoration(const TransactionRecord *wtx) const
482{
483 if (wtx->involvesWatchAddress)
484 return QIcon(":/icons/eye");
485 else
486 return QVariant();
487}
488
126185aa
WL
489QString TransactionTableModel::formatTooltip(const TransactionRecord *rec) const
490{
e74e8a18 491 QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
56c6e369 492 if(rec->type==TransactionRecord::RecvFromOther || rec->type==TransactionRecord::SendToOther ||
126185aa
WL
493 rec->type==TransactionRecord::SendToAddress || rec->type==TransactionRecord::RecvWithAddress)
494 {
495 tooltip += QString(" ") + formatTxToAddress(rec, true);
496 }
126185aa
WL
497 return tooltip;
498}
499
4d27c960
WL
500QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
501{
502 if(!index.isValid())
503 return QVariant();
213f7636 504 TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
4d27c960 505
e74e8a18 506 switch(role)
249300ae 507 {
9b7d3fb1 508 case RawDecorationRole:
05bcf708 509 switch(index.column())
249300ae 510 {
05bcf708 511 case Status:
126185aa 512 return txStatusDecoration(rec);
1c5f0af0
CL
513 case Watchonly:
514 return txWatchonlyDecoration(rec);
05bcf708
WL
515 case ToAddress:
516 return txAddressDecoration(rec);
249300ae 517 }
e74e8a18 518 break;
9b7d3fb1
LD
519 case Qt::DecorationRole:
520 {
521 QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
522 return TextColorIcon(icon);
523 }
e74e8a18 524 case Qt::DisplayRole:
213f7636
WL
525 switch(index.column())
526 {
213f7636
WL
527 case Date:
528 return formatTxDate(rec);
34fa1782
WL
529 case Type:
530 return formatTxType(rec);
531 case ToAddress:
2f5d3809 532 return formatTxToAddress(rec, false);
34fa1782 533 case Amount:
f7d70c60 534 return formatTxAmount(rec, true, BitcoinUnits::separatorAlways);
213f7636 535 }
e74e8a18
WL
536 break;
537 case Qt::EditRole:
538 // Edit role is used for sorting, so return the unformatted values
63760fa1
WL
539 switch(index.column())
540 {
541 case Status:
542 return QString::fromStdString(rec->status.sortKey);
543 case Date:
544 return rec->time;
34fa1782
WL
545 case Type:
546 return formatTxType(rec);
1c5f0af0
CL
547 case Watchonly:
548 return (rec->involvesWatchAddress ? 1 : 0);
34fa1782 549 case ToAddress:
2f5d3809 550 return formatTxToAddress(rec, true);
34fa1782 551 case Amount:
a372168e 552 return qint64(rec->credit + rec->debit);
63760fa1 553 }
e74e8a18
WL
554 break;
555 case Qt::ToolTipRole:
556 return formatTooltip(rec);
557 case Qt::TextAlignmentRole:
1355cfe1 558 return column_alignments[index.column()];
e74e8a18 559 case Qt::ForegroundRole:
f642fd9d
WL
560 // Non-confirmed (but not immature) as transactions are grey
561 if(!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature)
8e86dca2 562 {
bbae0fc9 563 return COLOR_UNCONFIRMED;
f488e735 564 }
34fa1782
WL
565 if(index.column() == Amount && (rec->credit+rec->debit) < 0)
566 {
bbae0fc9 567 return COLOR_NEGATIVE;
34fa1782 568 }
2f5d3809
WL
569 if(index.column() == ToAddress)
570 {
571 return addressColor(rec);
572 }
e74e8a18
WL
573 break;
574 case TypeRole:
ceb6d4e1 575 return rec->type;
e74e8a18 576 case DateRole:
ceb6d4e1 577 return QDateTime::fromTime_t(static_cast<uint>(rec->time));
1c5f0af0
CL
578 case WatchonlyRole:
579 return rec->involvesWatchAddress;
580 case WatchonlyDecorationRole:
581 return txWatchonlyDecoration(rec);
e74e8a18 582 case LongDescriptionRole:
bdd0c59a 583 return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit());
e74e8a18 584 case AddressRole:
ceb6d4e1 585 return QString::fromStdString(rec->address);
e74e8a18 586 case LabelRole:
51d7cc07 587 return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
e74e8a18 588 case AmountRole:
a372168e 589 return qint64(rec->credit + rec->debit);
e74e8a18 590 case TxIDRole:
ed4c7fd4 591 return rec->getTxID();
40c5b939
CL
592 case TxHashRole:
593 return QString::fromStdString(rec->hash.ToString());
e74e8a18 594 case ConfirmedRole:
f642fd9d 595 return rec->status.countsForBalance;
e74e8a18 596 case FormattedAmountRole:
f65352a7 597 // Used for copy/export, so don't include separators
70074029 598 return formatTxAmount(rec, false, BitcoinUnits::separatorNever);
9a3d936f
WL
599 case StatusRole:
600 return rec->status.status;
fbaee7a8 601 }
4d27c960
WL
602 return QVariant();
603}
604
605QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
606{
f6c18bc9 607 if(orientation == Qt::Horizontal)
1355cfe1 608 {
f6c18bc9 609 if(role == Qt::DisplayRole)
1355cfe1
WL
610 {
611 return columns[section];
8e86dca2
WL
612 }
613 else if (role == Qt::TextAlignmentRole)
f6c18bc9
WL
614 {
615 return column_alignments[section];
a790ec58
WL
616 } else if (role == Qt::ToolTipRole)
617 {
618 switch(section)
619 {
620 case Status:
40951d81 621 return tr("Transaction status. Hover over this field to show number of confirmations.");
a790ec58
WL
622 case Date:
623 return tr("Date and time that the transaction was received.");
34fa1782
WL
624 case Type:
625 return tr("Type of transaction.");
1c5f0af0
CL
626 case Watchonly:
627 return tr("Whether or not a watch-only address is involved in this transaction.");
34fa1782 628 case ToAddress:
e96028c7 629 return tr("User-defined intent/purpose of the transaction.");
34fa1782
WL
630 case Amount:
631 return tr("Amount removed from or added to balance.");
a790ec58 632 }
1355cfe1 633 }
4d27c960
WL
634 }
635 return QVariant();
636}
637
5d5990dc 638QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
213f7636
WL
639{
640 Q_UNUSED(parent);
5d5990dc 641 TransactionRecord *data = priv->index(row);
213f7636
WL
642 if(data)
643 {
5d5990dc 644 return createIndex(row, column, priv->index(row));
8e86dca2 645 }
bbad6832 646 return QModelIndex();
213f7636
WL
647}
648
229c34f8
PK
649void TransactionTableModel::updateDisplayUnit()
650{
651 // emit dataChanged to update Amount column with the current unit
8969828d 652 updateAmountColumnTitle();
229c34f8
PK
653 emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
654}
023e63df
WL
655
656// queue notifications to show a non freezing progress dialog e.g. for rescan
657struct TransactionNotification
658{
659public:
660 TransactionNotification() {}
661 TransactionNotification(uint256 hash, ChangeType status, bool showTransaction):
662 hash(hash), status(status), showTransaction(showTransaction) {}
663
664 void invoke(QObject *ttm)
665 {
666 QString strHash = QString::fromStdString(hash.GetHex());
5262fde0 667 qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
023e63df
WL
668 QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
669 Q_ARG(QString, strHash),
670 Q_ARG(int, status),
671 Q_ARG(bool, showTransaction));
672 }
673private:
674 uint256 hash;
675 ChangeType status;
676 bool showTransaction;
677};
678
679static bool fQueueNotifications = false;
680static std::vector< TransactionNotification > vQueueNotifications;
681
682static void NotifyTransactionChanged(TransactionTableModel *ttm, CWallet *wallet, const uint256 &hash, ChangeType status)
683{
684 // Find transaction in wallet
685 std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
686 // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
687 bool inWallet = mi != wallet->mapWallet.end();
688 bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
689
690 TransactionNotification notification(hash, status, showTransaction);
691
692 if (fQueueNotifications)
693 {
694 vQueueNotifications.push_back(notification);
695 return;
696 }
697 notification.invoke(ttm);
698}
699
700static void ShowProgress(TransactionTableModel *ttm, const std::string &title, int nProgress)
701{
702 if (nProgress == 0)
703 fQueueNotifications = true;
704
705 if (nProgress == 100)
706 {
707 fQueueNotifications = false;
708 if (vQueueNotifications.size() > 10) // prevent balloon spam, show maximum 10 balloons
709 QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
710 for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
711 {
712 if (vQueueNotifications.size() - i <= 10)
713 QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
714
715 vQueueNotifications[i].invoke(ttm);
716 }
717 std::vector<TransactionNotification >().swap(vQueueNotifications); // clear
718 }
719}
720
721void TransactionTableModel::subscribeToCoreSignals()
722{
723 // Connect signals to wallet
724 wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
725 wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
726}
727
728void TransactionTableModel::unsubscribeFromCoreSignals()
729{
730 // Disconnect signals from wallet
731 wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
732 wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
733}
This page took 0.278568 seconds and 4 git commands to generate.