diff --git a/bitcoin.pro b/bitcoin.pro index 5f406e82f..e4d694eb4 100644 --- a/bitcoin.pro +++ b/bitcoin.pro @@ -56,7 +56,8 @@ HEADERS += gui/include/bitcoingui.h \ gui/src/clientmodel.h \ gui/include/clientmodel.h \ gui/include/guiutil.h \ - gui/include/transactionrecord.h + gui/include/transactionrecord.h \ + gui/include/guiconstants.h SOURCES += gui/src/bitcoin.cpp gui/src/bitcoingui.cpp \ gui/src/transactiontablemodel.cpp \ gui/src/addresstablemodel.cpp \ diff --git a/gui/include/guiconstants.h b/gui/include/guiconstants.h new file mode 100644 index 000000000..cdd1a74d9 --- /dev/null +++ b/gui/include/guiconstants.h @@ -0,0 +1,11 @@ +#ifndef GUICONSTANTS_H +#define GUICONSTANTS_H + +/* milliseconds between model updates */ +static const int MODEL_UPDATE_DELAY = 250; + +/* size of cache */ +static const unsigned int WALLET_CACHE_SIZE = 100; + + +#endif // GUICONSTANTS_H diff --git a/gui/include/transactionrecord.h b/gui/include/transactionrecord.h index 646f87c91..9769d8061 100644 --- a/gui/include/transactionrecord.h +++ b/gui/include/transactionrecord.h @@ -75,6 +75,8 @@ public: { } + /* Decompose CWallet transaction to model transaction records. + */ static bool showTransaction(const CWalletTx &wtx); static QList decomposeTransaction(const CWalletTx &wtx); diff --git a/gui/include/transactiontablemodel.h b/gui/include/transactiontablemodel.h index 1ea749d86..b02019d47 100644 --- a/gui/include/transactiontablemodel.h +++ b/gui/include/transactiontablemodel.h @@ -37,8 +37,6 @@ public: 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; -public slots: - void updateWallet(); private: QStringList columns; TransactionTableImpl *impl; @@ -48,6 +46,9 @@ private: QVariant formatTxDescription(const TransactionRecord *wtx) const; QVariant formatTxDebit(const TransactionRecord *wtx) const; QVariant formatTxCredit(const TransactionRecord *wtx) const; + +private slots: + void update(); }; #endif diff --git a/gui/src/bitcoingui.cpp b/gui/src/bitcoingui.cpp index 831bef3f2..b409744b9 100644 --- a/gui/src/bitcoingui.cpp +++ b/gui/src/bitcoingui.cpp @@ -147,7 +147,7 @@ void BitcoinGUI::setModel(ClientModel *model) this->model = model; setBalance(model->getBalance()); - connect(model, SIGNAL(balanceChanged(double)), this, SLOT(setBalance(double))); + connect(model, SIGNAL(balanceChanged(qint64)), this, SLOT(setBalance(qint64))); setNumConnections(model->getNumConnections()); connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); @@ -197,12 +197,14 @@ QWidget *BitcoinGUI::createTabs() proxy_model->setDynamicSortFilter(true); proxy_model->setFilterRole(TransactionTableModel::TypeRole); proxy_model->setFilterRegExp(QRegExp(tab_filters.at(i))); + proxy_model->setSortRole(Qt::EditRole); QTableView *transaction_table = new QTableView(this); transaction_table->setModel(proxy_model); transaction_table->setSelectionBehavior(QAbstractItemView::SelectRows); transaction_table->setSelectionMode(QAbstractItemView::ExtendedSelection); transaction_table->setSortingEnabled(true); + transaction_table->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder); transaction_table->verticalHeader()->hide(); transaction_table->horizontalHeader()->resizeSection( diff --git a/gui/src/clientmodel.cpp b/gui/src/clientmodel.cpp index cc52df412..e355676cd 100644 --- a/gui/src/clientmodel.cpp +++ b/gui/src/clientmodel.cpp @@ -1,11 +1,9 @@ #include "clientmodel.h" #include "main.h" +#include "guiconstants.h" #include -/* milliseconds between model updates */ -const int MODEL_UPDATE_DELAY = 250; - ClientModel::ClientModel(QObject *parent) : QObject(parent) { diff --git a/gui/src/transactiontablemodel.cpp b/gui/src/transactiontablemodel.cpp index af8234bdd..3a501979f 100644 --- a/gui/src/transactiontablemodel.cpp +++ b/gui/src/transactiontablemodel.cpp @@ -1,12 +1,14 @@ #include "transactiontablemodel.h" #include "guiutil.h" #include "transactionrecord.h" +#include "guiconstants.h" #include "main.h" #include #include #include #include +#include const QString TransactionTableModel::Sent = "s"; const QString TransactionTableModel::Received = "r"; @@ -16,14 +18,15 @@ const QString TransactionTableModel::Other = "o"; class TransactionTableImpl { public: + /* Local cache of wallet. + * As it is in the same order as the CWallet, by definition + * this is sorted by sha256. + */ QList cachedWallet; - /* Update our model of the wallet */ - void updateWallet() + void refreshWallet() { - QList insertedIndices; - QList removedIndices; - + qDebug() << "refreshWallet"; cachedWallet.clear(); /* Query wallet from core, and compare with our own @@ -45,6 +48,26 @@ public: /* beginEndRows */ } + /* Update our model of the wallet. + Call with list of hashes of transactions that were added, removed or changed. + */ + void updateWallet(const QList &updated) + { + /* TODO: update only transactions in updated, and only if + the transactions are really part of the visible wallet. + + Update status of the other transactions in the cache just in case, + because this call means that a new block came in. + */ + qDebug() << "updateWallet"; + foreach(uint256 hash, updated) + { + qDebug() << " " << QString::fromStdString(hash.ToString()); + } + + refreshWallet(); + } + int size() { return cachedWallet.size(); @@ -59,6 +82,7 @@ public: return 0; } } + }; /* Credit and Debit columns are right-aligned as they contain numbers */ @@ -77,7 +101,11 @@ TransactionTableModel::TransactionTableModel(QObject *parent): { columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit"); - impl->updateWallet(); + impl->refreshWallet(); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(MODEL_UPDATE_DELAY); } TransactionTableModel::~TransactionTableModel() @@ -85,15 +113,33 @@ TransactionTableModel::~TransactionTableModel() delete impl; } -void TransactionTableModel::updateWallet() +void TransactionTableModel::update() { - /* TODO: improve this, way too brute-force at the moment, - only update transactions that actually changed, and add/remove - transactions that were added/removed. - */ - beginResetModel(); - impl->updateWallet(); - endResetModel(); + QList updated; + + /* Check if there are changes to wallet map */ + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + if(!vWalletUpdated.empty()) + { + BOOST_FOREACH(uint256 hash, vWalletUpdated) + { + updated.append(hash); + } + vWalletUpdated.clear(); + } + } + + if(!updated.empty()) + { + /* TODO: improve this, way too brute-force at the moment, + only update transactions that actually changed, and add/remove + transactions that were added/removed. + */ + beginResetModel(); + impl->updateWallet(updated); + endResetModel(); + } } int TransactionTableModel::rowCount(const QModelIndex &parent) const @@ -261,6 +307,22 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case Credit: return formatTxCredit(rec); } + } else if(role == Qt::EditRole) + { + /* Edit role is used for sorting so return the real values */ + switch(index.column()) + { + case Status: + return QString::fromStdString(rec->status.sortKey); + case Date: + return rec->time; + case Description: + return formatTxDescription(rec); + case Debit: + return rec->debit; + case Credit: + return rec->credit; + } } else if (role == Qt::TextAlignmentRole) { return column_alignments[index.column()];