From 213f7636301a3311cfcc47421910e326157501c2 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 27 May 2011 08:20:23 +0200 Subject: [PATCH] bind transactionmodel --- gui/forms/addressbookdialog.ui | 6 + gui/include/transactiontablemodel.h | 12 ++ gui/src/addresstablemodel.cpp | 8 +- gui/src/bitcoingui.cpp | 1 + gui/src/transactiontablemodel.cpp | 211 ++++++++++++++++++++++++++-- 5 files changed, 229 insertions(+), 9 deletions(-) diff --git a/gui/forms/addressbookdialog.ui b/gui/forms/addressbookdialog.ui index d66962a2b..761ea0fb9 100644 --- a/gui/forms/addressbookdialog.ui +++ b/gui/forms/addressbookdialog.ui @@ -32,6 +32,9 @@ QAbstractItemView::SelectRows + + true + false @@ -65,6 +68,9 @@ QAbstractItemView::SelectRows + + true + false diff --git a/gui/include/transactiontablemodel.h b/gui/include/transactiontablemodel.h index e86ab988c..684a9470d 100644 --- a/gui/include/transactiontablemodel.h +++ b/gui/include/transactiontablemodel.h @@ -4,11 +4,15 @@ #include #include +class TransactionTableImpl; +class TransactionRecord; + class TransactionTableModel : public QAbstractTableModel { Q_OBJECT public: explicit TransactionTableModel(QObject *parent = 0); + ~TransactionTableModel(); enum { Status = 0, @@ -32,8 +36,16 @@ public: QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; Qt::ItemFlags flags(const QModelIndex &index) const; + QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const; private: QStringList columns; + TransactionTableImpl *impl; + + QVariant formatTxStatus(const TransactionRecord *wtx) const; + QVariant formatTxDate(const TransactionRecord *wtx) const; + QVariant formatTxDescription(const TransactionRecord *wtx) const; + QVariant formatTxDebit(const TransactionRecord *wtx) const; + QVariant formatTxCredit(const TransactionRecord *wtx) const; }; #endif diff --git a/gui/src/addresstablemodel.cpp b/gui/src/addresstablemodel.cpp index 9a72cd972..aec29fa20 100644 --- a/gui/src/addresstablemodel.cpp +++ b/gui/src/addresstablemodel.cpp @@ -12,7 +12,13 @@ AddressTableModel::AddressTableModel(QObject *parent) : int AddressTableModel::rowCount(const QModelIndex &parent) const { - return 5; + Q_UNUSED(parent); + int retval = 0; + CRITICAL_BLOCK(cs_mapAddressBook) + { + retval = mapAddressBook.size(); + } + return retval; } int AddressTableModel::columnCount(const QModelIndex &parent) const diff --git a/gui/src/bitcoingui.cpp b/gui/src/bitcoingui.cpp index 168dffd7c..d8c72ae01 100644 --- a/gui/src/bitcoingui.cpp +++ b/gui/src/bitcoingui.cpp @@ -200,6 +200,7 @@ QWidget *BitcoinGUI::createTabs() transaction_table->setModel(proxy_model); transaction_table->setSelectionBehavior(QAbstractItemView::SelectRows); transaction_table->setSelectionMode(QAbstractItemView::ExtendedSelection); + transaction_table->setSortingEnabled(true); transaction_table->verticalHeader()->hide(); transaction_table->horizontalHeader()->resizeSection( diff --git a/gui/src/transactiontablemodel.cpp b/gui/src/transactiontablemodel.cpp index 0f16a3faf..454a10d93 100644 --- a/gui/src/transactiontablemodel.cpp +++ b/gui/src/transactiontablemodel.cpp @@ -2,11 +2,122 @@ #include "main.h" #include +#include +#include const QString TransactionTableModel::Sent = "s"; const QString TransactionTableModel::Received = "r"; const QString TransactionTableModel::Generated = "g"; +/* Separate transaction record format from core. + * When the GUI is going to communicate with the core through the network, + * we'll need our own internal formats anyway. + */ +class TransactionRecord +{ +public: + /* Information that never changes for the life of the transaction + */ + uint256 hash; + int64 time; + int64 credit; + int64 debit; + int64 change; + int64 lockTime; + int64 timeReceived; + bool isCoinBase; + int blockIndex; + + /* Properties that change based on changes in block chain that come in + over the network. + */ + bool confirmed; + int depthInMainChain; + bool final; + int requestCount; + + TransactionRecord(const CWalletTx &tx) + { + /* Copy immutable properties. + */ + hash = tx.GetHash(); + time = tx.GetTxTime(); + credit = tx.GetCredit(true); + debit = tx.GetDebit(); + change = tx.GetChange(); + isCoinBase = tx.IsCoinBase(); + lockTime = tx.nLockTime; + timeReceived = tx.nTimeReceived; + + /* Find the block the tx is in, store the index + */ + CBlockIndex* pindex = NULL; + std::map::iterator mi = mapBlockIndex.find(tx.hashBlock); + if (mi != mapBlockIndex.end()) + pindex = (*mi).second; + blockIndex = (pindex ? pindex->nHeight : INT_MAX); + + update(tx); + } + + void update(const CWalletTx &tx) + { + confirmed = tx.IsConfirmed(); + depthInMainChain = tx.GetDepthInMainChain(); + final = tx.IsFinal(); + requestCount = tx.GetRequestCount(); + } +}; + +/* Internal implementation */ +class TransactionTableImpl +{ +public: + QList cachedWallet; + + /* Update our model of the wallet */ + void updateWallet() + { + QList insertedIndices; + QList removedIndices; + + cachedWallet.clear(); + + /* Query wallet from core, and compare with our own + representation. + */ + CRITICAL_BLOCK(cs_mapWallet) + { + for(std::map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + /* TODO: Make note of new and removed transactions */ + /* insertedIndices */ + /* removedIndices */ + cachedWallet.append(TransactionRecord(it->second)); + } + } + /* beginInsertRows(QModelIndex(), first, last) */ + /* endInsertRows */ + /* beginRemoveRows(QModelIndex(), first, last) */ + /* beginEndRows */ + } + + int size() + { + return cachedWallet.size(); + } + + TransactionRecord *index(int idx) + { + if(idx >= 0 && idx < cachedWallet.size()) + { + return &cachedWallet[idx]; + } else { + return 0; + } + } +}; + /* Credit and Debit columns are right-aligned as they contain numbers */ static int column_alignments[] = { Qt::AlignLeft|Qt::AlignVCenter, @@ -18,15 +129,32 @@ static int column_alignments[] = { }; TransactionTableModel::TransactionTableModel(QObject *parent): - QAbstractTableModel(parent) + QAbstractTableModel(parent), + impl(new TransactionTableImpl()) { columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit"); + + impl->updateWallet(); } +TransactionTableModel::~TransactionTableModel() +{ + delete impl; +} + + int TransactionTableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return 4; + /* + int retval = 0; + CRITICAL_BLOCK(cs_mapWallet) + { + retval = mapWallet.size(); + } + return retval; + */ + return impl->size(); } int TransactionTableModel::columnCount(const QModelIndex &parent) const @@ -35,16 +163,72 @@ int TransactionTableModel::columnCount(const QModelIndex &parent) const return columns.length(); } +QVariant TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) const +{ + return QVariant(QString("Test")); +#if 0 + // Status + if (!wtx.IsFinal()) + { + if (wtx.nLockTime < 500000000) + return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime); + else + return strprintf(_("Open until %s"), DateTimeStr(wtx.nLockTime).c_str()); + } + else + { + int nDepth = wtx.GetDepthInMainChain(); + if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + return strprintf(_("%d/offline?"), nDepth); + else if (nDepth < 6) + return strprintf(_("%d/unconfirmed"), nDepth); + else + return strprintf(_("%d confirmations"), nDepth); + } +#endif +} + +QVariant TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const +{ + return QVariant(); +} + +QVariant TransactionTableModel::formatTxDescription(const TransactionRecord *wtx) const +{ + return QVariant(); +} + +QVariant TransactionTableModel::formatTxDebit(const TransactionRecord *wtx) const +{ + return QVariant(); +} + +QVariant TransactionTableModel::formatTxCredit(const TransactionRecord *wtx) const +{ + return QVariant(); +} + QVariant TransactionTableModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); + TransactionRecord *rec = static_cast(index.internalPointer()); if(role == Qt::DisplayRole) { - /* index.row(), index.column() */ - /* Return QString */ - return QLocale::system().toString(index.row()); + switch(index.column()) + { + case Status: + return formatTxStatus(rec); + case Date: + return formatTxDate(rec); + case Description: + return formatTxDescription(rec); + case Debit: + return formatTxDebit(rec); + case Credit: + return formatTxCredit(rec); + } } else if (role == Qt::TextAlignmentRole) { return column_alignments[index.column()]; @@ -82,8 +266,19 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat Qt::ItemFlags TransactionTableModel::flags(const QModelIndex &index) const { - if (!index.isValid()) - return Qt::ItemIsEnabled; - return QAbstractTableModel::flags(index); } + + +QModelIndex TransactionTableModel::index ( int row, int column, const QModelIndex & parent ) const +{ + Q_UNUSED(parent); + TransactionRecord *data = impl->index(row); + if(data) + { + return createIndex(row, column, impl->index(row)); + } else { + return QModelIndex(); + } +} +