1 #include "transactionview.h"
3 #include "transactionfilterproxy.h"
4 #include "transactionrecord.h"
5 #include "walletmodel.h"
6 #include "addresstablemodel.h"
7 #include "transactiontablemodel.h"
8 #include "bitcoinunits.h"
9 #include "csvmodelwriter.h"
10 #include "transactiondescdialog.h"
11 #include "editaddressdialog.h"
12 #include "optionsmodel.h"
16 #include <QDoubleValidator>
17 #include <QHBoxLayout>
18 #include <QVBoxLayout>
21 #include <QHeaderView>
22 #include <QPushButton>
23 #include <QFileDialog>
24 #include <QMessageBox>
27 #include <QApplication>
30 #include <QDateTimeEdit>
34 TransactionView::TransactionView(QWidget *parent) :
35 QWidget(parent), model(0), transactionProxyModel(0),
39 setContentsMargins(0,0,0,0);
41 QHBoxLayout *hlayout = new QHBoxLayout();
42 hlayout->setContentsMargins(0,0,0,0);
43 hlayout->setSpacing(0);
45 hlayout->addSpacing(23);
47 dateWidget = new QComboBox(this);
48 dateWidget->setMaximumWidth(120);
49 dateWidget->setMinimumWidth(120);
50 dateWidget->addItem(tr("All"), All);
51 dateWidget->addItem(tr("Today"), Today);
52 dateWidget->addItem(tr("This week"), ThisWeek);
53 dateWidget->addItem(tr("This month"), ThisMonth);
54 dateWidget->addItem(tr("Last month"), LastMonth);
55 dateWidget->addItem(tr("This year"), ThisYear);
56 dateWidget->addItem(tr("Range..."), Range);
57 hlayout->addWidget(dateWidget);
59 typeWidget = new QComboBox(this);
60 typeWidget->setMaximumWidth(120);
61 typeWidget->setMinimumWidth(120);
63 typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
64 typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
65 TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
66 typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
67 TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
68 typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
69 typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
70 typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
72 hlayout->addWidget(typeWidget);
74 addressWidget = new QLineEdit(this);
75 #if QT_VERSION >= 0x040700
76 addressWidget->setPlaceholderText("Enter address or label to search");
78 hlayout->addWidget(addressWidget);
80 amountWidget = new QLineEdit(this);
81 #if QT_VERSION >= 0x040700
82 amountWidget->setPlaceholderText("Min amount");
84 amountWidget->setMaximumWidth(100);
85 amountWidget->setMinimumWidth(100);
86 amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
87 hlayout->addWidget(amountWidget);
89 QVBoxLayout *vlayout = new QVBoxLayout(this);
90 vlayout->setContentsMargins(0,0,0,0);
91 vlayout->setSpacing(0);
92 //vlayout->addLayout(hlayout2);
94 QTableView *view = new QTableView(this);
95 vlayout->addLayout(hlayout);
96 vlayout->addWidget(createDateRangeWidget());
97 vlayout->addWidget(view);
98 vlayout->setSpacing(0);
99 int width = view->verticalScrollBar()->sizeHint().width();
100 // Cover scroll bar width with spacing
101 hlayout->addSpacing(width);
102 // Always show scroll bar
103 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
104 view->setTabKeyNavigation(false);
105 view->setContextMenuPolicy(Qt::CustomContextMenu);
107 transactionView = view;
110 QAction *copyAddressAction = new QAction("Copy address", this);
111 QAction *copyLabelAction = new QAction("Copy label", this);
112 QAction *editLabelAction = new QAction("Edit label", this);
113 QAction *showDetailsAction = new QAction("Show details...", this);
115 contextMenu = new QMenu();
116 contextMenu->addAction(copyAddressAction);
117 contextMenu->addAction(copyLabelAction);
118 contextMenu->addAction(editLabelAction);
119 contextMenu->addAction(showDetailsAction);
122 connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
123 connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
124 connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
125 connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
127 connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
130 SIGNAL(customContextMenuRequested(QPoint)),
132 SLOT(contextualMenu(QPoint)));
134 connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
135 connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
136 connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
137 connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
140 void TransactionView::setModel(WalletModel *model)
144 transactionProxyModel = new TransactionFilterProxy(this);
145 transactionProxyModel->setSourceModel(model->getTransactionTableModel());
146 transactionProxyModel->setDynamicSortFilter(true);
148 transactionProxyModel->setSortRole(Qt::EditRole);
150 transactionView->setModel(transactionProxyModel);
151 transactionView->setAlternatingRowColors(true);
152 transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
153 transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
154 transactionView->setSortingEnabled(true);
155 transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
156 transactionView->verticalHeader()->hide();
158 transactionView->horizontalHeader()->resizeSection(
159 TransactionTableModel::Status, 23);
160 transactionView->horizontalHeader()->resizeSection(
161 TransactionTableModel::Date, 120);
162 transactionView->horizontalHeader()->resizeSection(
163 TransactionTableModel::Type, 120);
164 transactionView->horizontalHeader()->setResizeMode(
165 TransactionTableModel::ToAddress, QHeaderView::Stretch);
166 transactionView->horizontalHeader()->resizeSection(
167 TransactionTableModel::Amount, 100);
171 void TransactionView::chooseDate(int idx)
173 QDate current = QDate::currentDate();
174 dateRangeWidget->setVisible(false);
175 switch(dateWidget->itemData(idx).toInt())
178 transactionProxyModel->setDateRange(
179 TransactionFilterProxy::MIN_DATE,
180 TransactionFilterProxy::MAX_DATE);
183 transactionProxyModel->setDateRange(
185 TransactionFilterProxy::MAX_DATE);
189 QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
190 transactionProxyModel->setDateRange(
191 QDateTime(startOfWeek),
192 TransactionFilterProxy::MAX_DATE);
196 transactionProxyModel->setDateRange(
197 QDateTime(QDate(current.year(), current.month(), 1)),
198 TransactionFilterProxy::MAX_DATE);
201 transactionProxyModel->setDateRange(
202 QDateTime(QDate(current.year(), current.month()-1, 1)),
203 QDateTime(QDate(current.year(), current.month(), 1)));
206 transactionProxyModel->setDateRange(
207 QDateTime(QDate(current.year(), 1, 1)),
208 TransactionFilterProxy::MAX_DATE);
211 dateRangeWidget->setVisible(true);
217 void TransactionView::chooseType(int idx)
219 transactionProxyModel->setTypeFilter(
220 typeWidget->itemData(idx).toInt());
223 void TransactionView::changedPrefix(const QString &prefix)
225 transactionProxyModel->setAddressPrefix(prefix);
228 void TransactionView::changedAmount(const QString &amount)
230 qint64 amount_parsed = 0;
231 if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
233 transactionProxyModel->setMinAmount(amount_parsed);
237 transactionProxyModel->setMinAmount(0);
241 void TransactionView::exportClicked()
243 // CSV is currently the only supported format
244 QString filename = QFileDialog::getSaveFileName(
246 tr("Export Transaction Data"),
248 tr("Comma separated file (*.csv)"));
250 if (filename.isNull()) return;
252 CSVModelWriter writer(filename);
254 // name, column, role
255 writer.setModel(transactionProxyModel);
256 writer.addColumn("Confirmed", 0, TransactionTableModel::ConfirmedRole);
257 writer.addColumn("Date", 0, TransactionTableModel::DateRole);
258 writer.addColumn("Type", TransactionTableModel::Type, Qt::EditRole);
259 writer.addColumn("Label", 0, TransactionTableModel::LabelRole);
260 writer.addColumn("Address", 0, TransactionTableModel::AddressRole);
261 writer.addColumn("Amount", 0, TransactionTableModel::FormattedAmountRole);
262 writer.addColumn("ID", 0, TransactionTableModel::TxIDRole);
266 QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
267 QMessageBox::Abort, QMessageBox::Abort);
271 void TransactionView::contextualMenu(const QPoint &point)
273 QModelIndex index = transactionView->indexAt(point);
276 contextMenu->exec(QCursor::pos());
280 void TransactionView::copyAddress()
282 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
283 if(!selection.isEmpty())
285 QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::AddressRole).toString());
289 void TransactionView::copyLabel()
291 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
292 if(!selection.isEmpty())
294 QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::LabelRole).toString());
298 void TransactionView::editLabel()
300 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
301 if(!selection.isEmpty())
303 AddressTableModel *addressBook = model->getAddressTableModel();
304 QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
305 if(address.isEmpty())
307 // If this transaction has no associated address, exit
310 int idx = addressBook->lookupAddress(address);
313 // Edit sending / receiving address
314 QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
315 // Determine type of address, launch appropriate editor dialog type
316 QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
318 EditAddressDialog dlg(type==AddressTableModel::Receive
319 ? EditAddressDialog::EditReceivingAddress
320 : EditAddressDialog::EditSendingAddress,
322 dlg.setModel(addressBook);
328 // Add sending address
329 EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
336 void TransactionView::showDetails()
338 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
339 if(!selection.isEmpty())
341 TransactionDescDialog dlg(selection.at(0));
346 QWidget *TransactionView::createDateRangeWidget()
348 dateRangeWidget = new QFrame();
349 dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
350 dateRangeWidget->setContentsMargins(1,1,1,1);
351 QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
352 layout->setContentsMargins(0,0,0,0);
353 layout->addSpacing(23);
354 layout->addWidget(new QLabel("Range:"));
356 dateFrom = new QDateTimeEdit(this);
357 dateFrom->setDisplayFormat("dd/MM/yy");
358 dateFrom->setCalendarPopup(true);
359 dateFrom->setMinimumWidth(100);
360 dateFrom->setDate(QDate::currentDate().addDays(-7));
361 layout->addWidget(dateFrom);
362 layout->addWidget(new QLabel("to"));
364 dateTo = new QDateTimeEdit(this);
365 dateTo->setDisplayFormat("dd/MM/yy");
366 dateTo->setCalendarPopup(true);
367 dateTo->setMinimumWidth(100);
368 dateTo->setDate(QDate::currentDate());
369 layout->addWidget(dateTo);
370 layout->addStretch();
373 dateRangeWidget->setVisible(false);
376 connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
377 connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
379 return dateRangeWidget;
382 void TransactionView::dateRangeChanged()
384 transactionProxyModel->setDateRange(
385 QDateTime(dateFrom->date()),
386 QDateTime(dateTo->date()).addDays(1));