On initial block chain download, show a progress bar
[novacoin.git] / src / qt / transactiontablemodel.cpp
index 8fe1839..bed08d7 100644 (file)
 #include <QList>
 #include <QColor>
 #include <QTimer>
+#include <QIcon>
 #include <QtAlgorithms>
 
 const QString TransactionTableModel::Sent = "s";
 const QString TransactionTableModel::Received = "r";
 const QString TransactionTableModel::Other = "o";
 
-/* Comparison operator for sort/binary search of model tx list */
+// Comparison operator for sort/binary search of model tx list
 struct TxLessThan
 {
     bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
@@ -33,7 +34,7 @@ struct TxLessThan
     }
 };
 
-/* Private implementation */
+// Private implementation
 struct TransactionTablePriv
 {
     TransactionTablePriv(TransactionTableModel *parent):
@@ -49,12 +50,13 @@ struct TransactionTablePriv
      */
     QList<TransactionRecord> cachedWallet;
 
+    /* Query entire wallet anew from core.
+     */
     void refreshWallet()
     {
+#ifdef WALLET_UPDATE_DEBUG
         qDebug() << "refreshWallet";
-
-        /* Query entire wallet from core.
-         */
+#endif
         cachedWallet.clear();
         CRITICAL_BLOCK(cs_mapWallet)
         {
@@ -65,19 +67,20 @@ struct TransactionTablePriv
         }
     }
 
-    /* Update our model of the wallet incrementally.
+    /* Update our model of the wallet incrementally, to synchronize our model of the wallet
+       with that of the core.
+
        Call with list of hashes of transactions that were added, removed or changed.
      */
     void updateWallet(const QList<uint256> &updated)
     {
-        /* Walk through updated transactions, update model as needed.
-         */
+        // Walk through updated transactions, update model as needed.
+#ifdef WALLET_UPDATE_DEBUG
         qDebug() << "updateWallet";
-
-        /* Sort update list, and iterate through it in reverse, so that model updates
-           can be emitted from end to beginning (so that earlier updates will not influence
-           the indices of latter ones).
-         */
+#endif
+        // Sort update list, and iterate through it in reverse, so that model updates
+        //  can be emitted from end to beginning (so that earlier updates will not influence
+        // the indices of latter ones).
         QList<uint256> updated_sorted = updated;
         qSort(updated_sorted);
 
@@ -103,12 +106,14 @@ struct TransactionTablePriv
                     inModel = true;
                 }
 
+#ifdef WALLET_UPDATE_DEBUG
                 qDebug() << "  " << QString::fromStdString(hash.ToString()) << inWallet << " " << inModel
                         << lowerIndex << "-" << upperIndex;
+#endif
 
                 if(inWallet && !inModel)
                 {
-                    /* Added */
+                    // Added -- insert at the right position
                     QList<TransactionRecord> toInsert =
                             TransactionRecord::decomposeTransaction(mi->second);
                     if(!toInsert.isEmpty()) /* only if something to insert */
@@ -125,14 +130,14 @@ struct TransactionTablePriv
                 }
                 else if(!inWallet && inModel)
                 {
-                    /* Removed */
+                    // Removed -- remove entire transaction from table
                     parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
                     cachedWallet.erase(lower, upper);
                     parent->endRemoveRows();
                 }
                 else if(inWallet && inModel)
                 {
-                    /* Updated -- nothing to do, status update will take care of this */
+                    // Updated -- nothing to do, status update will take care of this
                 }
             }
         }
@@ -149,10 +154,9 @@ struct TransactionTablePriv
         {
             TransactionRecord *rec = &cachedWallet[idx];
 
-            /* If a status update is needed (blocks came in since last check),
-               update the status of this transaction from the wallet. Otherwise,
-               simply re-use the cached status.
-             */
+            // If a status update is needed (blocks came in since last check),
+            //  update the status of this transaction from the wallet. Otherwise,
+            // simply re-use the cached status.
             if(rec->statusUpdateNeeded())
             {
                 CRITICAL_BLOCK(cs_mapWallet)
@@ -188,7 +192,7 @@ struct TransactionTablePriv
 
 };
 
-/* Credit and Debit columns are right-aligned as they contain numbers */
+// Credit and Debit columns are right-aligned as they contain numbers
 static int column_alignments[] = {
         Qt::AlignLeft|Qt::AlignVCenter,
         Qt::AlignLeft|Qt::AlignVCenter,
@@ -220,7 +224,7 @@ void TransactionTableModel::update()
 {
     QList<uint256> updated;
 
-    /* Check if there are changes to wallet map */
+    // Check if there are changes to wallet map
     TRY_CRITICAL_BLOCK(cs_mapWallet)
     {
         if(!vWalletUpdated.empty())
@@ -237,9 +241,8 @@ void TransactionTableModel::update()
     {
         priv->updateWallet(updated);
 
-        /* Status (number of confirmations) and (possibly) description
-           columns changed for all rows.
-         */
+        // Status (number of confirmations) and (possibly) description
+        //  columns changed for all rows.
         emit dataChanged(index(0, Status), index(priv->size()-1, Status));
         emit dataChanged(index(0, Description), index(priv->size()-1, Description));
     }
@@ -270,13 +273,13 @@ QVariant TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) con
         status = tr("Open until ") + GUIUtil::DateTimeStr(wtx->status.open_for);
         break;
     case TransactionStatus::Offline:
-        status = tr("%1/offline").arg(wtx->status.depth);
+        status = tr("Offline (%1)").arg(wtx->status.depth);
         break;
     case TransactionStatus::Unconfirmed:
-        status = tr("%1/unconfirmed").arg(wtx->status.depth);
+        status = tr("Unconfirmed (%1)").arg(wtx->status.depth);
         break;
     case TransactionStatus::HaveConfirmations:
-        status = tr("%1 confirmations").arg(wtx->status.depth);
+        status = tr("Confirmed (%1)").arg(wtx->status.depth);
         break;
     }
 
@@ -396,19 +399,50 @@ QVariant TransactionTableModel::formatTxCredit(const TransactionRecord *wtx) con
     }
 }
 
+QVariant TransactionTableModel::formatTxDecoration(const TransactionRecord *wtx) const
+{
+    switch(wtx->status.status)
+    {
+    case TransactionStatus::OpenUntilBlock:
+    case TransactionStatus::OpenUntilDate:
+        return QColor(64,64,255);
+        break;
+    case TransactionStatus::Offline:
+        return QColor(192,192,192);
+    case TransactionStatus::Unconfirmed:
+        switch(wtx->status.depth)
+        {
+        case 0: return QIcon(":/icons/transaction_0");
+        case 1: return QIcon(":/icons/transaction_1");
+        case 2: return QIcon(":/icons/transaction_2");
+        case 3: return QIcon(":/icons/transaction_3");
+        case 4: return QIcon(":/icons/transaction_4");
+        default: return QIcon(":/icons/transaction_5");
+        };
+    case TransactionStatus::HaveConfirmations:
+        return QIcon(":/icons/transaction_confirmed");
+    }
+    return QColor(0,0,0);
+}
+
 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
 {
     if(!index.isValid())
         return QVariant();
     TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
 
-    if(role == Qt::DisplayRole)
+    if(role == Qt::DecorationRole)
     {
-        /* Delegate to specific column handlers */
+        if(index.column() == Status)
+        {
+            return formatTxDecoration(rec);
+        }
+    }
+    else if(role == Qt::DisplayRole)
+    {
+        // Delegate to specific column handlers
         switch(index.column())
         {
-        case Status:
-            return formatTxStatus(rec);
         case Date:
             return formatTxDate(rec);
         case Description:
@@ -421,7 +455,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
     }
     else if(role == Qt::EditRole)
     {
-        /* Edit role is used for sorting so return the real values */
+        // Edit role is used for sorting so return the real values
         switch(index.column())
         {
         case Status:
@@ -436,6 +470,13 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
             return rec->credit;
         }
     }
+    else if (role == Qt::ToolTipRole)
+    {
+        if(index.column() == Status)
+        {
+            return formatTxStatus(rec);
+        }
+    }
     else if (role == Qt::TextAlignmentRole)
     {
         return column_alignments[index.column()];
@@ -443,11 +484,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
     else if (role == Qt::ForegroundRole)
     {
         /* Non-confirmed transactions are grey */
-        if(rec->status.confirmed)
-        {
-            return QColor(0, 0, 0);
-        }
-        else
+        if(!rec->status.confirmed)
         {
             return QColor(128, 128, 128);
         }
@@ -486,6 +523,21 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
         else if (role == Qt::TextAlignmentRole)
         {
             return column_alignments[section];
+        } else if (role == Qt::ToolTipRole)
+        {
+            switch(section)
+            {
+            case Status:
+                return tr("Transaction status. Hover over this field to show number of transactions.");
+            case Date:
+                return tr("Date and time that the transaction was received.");
+            case Description:
+                return tr("Short description of the transaction.");
+            case Debit:
+                return tr("Amount removed from balance.");
+            case Credit:
+                return tr("Amount added to balance.");
+            }
         }
     }
     return QVariant();