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>
32 TransactionView::TransactionView(QWidget *parent) :
33 QWidget(parent), model(0), transactionProxyModel(0),
37 setContentsMargins(0,0,0,0);
39 QHBoxLayout *hlayout = new QHBoxLayout();
40 hlayout->setContentsMargins(0,0,0,0);
41 hlayout->setSpacing(0);
43 hlayout->addSpacing(23);
45 dateWidget = new QComboBox(this);
46 dateWidget->setMaximumWidth(120);
47 dateWidget->setMinimumWidth(120);
48 dateWidget->addItem(tr("All"), All);
49 dateWidget->addItem(tr("Today"), Today);
50 dateWidget->addItem(tr("This week"), ThisWeek);
51 dateWidget->addItem(tr("This month"), ThisMonth);
52 dateWidget->addItem(tr("Last month"), LastMonth);
53 dateWidget->addItem(tr("This year"), ThisYear);
54 dateWidget->addItem(tr("Range..."), Range);
55 hlayout->addWidget(dateWidget);
57 typeWidget = new QComboBox(this);
58 typeWidget->setMaximumWidth(120);
59 typeWidget->setMinimumWidth(120);
61 typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
62 typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
63 TransactionFilterProxy::TYPE(TransactionRecord::RecvFromIP));
64 typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
65 TransactionFilterProxy::TYPE(TransactionRecord::SendToIP));
66 typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
67 typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
68 typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
70 hlayout->addWidget(typeWidget);
72 addressWidget = new QLineEdit(this);
73 #if QT_VERSION >= 0x040700
74 addressWidget->setPlaceholderText(tr("Enter address or label to search"));
76 hlayout->addWidget(addressWidget);
78 amountWidget = new QLineEdit(this);
79 #if QT_VERSION >= 0x040700
80 amountWidget->setPlaceholderText(tr("Min amount"));
82 amountWidget->setMaximumWidth(100);
83 amountWidget->setMinimumWidth(100);
84 amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
85 hlayout->addWidget(amountWidget);
87 QVBoxLayout *vlayout = new QVBoxLayout(this);
88 vlayout->setContentsMargins(0,0,0,0);
89 vlayout->setSpacing(0);
90 //vlayout->addLayout(hlayout2);
92 QTableView *view = new QTableView(this);
93 vlayout->addLayout(hlayout);
94 vlayout->addWidget(createDateRangeWidget());
95 vlayout->addWidget(view);
96 vlayout->setSpacing(0);
97 int width = view->verticalScrollBar()->sizeHint().width();
98 // Cover scroll bar width with spacing
99 hlayout->addSpacing(width);
100 // Always show scroll bar
101 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
102 view->setTabKeyNavigation(false);
103 view->setContextMenuPolicy(Qt::CustomContextMenu);
105 transactionView = view;
108 QAction *copyAddressAction = new QAction(tr("Copy address"), this);
109 QAction *copyLabelAction = new QAction(tr("Copy label"), this);
110 QAction *editLabelAction = new QAction(tr("Edit label"), this);
111 QAction *showDetailsAction = new QAction(tr("Show details..."), this);
113 contextMenu = new QMenu();
114 contextMenu->addAction(copyAddressAction);
115 contextMenu->addAction(copyLabelAction);
116 contextMenu->addAction(editLabelAction);
117 contextMenu->addAction(showDetailsAction);
120 connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
121 connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
122 connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
123 connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
125 connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
128 SIGNAL(customContextMenuRequested(QPoint)),
130 SLOT(contextualMenu(QPoint)));
132 connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
133 connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
134 connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
135 connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
138 void TransactionView::setModel(WalletModel *model)
142 transactionProxyModel = new TransactionFilterProxy(this);
143 transactionProxyModel->setSourceModel(model->getTransactionTableModel());
144 transactionProxyModel->setDynamicSortFilter(true);
146 transactionProxyModel->setSortRole(Qt::EditRole);
148 transactionView->setModel(transactionProxyModel);
149 transactionView->setAlternatingRowColors(true);
150 transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
151 transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
152 transactionView->setSortingEnabled(true);
153 transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
154 transactionView->verticalHeader()->hide();
156 transactionView->horizontalHeader()->resizeSection(
157 TransactionTableModel::Status, 23);
158 transactionView->horizontalHeader()->resizeSection(
159 TransactionTableModel::Date, 120);
160 transactionView->horizontalHeader()->resizeSection(
161 TransactionTableModel::Type, 120);
162 transactionView->horizontalHeader()->setResizeMode(
163 TransactionTableModel::ToAddress, QHeaderView::Stretch);
164 transactionView->horizontalHeader()->resizeSection(
165 TransactionTableModel::Amount, 100);
169 void TransactionView::chooseDate(int idx)
171 QDate current = QDate::currentDate();
172 dateRangeWidget->setVisible(false);
173 switch(dateWidget->itemData(idx).toInt())
176 transactionProxyModel->setDateRange(
177 TransactionFilterProxy::MIN_DATE,
178 TransactionFilterProxy::MAX_DATE);
181 transactionProxyModel->setDateRange(
183 TransactionFilterProxy::MAX_DATE);
187 QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
188 transactionProxyModel->setDateRange(
189 QDateTime(startOfWeek),
190 TransactionFilterProxy::MAX_DATE);
194 transactionProxyModel->setDateRange(
195 QDateTime(QDate(current.year(), current.month(), 1)),
196 TransactionFilterProxy::MAX_DATE);
199 transactionProxyModel->setDateRange(
200 QDateTime(QDate(current.year(), current.month()-1, 1)),
201 QDateTime(QDate(current.year(), current.month(), 1)));
204 transactionProxyModel->setDateRange(
205 QDateTime(QDate(current.year(), 1, 1)),
206 TransactionFilterProxy::MAX_DATE);
209 dateRangeWidget->setVisible(true);
215 void TransactionView::chooseType(int idx)
217 transactionProxyModel->setTypeFilter(
218 typeWidget->itemData(idx).toInt());
221 void TransactionView::changedPrefix(const QString &prefix)
223 transactionProxyModel->setAddressPrefix(prefix);
226 void TransactionView::changedAmount(const QString &amount)
228 qint64 amount_parsed = 0;
229 if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
231 transactionProxyModel->setMinAmount(amount_parsed);
235 transactionProxyModel->setMinAmount(0);
239 void TransactionView::exportClicked()
241 // CSV is currently the only supported format
242 QString filename = QFileDialog::getSaveFileName(
244 tr("Export Transaction Data"),
246 tr("Comma separated file (*.csv)"));
248 if (filename.isNull()) return;
250 CSVModelWriter writer(filename);
252 // name, column, role
253 writer.setModel(transactionProxyModel);
254 writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
255 writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
256 writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
257 writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
258 writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
259 writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
260 writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
264 QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
265 QMessageBox::Abort, QMessageBox::Abort);
269 void TransactionView::contextualMenu(const QPoint &point)
271 QModelIndex index = transactionView->indexAt(point);
274 contextMenu->exec(QCursor::pos());
278 void TransactionView::copyAddress()
280 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
281 if(!selection.isEmpty())
283 QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::AddressRole).toString());
287 void TransactionView::copyLabel()
289 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
290 if(!selection.isEmpty())
292 QApplication::clipboard()->setText(selection.at(0).data(TransactionTableModel::LabelRole).toString());
296 void TransactionView::editLabel()
298 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
299 if(!selection.isEmpty())
301 AddressTableModel *addressBook = model->getAddressTableModel();
302 QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
303 if(address.isEmpty())
305 // If this transaction has no associated address, exit
308 int idx = addressBook->lookupAddress(address);
311 // Edit sending / receiving address
312 QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
313 // Determine type of address, launch appropriate editor dialog type
314 QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
316 EditAddressDialog dlg(type==AddressTableModel::Receive
317 ? EditAddressDialog::EditReceivingAddress
318 : EditAddressDialog::EditSendingAddress,
320 dlg.setModel(addressBook);
326 // Add sending address
327 EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
334 void TransactionView::showDetails()
336 QModelIndexList selection = transactionView->selectionModel()->selectedRows();
337 if(!selection.isEmpty())
339 TransactionDescDialog dlg(selection.at(0));
344 QWidget *TransactionView::createDateRangeWidget()
346 dateRangeWidget = new QFrame();
347 dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
348 dateRangeWidget->setContentsMargins(1,1,1,1);
349 QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
350 layout->setContentsMargins(0,0,0,0);
351 layout->addSpacing(23);
352 layout->addWidget(new QLabel(tr("Range:")));
354 dateFrom = new QDateTimeEdit(this);
355 dateFrom->setDisplayFormat("dd/MM/yy");
356 dateFrom->setCalendarPopup(true);
357 dateFrom->setMinimumWidth(100);
358 dateFrom->setDate(QDate::currentDate().addDays(-7));
359 layout->addWidget(dateFrom);
360 layout->addWidget(new QLabel(tr("to")));
362 dateTo = new QDateTimeEdit(this);
363 dateTo->setDisplayFormat("dd/MM/yy");
364 dateTo->setCalendarPopup(true);
365 dateTo->setMinimumWidth(100);
366 dateTo->setDate(QDate::currentDate());
367 layout->addWidget(dateTo);
368 layout->addStretch();
371 dateRangeWidget->setVisible(false);
374 connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
375 connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
377 return dateRangeWidget;
380 void TransactionView::dateRangeChanged()
382 transactionProxyModel->setDateRange(
383 QDateTime(dateFrom->date()),
384 QDateTime(dateTo->date()).addDays(1));