#include "transactionview.h" #include "transactionfilterproxy.h" #include "transactionrecord.h" #include "walletmodel.h" #include "addresstablemodel.h" #include "transactiontablemodel.h" #include "guiutil.h" #include "csvmodelwriter.h" #include "transactiondescdialog.h" #include "editaddressdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include TransactionView::TransactionView(QWidget *parent) : QWidget(parent), model(0), transactionProxyModel(0), transactionView(0) { // Build filter row setContentsMargins(0,0,0,0); QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setContentsMargins(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("Last month"), LastMonth); 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("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); hlayout->addWidget(typeWidget); addressWidget = new QLineEdit(this); #if QT_VERSION >= 0x040700 addressWidget->setPlaceholderText("Enter address or label to search"); #endif hlayout->addWidget(addressWidget); amountWidget = new QLineEdit(this); #if QT_VERSION >= 0x040700 amountWidget->setPlaceholderText("Min amount"); #endif amountWidget->setMaximumWidth(100); amountWidget->setMinimumWidth(100); amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); hlayout->addWidget(amountWidget); QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setContentsMargins(0,0,0,0); vlayout->setSpacing(0); //vlayout->addLayout(hlayout2); 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); view->setTabKeyNavigation(false); view->setContextMenuPolicy(Qt::CustomContextMenu); transactionView = view; // Actions QAction *copyAddressAction = new QAction("Copy address", this); QAction *copyLabelAction = new QAction("Copy label", this); QAction *editLabelAction = new QAction("Edit label", this); QAction *showDetailsAction = new QAction("Show details...", this); contextMenu = new QMenu(); contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(editLabelAction); contextMenu->addAction(showDetailsAction); // Connect actions 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&))); connect(view, SIGNAL(doubleClicked(const QModelIndex&)), this, SIGNAL(doubleClicked(const QModelIndex&))); connect(view, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextualMenu(const QPoint &))); connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel())); connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } void TransactionView::setModel(WalletModel *model) { this->model = model; transactionProxyModel = new TransactionFilterProxy(this); transactionProxyModel->setSourceModel(model->getTransactionTableModel()); 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, 100); } 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 LastMonth: transactionProxyModel->setDateRange( QDateTime(QDate(current.year(), current.month()-1, 1)), QDateTime(QDate(current.year(), current.month(), 1))); 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 = 0; if(GUIUtil::parseMoney(amount, &amount_parsed)) { transactionProxyModel->setMinAmount(amount_parsed); } else { transactionProxyModel->setMinAmount(0); } } void TransactionView::exportClicked() { // CSV is currently the only supported format QString filename = QFileDialog::getSaveFileName( this, tr("Export Transaction Data"), QDir::currentPath(), tr("Comma separated file (*.csv)")); if(!filename.endsWith(".csv")) { filename += ".csv"; } CSVModelWriter writer(filename); // name, column, role writer.setModel(transactionProxyModel); writer.addColumn("Confirmed", 0, TransactionTableModel::ConfirmedRole); writer.addColumn("Date", 0, TransactionTableModel::DateRole); writer.addColumn("Type", TransactionTableModel::Type, Qt::EditRole); writer.addColumn("Label", 0, TransactionTableModel::LabelRole); writer.addColumn("Address", 0, TransactionTableModel::AddressRole); writer.addColumn("Amount", 0, TransactionTableModel::FormattedAmountRole); writer.addColumn("ID", 0, TransactionTableModel::TxIDRole); if(!writer.write()) { QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename), QMessageBox::Abort, QMessageBox::Abort); } } void TransactionView::contextualMenu(const QPoint &point) { QModelIndex index = transactionView->indexAt(point); if(index.isValid()) { contextMenu->exec(QCursor::pos()); } } void TransactionView::copyAddress() { QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::AddressRole).toString()); } } void TransactionView::copyLabel() { QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::LabelRole).toString()); } } void TransactionView::editLabel() { QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { AddressTableModel *addressBook = model->getAddressTableModel(); QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString(); if(address.isEmpty()) { // If this transaction has no associated address, exit return; } int idx = addressBook->lookupAddress(address); if(idx != -1) { // Edit sending / receiving address QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex()); // Determine type of address, launch appropriate editor dialog type QString type = modelIdx.data(AddressTableModel::TypeRole).toString(); EditAddressDialog dlg(type==AddressTableModel::Receive ? EditAddressDialog::EditReceivingAddress : EditAddressDialog::EditSendingAddress, this); dlg.setModel(addressBook); dlg.loadRow(idx); dlg.exec(); } else { // Add sending address EditAddressDialog dlg(EditAddressDialog::NewSendingAddress, this); dlg.exec(); } } } void TransactionView::showDetails() { QModelIndexList selection = transactionView->selectionModel()->selectedRows(); if(!selection.isEmpty()) { TransactionDescDialog dlg(selection.at(0)); dlg.exec(); } }