Implement filter row instead of tabs, allows for more expressive filters
authorWladimir J. van der Laan <laanwj@gmail.com>
Tue, 28 Jun 2011 19:41:56 +0000 (21:41 +0200)
committerWladimir J. van der Laan <laanwj@gmail.com>
Wed, 29 Jun 2011 21:09:55 +0000 (23:09 +0200)
13 files changed:
bitcoin-qt.pro
src/qt/bitcoingui.cpp
src/qt/bitcoingui.h
src/qt/guiutil.cpp
src/qt/guiutil.h
src/qt/sendcoinsdialog.cpp
src/qt/transactionfilterproxy.cpp [new file with mode: 0644]
src/qt/transactionfilterproxy.h [new file with mode: 0644]
src/qt/transactionrecord.h
src/qt/transactiontablemodel.cpp
src/qt/transactiontablemodel.h
src/qt/transactionview.cpp [new file with mode: 0644]
src/qt/transactionview.h [new file with mode: 0644]

index 4036c14..76841f8 100644 (file)
@@ -72,7 +72,9 @@ HEADERS += src/qt/bitcoingui.h \
     src/qt/transactiondescdialog.h \
     src/qt/bitcoinamountfield.h \
     src/wallet.h \
-    src/keystore.h
+    src/keystore.h \
+    src/qt/transactionfilterproxy.h \
+    src/qt/transactionview.h
 SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
     src/qt/transactiontablemodel.cpp \
     src/qt/addresstablemodel.cpp \
@@ -105,7 +107,9 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
     src/qt/bitcoinstrings.cpp \
     src/qt/bitcoinamountfield.cpp \
     src/wallet.cpp \
-    src/keystore.cpp
+    src/keystore.cpp \
+    src/qt/transactionfilterproxy.cpp \
+    src/qt/transactionview.cpp
 
 RESOURCES += \
     src/qt/bitcoin.qrc
index 5bf79ee..44f7746 100644 (file)
@@ -15,6 +15,7 @@
 #include "optionsmodel.h"
 #include "transactiondescdialog.h"
 #include "addresstablemodel.h"
+#include "transactionview.h"
 
 #include "headers.h"
 
 #include <QToolBar>
 #include <QStatusBar>
 #include <QLabel>
-#include <QTableView>
 #include <QLineEdit>
 #include <QPushButton>
-#include <QHeaderView>
 #include <QLocale>
-#include <QSortFilterProxyModel>
 #include <QClipboard>
 #include <QMessageBox>
 #include <QProgressBar>
@@ -104,7 +102,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
     vbox->addLayout(hbox_address);
     vbox->addLayout(hbox_balance);
 
-    vbox->addWidget(createTabs());
+    transactionView = new TransactionView(this);
+    connect(transactionView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(transactionDetails(const QModelIndex&)));
+    vbox->addWidget(transactionView);
 
     QWidget *centralwidget = new QWidget(this);
     centralwidget->setLayout(vbox);
@@ -198,7 +198,11 @@ void BitcoinGUI::setModel(ClientModel *model)
     connect(model, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));    
 
     // Put transaction list in tabs
-    setTabsModel(model->getTransactionTableModel());
+    transactionView->setModel(model->getTransactionTableModel());
+
+    // Balloon popup for new transaction
+    connect(model->getTransactionTableModel(), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
+            this, SLOT(incomingTransaction(const QModelIndex &, int, int)));
 }
 
 void BitcoinGUI::createTrayIcon()
@@ -227,69 +231,6 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
     }
 }
 
-QWidget *BitcoinGUI::createTabs()
-{
-    QStringList tab_labels;
-    tab_labels  << tr("All transactions")
-                << tr("Sent/Received")
-                << tr("Sent")
-                << tr("Received");
-
-    QTabWidget *tabs = new QTabWidget(this);
-    for(int i = 0; i < tab_labels.size(); ++i)
-    {
-        QTableView *view = new QTableView(this);
-        tabs->addTab(view, tab_labels.at(i));
-
-        connect(view, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(transactionDetails(const QModelIndex&)));
-        transactionViews.append(view);
-    }
-
-    return tabs;
-}
-
-void BitcoinGUI::setTabsModel(QAbstractItemModel *transaction_model)
-{
-    QStringList tab_filters;
-    tab_filters << "^."
-            << "^["+TransactionTableModel::Sent+TransactionTableModel::Received+"]"
-            << "^["+TransactionTableModel::Sent+"]"
-            << "^["+TransactionTableModel::Received+"]";
-
-    for(int i = 0; i < transactionViews.size(); ++i)
-    {
-        QSortFilterProxyModel *proxy_model = new QSortFilterProxyModel(this);
-        proxy_model->setSourceModel(transaction_model);
-        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 = transactionViews.at(i);
-        transaction_table->setModel(proxy_model);
-        transaction_table->setAlternatingRowColors(true);
-        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(
-                TransactionTableModel::Status, 23);
-        transaction_table->horizontalHeader()->resizeSection(
-                TransactionTableModel::Date, 120);
-        transaction_table->horizontalHeader()->resizeSection(
-                TransactionTableModel::Type, 120);
-        transaction_table->horizontalHeader()->setResizeMode(
-                TransactionTableModel::ToAddress, QHeaderView::Stretch);
-        transaction_table->horizontalHeader()->resizeSection(
-                TransactionTableModel::Amount, 79);
-    }
-
-    connect(transaction_model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
-            this, SLOT(incomingTransaction(const QModelIndex &, int, int)));
-}
-
 void BitcoinGUI::sendcoinsClicked()
 {
     SendCoinsDialog dlg;
index b3559c3..f6241a4 100644 (file)
@@ -6,6 +6,7 @@
 
 class TransactionTableModel;
 class ClientModel;
+class TransactionView;
 
 QT_BEGIN_NAMESPACE
 class QLabel;
@@ -56,12 +57,11 @@ private:
     QAction *openBitcoin;
 
     QSystemTrayIcon *trayIcon;
-    QList<QTableView *> transactionViews;
+    TransactionView *transactionView;
 
     void createActions();
     QWidget *createTabs();
     void createTrayIcon();
-    void setTabsModel(QAbstractItemModel *transaction_model);
 
 public slots:
     void setBalance(qint64 balance);
index ec8b435..c68532b 100644 (file)
@@ -1,5 +1,6 @@
 #include "guiutil.h"
 #include "bitcoinaddressvalidator.h"
+#include "util.h"
 
 #include <QString>
 #include <QDateTime>
@@ -36,3 +37,12 @@ void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
     widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
 }
 
+bool GUIUtil::parseMoney(const QString &amount, qint64 *val_out)
+{
+    return ParseMoney(amount.toStdString(), *val_out);
+}
+
+QString GUIUtil::formatMoney(qint64 amount, bool plussign)
+{
+    return QString::fromStdString(FormatMoney(amount, plussign));
+}
index 748e29b..58f8979 100644 (file)
@@ -14,12 +14,18 @@ class GUIUtil
 public:
     static QString DateTimeStr(qint64 nTime);
 
-    /* Render bitcoin addresses in monospace font */
+    // Render bitcoin addresses in monospace font
     static QFont bitcoinAddressFont();
 
     static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
 
     static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
+
+    // Convenience wrapper around ParseMoney that takes QString
+    static bool parseMoney(const QString &amount, qint64 *val_out);
+
+    // Convenience wrapper around FormatMoney that returns QString
+    static QString formatMoney(qint64 amount, bool plussign=false);
 };
 
 #endif // GUIUTIL_H
index 67c270e..33d9a25 100644 (file)
@@ -12,9 +12,6 @@
 #include <QLocale>
 #include <QDebug>
 
-#include "util.h"
-#include "base58.h"
-
 SendCoinsDialog::SendCoinsDialog(QWidget *parent, const QString &address) :
     QDialog(parent),
     ui(new Ui::SendCoinsDialog),
@@ -49,7 +46,7 @@ void SendCoinsDialog::on_sendButton_clicked()
     QString label;
     qint64 payAmountParsed;
 
-    valid = ParseMoney(payAmount.toStdString(), payAmountParsed);
+    valid = GUIUtil::parseMoney(payAmount, &payAmountParsed);
 
     if(!valid)
     {
@@ -88,7 +85,7 @@ void SendCoinsDialog::on_sendButton_clicked()
     case ClientModel::AmountWithFeeExceedsBalance:
         QMessageBox::warning(this, tr("Send Coins"),
             tr("Total exceeds your balance when the %1 transaction fee is included").
-                arg(QString::fromStdString(FormatMoney(model->getOptionsModel()->getTransactionFee()))),
+            arg(GUIUtil::formatMoney(model->getOptionsModel()->getTransactionFee())),
             QMessageBox::Ok, QMessageBox::Ok);
         ui->payAmount->setFocus();
         break;
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
new file mode 100644 (file)
index 0000000..cd1194d
--- /dev/null
@@ -0,0 +1,67 @@
+#include "transactionfilterproxy.h"
+#include "transactiontablemodel.h"
+
+#include <QDateTime>
+#include <QDebug>
+
+// Earliest date that can be represented (far in the past)
+const QDateTime TransactionFilterProxy::MIN_DATE = QDateTime::fromTime_t(0);
+// Last date that can be represented (far in the future)
+const QDateTime TransactionFilterProxy::MAX_DATE = QDateTime::fromTime_t(0xFFFFFFFF);
+
+TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
+    QSortFilterProxyModel(parent),
+    dateFrom(MIN_DATE),
+    dateTo(MAX_DATE),
+    addrPrefix(),
+    typeFilter(ALL_TYPES),
+    minAmount(0)
+{
+}
+
+bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+    QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+
+    int type = index.data(TransactionTableModel::TypeRole).toInt();
+    QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime();
+    QString address = index.data(TransactionTableModel::AddressRole).toString();
+    QString label = index.data(TransactionTableModel::LabelRole).toString();
+    qint64 amount = index.data(TransactionTableModel::AbsoluteAmountRole).toLongLong();
+
+    if(!(TYPE(type) & typeFilter))
+        return false;
+    if(datetime < dateFrom || datetime > dateTo)
+        return false;
+    if(!address.startsWith(addrPrefix) && !label.startsWith(addrPrefix))
+        return false;
+    if(amount < minAmount)
+        return false;
+
+    return true;
+}
+
+void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime &to)
+{
+    this->dateFrom = from;
+    this->dateTo = to;
+    invalidateFilter();
+}
+
+void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
+{
+    this->addrPrefix = addrPrefix;
+    invalidateFilter();
+}
+
+void TransactionFilterProxy::setTypeFilter(quint32 modes)
+{
+    this->typeFilter = modes;
+    invalidateFilter();
+}
+
+void TransactionFilterProxy::setMinAmount(qint64 minimum)
+{
+    this->minAmount = minimum;
+    invalidateFilter();
+}
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
new file mode 100644 (file)
index 0000000..a44c9c4
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef TRANSACTIONFILTERPROXY_H
+#define TRANSACTIONFILTERPROXY_H
+
+#include <QSortFilterProxyModel>
+#include <QDateTime>
+
+// Filter transaction list according to pre-specified rules
+class TransactionFilterProxy : public QSortFilterProxyModel
+{
+    Q_OBJECT
+public:
+    explicit TransactionFilterProxy(QObject *parent = 0);
+
+    // Earliest date that can be represented (far in the past)
+    static const QDateTime MIN_DATE;
+    // Last date that can be represented (far in the future)
+    static const QDateTime MAX_DATE;
+    // Type filter bit field (all types)
+    static const quint32 ALL_TYPES = 0xFFFFFFFF;
+
+    static quint32 TYPE(int type) { return 1<<type; }
+
+    void setDateRange(const QDateTime &from, const QDateTime &to);
+    void setAddressPrefix(const QString &addrPrefix);
+    // Type filter takes a bitfield created with TYPE() or ALL_TYPES
+    void setTypeFilter(quint32 modes);
+    void setMinAmount(qint64 minimum);
+
+protected:
+    bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const;
+
+private:
+    QDateTime dateFrom;
+    QDateTime dateTo;
+    QString addrPrefix;
+    quint32 typeFilter;
+    qint64 minAmount;
+
+signals:
+
+public slots:
+
+};
+
+#endif // TRANSACTIONFILTERPROXY_H
index ba071df..c196be2 100644 (file)
@@ -1,11 +1,12 @@
 #ifndef TRANSACTIONRECORD_H
 #define TRANSACTIONRECORD_H
 
-#include "main.h"
+#include "uint256.h"
 
 #include <QList>
 
 class CWallet;
+class CWalletTx;
 
 class TransactionStatus
 {
index e49629c..28d22b8 100644 (file)
@@ -12,6 +12,7 @@
 #include <QColor>
 #include <QTimer>
 #include <QIcon>
+#include <QDateTime>
 #include <QtAlgorithms>
 
 const QString TransactionTableModel::Sent = "s";
@@ -301,27 +302,38 @@ QVariant TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const
     }
 }
 
-/* Look up address in address book, if found return
-     address[0:12]... (label)
-   otherwise just return address
+/* Look up label for address in address book, if not found return empty string.
+   This should really move to the wallet class.
  */
-std::string TransactionTableModel::lookupAddress(const std::string &address) const
+QString TransactionTableModel::labelForAddress(const std::string &address) const
 {
-    std::string description;
     CRITICAL_BLOCK(wallet->cs_mapAddressBook)
     {
         std::map<std::string, std::string>::iterator mi = wallet->mapAddressBook.find(address);
-        if (mi != wallet->mapAddressBook.end() && !(*mi).second.empty())
-        {
-            std::string label = (*mi).second;
-            description += address.substr(0,12) + "... ";
-            description += "(" + label + ")";
-        }
-        else
+        if (mi != wallet->mapAddressBook.end())
         {
-            description += address;
+            return QString::fromStdString(mi->second);
         }
     }
+    return QString();
+}
+
+/* Look up address in address book, if found return
+     address[0:12]... (label)
+   otherwise just return address
+ */
+QString TransactionTableModel::lookupAddress(const std::string &address) const
+{
+    QString label = labelForAddress(address);
+    QString description;
+    if(label.isEmpty())
+    {
+        description = QString::fromStdString(address);
+    }
+    else
+    {
+        description = QString::fromStdString(address.substr(0,12)) + QString("... (") + label + QString(")");
+    }
     return description;
 }
 
@@ -360,13 +372,13 @@ QVariant TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx)
     switch(wtx->type)
     {
     case TransactionRecord::RecvWithAddress:
-        description = QString::fromStdString(lookupAddress(wtx->address));
+        description = lookupAddress(wtx->address);
         break;
     case TransactionRecord::RecvFromIP:
         description = QString::fromStdString(wtx->address);
         break;
     case TransactionRecord::SendToAddress:
-        description = QString::fromStdString(lookupAddress(wtx->address));
+        description = lookupAddress(wtx->address);
         break;
     case TransactionRecord::SendToIP:
         description = QString::fromStdString(wtx->address);
@@ -502,24 +514,28 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
     }
     else if (role == TypeRole)
     {
-        /* Role for filtering tabs by type */
-        switch(rec->type)
-        {
-        case TransactionRecord::RecvWithAddress:
-        case TransactionRecord::RecvFromIP:
-            return TransactionTableModel::Received;
-        case TransactionRecord::SendToAddress:
-        case TransactionRecord::SendToIP:
-        case TransactionRecord::SendToSelf:
-            return TransactionTableModel::Sent;
-        default:
-            return TransactionTableModel::Other;
-        }
+        return rec->type;
+    }
+    else if (role == DateRole)
+    {
+        return QDateTime::fromTime_t(static_cast<uint>(rec->time));
     }
     else if (role == LongDescriptionRole)
     {
         return priv->describe(rec);
     }
+    else if (role == AddressRole)
+    {
+        return QString::fromStdString(rec->address);
+    }
+    else if (role == LabelRole)
+    {
+        return labelForAddress(rec->address);
+    }
+    else if (role == AbsoluteAmountRole)
+    {
+        return llabs(rec->credit + rec->debit);
+    }
     return QVariant();
 }
 
index d19e1a3..c26acbc 100644 (file)
@@ -23,9 +23,20 @@ public:
         Amount = 4
     } ColumnIndex;
 
+    // Roles to get specific information from a transaction row
     enum {
+        // Type of transaction
         TypeRole = Qt::UserRole,
-        LongDescriptionRole = Qt::UserRole+1
+        // Date and time this transaction was created
+        DateRole,
+        // Long description (HTML format)
+        LongDescriptionRole,
+        // Address of transaction
+        AddressRole,
+        // Label of address related to transaction
+        LabelRole,
+        // Absolute net amount of transaction
+        AbsoluteAmountRole
     } RoleIndex;
 
     /* TypeRole values */
@@ -44,7 +55,8 @@ private:
     QStringList columns;
     TransactionTablePriv *priv;
 
-    std::string lookupAddress(const std::string &address) const;
+    QString labelForAddress(const std::string &address) const;
+    QString lookupAddress(const std::string &address) const;
     QVariant formatTxStatus(const TransactionRecord *wtx) const;
     QVariant formatTxDate(const TransactionRecord *wtx) const;
     QVariant formatTxType(const TransactionRecord *wtx) const;
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
new file mode 100644 (file)
index 0000000..bf7d55d
--- /dev/null
@@ -0,0 +1,182 @@
+#include "transactionview.h"
+
+// Temp includes for filtering prototype
+// Move to TransactionFilterRow class
+#include "transactionfilterproxy.h"
+#include "transactionrecord.h"
+#include "transactiontablemodel.h"
+#include "guiutil.h"
+
+#include <QScrollBar>
+#include <QComboBox>
+#include <QDoubleValidator>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QLineEdit>
+#include <QTableView>
+#include <QHeaderView>
+
+#include <QDebug>
+
+TransactionView::TransactionView(QWidget *parent) :
+    QWidget(parent), model(0), transactionProxyModel(0),
+    transactionView(0)
+{
+    // Build filter row
+    QHBoxLayout *hlayout = new QHBoxLayout();
+    hlayout->setContentsMargins(QMargins(0,0,0,0));
+    hlayout->setSpacing(0);
+
+    hlayout->addSpacing(23);
+
+    dateWidget = new QComboBox(this);
+    dateWidget->setMaximumWidth(120);
+    dateWidget->setMinimumWidth(120);
+    dateWidget->addItem(tr("All"), All);
+    dateWidget->addItem(tr("Today"), Today);
+    dateWidget->addItem(tr("This week"), ThisWeek);
+    dateWidget->addItem(tr("This month"), ThisMonth);
+    dateWidget->addItem(tr("This year"), ThisYear);
+    dateWidget->addItem(tr("Range..."), Range);
+    hlayout->addWidget(dateWidget);
+
+    typeWidget = new QComboBox(this);
+    typeWidget->setMaximumWidth(120);
+    typeWidget->setMinimumWidth(120);
+
+    typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
+    typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
+                                        TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
+    typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
+                                  TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
+    typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
+    typeWidget->addItem(tr("Generated"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
+    typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
+
+    hlayout->addWidget(typeWidget);
+
+    addressWidget = new QLineEdit(this);
+    addressWidget->setPlaceholderText("Enter address or label to search");
+    hlayout->addWidget(addressWidget);
+
+    amountWidget = new QLineEdit(this);
+    amountWidget->setPlaceholderText("Min amount");
+    amountWidget->setMaximumWidth(79);
+    amountWidget->setMinimumWidth(79);
+    amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
+    hlayout->addWidget(amountWidget);
+
+    QVBoxLayout *vlayout = new QVBoxLayout(this);
+
+    QTableView *view = new QTableView(this);
+    vlayout->addLayout(hlayout);
+    vlayout->addWidget(view);
+    vlayout->setSpacing(0);
+    int width = view->verticalScrollBar()->sizeHint().width();
+    // Cover scroll bar width with spacing
+    hlayout->addSpacing(width);
+    // Always show scroll bar
+    view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
+    transactionView = view;
+
+    connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
+    connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
+    connect(addressWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedPrefix(const QString&)));
+    connect(amountWidget, SIGNAL(textChanged(const QString&)), this, SLOT(changedAmount(const QString&)));
+}
+
+void TransactionView::setModel(TransactionTableModel *model)
+{
+    this->model = model;
+
+    transactionProxyModel = new TransactionFilterProxy(this);
+    transactionProxyModel->setSourceModel(model);
+    transactionProxyModel->setDynamicSortFilter(true);
+
+    transactionProxyModel->setSortRole(Qt::EditRole);
+
+    transactionView->setModel(transactionProxyModel);
+    transactionView->setAlternatingRowColors(true);
+    transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
+    transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+    transactionView->setSortingEnabled(true);
+    transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
+    transactionView->verticalHeader()->hide();
+
+    transactionView->horizontalHeader()->resizeSection(
+            TransactionTableModel::Status, 23);
+    transactionView->horizontalHeader()->resizeSection(
+            TransactionTableModel::Date, 120);
+    transactionView->horizontalHeader()->resizeSection(
+            TransactionTableModel::Type, 120);
+    transactionView->horizontalHeader()->setResizeMode(
+            TransactionTableModel::ToAddress, QHeaderView::Stretch);
+    transactionView->horizontalHeader()->resizeSection(
+            TransactionTableModel::Amount, 79);
+
+}
+
+void TransactionView::chooseDate(int idx)
+{
+    QDate current = QDate::currentDate();
+    switch(dateWidget->itemData(idx).toInt())
+    {
+    case All:
+        transactionProxyModel->setDateRange(
+                TransactionFilterProxy::MIN_DATE,
+                TransactionFilterProxy::MAX_DATE);
+        break;
+    case Today:
+        transactionProxyModel->setDateRange(
+                QDateTime(current),
+                TransactionFilterProxy::MAX_DATE);
+        break;
+    case ThisWeek: {
+        // Find last monday
+        QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
+        transactionProxyModel->setDateRange(
+                QDateTime(startOfWeek),
+                TransactionFilterProxy::MAX_DATE);
+
+        } break;
+    case ThisMonth:
+        transactionProxyModel->setDateRange(
+                QDateTime(QDate(current.year(), current.month(), 1)),
+                TransactionFilterProxy::MAX_DATE);
+        break;
+    case ThisYear:
+        transactionProxyModel->setDateRange(
+                QDateTime(QDate(current.year(), 1, 1)),
+                TransactionFilterProxy::MAX_DATE);
+        break;
+    case Range:
+        // TODO ask specific range
+        break;
+    }
+
+}
+
+void TransactionView::chooseType(int idx)
+{
+    transactionProxyModel->setTypeFilter(
+        typeWidget->itemData(idx).toInt());
+}
+
+void TransactionView::changedPrefix(const QString &prefix)
+{
+    transactionProxyModel->setAddressPrefix(prefix);
+}
+
+void TransactionView::changedAmount(const QString &amount)
+{
+    qint64 amount_parsed;
+    if(GUIUtil::parseMoney(amount, &amount_parsed))
+    {
+        transactionProxyModel->setMinAmount(amount_parsed);
+    }
+    else
+    {
+        transactionProxyModel->setMinAmount(0);
+    }
+}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
new file mode 100644 (file)
index 0000000..e75dcc2
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef TRANSACTIONVIEW_H
+#define TRANSACTIONVIEW_H
+
+#include <QWidget>
+
+class TransactionTableModel;
+class TransactionFilterProxy;
+
+QT_BEGIN_NAMESPACE
+class QTableView;
+class QComboBox;
+class QLineEdit;
+QT_END_NAMESPACE
+
+class TransactionView : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit TransactionView(QWidget *parent = 0);
+
+    void setModel(TransactionTableModel *model);
+
+    enum DateEnum
+    {
+        All,
+        Today,
+        ThisWeek,
+        ThisMonth,
+        ThisYear,
+        Range
+    };
+
+private:
+    TransactionTableModel *model;
+    TransactionFilterProxy *transactionProxyModel;
+    QTableView *transactionView;
+
+    QComboBox *dateWidget;
+    QComboBox *typeWidget;
+    QLineEdit *addressWidget;
+    QLineEdit *amountWidget;
+
+signals:
+
+public slots:
+    void chooseDate(int idx);
+    void chooseType(int idx);
+    void changedPrefix(const QString &prefix);
+    void changedAmount(const QString &amount);
+
+};
+
+#endif // TRANSACTIONVIEW_H