LCOV - code coverage report
Current view: top level - src/qt - transactiontablemodel.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 297 0.0 %
Date: 2015-10-12 22:39:14 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11