Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
transactionview.cpp
Go to the documentation of this file.
1 #include "transactionview.h"
2 
4 #include "transactionrecord.h"
5 #include "walletmodel.h"
6 #include "addresstablemodel.h"
8 #include "bitcoinunits.h"
9 #include "csvmodelwriter.h"
10 #include "transactiondescdialog.h"
11 #include "editaddressdialog.h"
12 #include "optionsmodel.h"
13 #include "guiutil.h"
14 
15 #include <QScrollBar>
16 #include <QComboBox>
17 #include <QDoubleValidator>
18 #include <QHBoxLayout>
19 #include <QVBoxLayout>
20 #include <QLineEdit>
21 #include <QTableView>
22 #include <QHeaderView>
23 #include <QMessageBox>
24 #include <QPoint>
25 #include <QMenu>
26 #include <QLabel>
27 #include <QDateTimeEdit>
28 
30  QWidget(parent), model(0), transactionProxyModel(0),
31  transactionView(0)
32 {
33  // Build filter row
34  setContentsMargins(0,0,0,0);
35 
36  QHBoxLayout *hlayout = new QHBoxLayout();
37  hlayout->setContentsMargins(0,0,0,0);
38 #ifdef Q_OS_MAC
39  hlayout->setSpacing(5);
40  hlayout->addSpacing(26);
41 #else
42  hlayout->setSpacing(0);
43  hlayout->addSpacing(23);
44 #endif
45 
46  dateWidget = new QComboBox(this);
47 #ifdef Q_OS_MAC
48  dateWidget->setFixedWidth(121);
49 #else
50  dateWidget->setFixedWidth(120);
51 #endif
52  dateWidget->addItem(tr("All"), All);
53  dateWidget->addItem(tr("Today"), Today);
54  dateWidget->addItem(tr("This week"), ThisWeek);
55  dateWidget->addItem(tr("This month"), ThisMonth);
56  dateWidget->addItem(tr("Last month"), LastMonth);
57  dateWidget->addItem(tr("This year"), ThisYear);
58  dateWidget->addItem(tr("Range..."), Range);
59  hlayout->addWidget(dateWidget);
60 
61  typeWidget = new QComboBox(this);
62 #ifdef Q_OS_MAC
63  typeWidget->setFixedWidth(121);
64 #else
65  typeWidget->setFixedWidth(120);
66 #endif
67 
68  typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
76 
77  hlayout->addWidget(typeWidget);
78 
79  addressWidget = new QLineEdit(this);
80 #if QT_VERSION >= 0x040700
81  /* Do not move this to the XML file, Qt before 4.7 will choke on it */
82  addressWidget->setPlaceholderText(tr("Enter address or label to search"));
83 #endif
84  hlayout->addWidget(addressWidget);
85 
86  amountWidget = new QLineEdit(this);
87 #if QT_VERSION >= 0x040700
88  /* Do not move this to the XML file, Qt before 4.7 will choke on it */
89  amountWidget->setPlaceholderText(tr("Min amount"));
90 #endif
91 #ifdef Q_OS_MAC
92  amountWidget->setFixedWidth(97);
93 #else
94  amountWidget->setFixedWidth(100);
95 #endif
96  amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
97  hlayout->addWidget(amountWidget);
98 
99  QVBoxLayout *vlayout = new QVBoxLayout(this);
100  vlayout->setContentsMargins(0,0,0,0);
101  vlayout->setSpacing(0);
102 
103  QTableView *view = new QTableView(this);
104  vlayout->addLayout(hlayout);
105  vlayout->addWidget(createDateRangeWidget());
106  vlayout->addWidget(view);
107  vlayout->setSpacing(0);
108  int width = view->verticalScrollBar()->sizeHint().width();
109  // Cover scroll bar width with spacing
110 #ifdef Q_OS_MAC
111  hlayout->addSpacing(width+2);
112 #else
113  hlayout->addSpacing(width);
114 #endif
115  // Always show scroll bar
116  view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
117  view->setTabKeyNavigation(false);
118  view->setContextMenuPolicy(Qt::CustomContextMenu);
119 
120  transactionView = view;
121 
122  // Actions
123  QAction *copyAddressAction = new QAction(tr("Copy address"), this);
124  QAction *copyLabelAction = new QAction(tr("Copy label"), this);
125  QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
126  QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
127  QAction *editLabelAction = new QAction(tr("Edit label"), this);
128  QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
129 
130  contextMenu = new QMenu();
131  contextMenu->addAction(copyAddressAction);
132  contextMenu->addAction(copyLabelAction);
133  contextMenu->addAction(copyAmountAction);
134  contextMenu->addAction(copyTxIDAction);
135  contextMenu->addAction(editLabelAction);
136  contextMenu->addAction(showDetailsAction);
137 
138  // Connect actions
139  connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
140  connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
141  connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
142  connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
143 
144  connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
145  connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
146 
147  connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress()));
148  connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
149  connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
150  connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID()));
151  connect(editLabelAction, SIGNAL(triggered()), this, SLOT(editLabel()));
152  connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
153 }
154 
156 {
157  this->model = model;
158  if(model)
159  {
161  transactionProxyModel->setSourceModel(model->getTransactionTableModel());
162  transactionProxyModel->setDynamicSortFilter(true);
163  transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
164  transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
165 
166  transactionProxyModel->setSortRole(Qt::EditRole);
167 
169  transactionView->setAlternatingRowColors(true);
170  transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
171  transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
172  transactionView->setSortingEnabled(true);
173  transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
174  transactionView->verticalHeader()->hide();
175 
176  transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Status, 23);
177  transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Date, 120);
178  transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Type, 120);
179 #if QT_VERSION < 0x050000
180  transactionView->horizontalHeader()->setResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
181 #else
182  transactionView->horizontalHeader()->setSectionResizeMode(TransactionTableModel::ToAddress, QHeaderView::Stretch);
183 #endif
184  transactionView->horizontalHeader()->resizeSection(TransactionTableModel::Amount, 100);
185  }
186 }
187 
189 {
191  return;
192  QDate current = QDate::currentDate();
193  dateRangeWidget->setVisible(false);
194  switch(dateWidget->itemData(idx).toInt())
195  {
196  case All:
200  break;
201  case Today:
203  QDateTime(current),
205  break;
206  case ThisWeek: {
207  // Find last Monday
208  QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
210  QDateTime(startOfWeek),
212 
213  } break;
214  case ThisMonth:
216  QDateTime(QDate(current.year(), current.month(), 1)),
218  break;
219  case LastMonth:
221  QDateTime(QDate(current.year(), current.month()-1, 1)),
222  QDateTime(QDate(current.year(), current.month(), 1)));
223  break;
224  case ThisYear:
226  QDateTime(QDate(current.year(), 1, 1)),
228  break;
229  case Range:
230  dateRangeWidget->setVisible(true);
232  break;
233  }
234 }
235 
237 {
239  return;
241  typeWidget->itemData(idx).toInt());
242 }
243 
244 void TransactionView::changedPrefix(const QString &prefix)
245 {
247  return;
249 }
250 
251 void TransactionView::changedAmount(const QString &amount)
252 {
254  return;
255  qint64 amount_parsed = 0;
256  if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
257  {
258  transactionProxyModel->setMinAmount(amount_parsed);
259  }
260  else
261  {
263  }
264 }
265 
267 {
268  // CSV is currently the only supported format
269  QString filename = GUIUtil::getSaveFileName(
270  this,
271  tr("Export Transaction Data"), QString(),
272  tr("Comma separated file (*.csv)"));
273 
274  if (filename.isNull()) return;
275 
276  CSVModelWriter writer(filename);
277 
278  // name, column, role
280  writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
281  writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
282  writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
283  writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
284  writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
285  writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
286  writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
287 
288  if(!writer.write())
289  {
290  QMessageBox::critical(this, tr("Error exporting"), tr("Could not write to file %1.").arg(filename),
291  QMessageBox::Abort, QMessageBox::Abort);
292  }
293 }
294 
295 void TransactionView::contextualMenu(const QPoint &point)
296 {
297  QModelIndex index = transactionView->indexAt(point);
298  if(index.isValid())
299  {
300  contextMenu->exec(QCursor::pos());
301  }
302 }
303 
305 {
307 }
308 
310 {
312 }
313 
315 {
317 }
318 
320 {
322 }
323 
325 {
326  if(!transactionView->selectionModel() ||!model)
327  return;
328  QModelIndexList selection = transactionView->selectionModel()->selectedRows();
329  if(!selection.isEmpty())
330  {
331  AddressTableModel *addressBook = model->getAddressTableModel();
332  if(!addressBook)
333  return;
334  QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
335  if(address.isEmpty())
336  {
337  // If this transaction has no associated address, exit
338  return;
339  }
340  // Is address in address book? Address book can miss address when a transaction is
341  // sent from outside the UI.
342  int idx = addressBook->lookupAddress(address);
343  if(idx != -1)
344  {
345  // Edit sending / receiving address
346  QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
347  // Determine type of address, launch appropriate editor dialog type
348  QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
349 
353  this);
354  dlg.setModel(addressBook);
355  dlg.loadRow(idx);
356  dlg.exec();
357  }
358  else
359  {
360  // Add sending address
362  this);
363  dlg.setModel(addressBook);
364  dlg.setAddress(address);
365  dlg.exec();
366  }
367  }
368 }
369 
371 {
372  if(!transactionView->selectionModel())
373  return;
374  QModelIndexList selection = transactionView->selectionModel()->selectedRows();
375  if(!selection.isEmpty())
376  {
377  TransactionDescDialog dlg(selection.at(0));
378  dlg.exec();
379  }
380 }
381 
383 {
384  dateRangeWidget = new QFrame();
385  dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
386  dateRangeWidget->setContentsMargins(1,1,1,1);
387  QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
388  layout->setContentsMargins(0,0,0,0);
389  layout->addSpacing(23);
390  layout->addWidget(new QLabel(tr("Range:")));
391 
392  dateFrom = new QDateTimeEdit(this);
393  dateFrom->setDisplayFormat("dd/MM/yy");
394  dateFrom->setCalendarPopup(true);
395  dateFrom->setMinimumWidth(100);
396  dateFrom->setDate(QDate::currentDate().addDays(-7));
397  layout->addWidget(dateFrom);
398  layout->addWidget(new QLabel(tr("to")));
399 
400  dateTo = new QDateTimeEdit(this);
401  dateTo->setDisplayFormat("dd/MM/yy");
402  dateTo->setCalendarPopup(true);
403  dateTo->setMinimumWidth(100);
404  dateTo->setDate(QDate::currentDate());
405  layout->addWidget(dateTo);
406  layout->addStretch();
407 
408  // Hide by default
409  dateRangeWidget->setVisible(false);
410 
411  // Notify on change
412  connect(dateFrom, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
413  connect(dateTo, SIGNAL(dateChanged(QDate)), this, SLOT(dateRangeChanged()));
414 
415  return dateRangeWidget;
416 }
417 
419 {
421  return;
423  QDateTime(dateFrom->date()),
424  QDateTime(dateTo->date()).addDays(1));
425 }
426 
427 void TransactionView::focusTransaction(const QModelIndex &idx)
428 {
430  return;
431  QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
432  transactionView->scrollTo(targetIdx);
433  transactionView->setCurrentIndex(targetIdx);
434  transactionView->setFocus();
435 }
void changedPrefix(const QString &prefix)
TransactionView(QWidget *parent=0)
void addColumn(const QString &title, int column, int role=Qt::EditRole)
QModelIndex index(int row, int column, const QModelIndex &parent) const
QWidget * createDateRangeWidget()
Dialog showing transaction details.
int lookupAddress(const QString &address) const
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
Definition: guiutil.cpp:190
void focusTransaction(const QModelIndex &)
TransactionRecord * index(int idx)
void setTypeFilter(quint32 modes)
QTableView * transactionView
AddressTableModel * getAddressTableModel()
Export a Qt table model to a CSV file.
TransactionTableModel * parent
void setAddressPrefix(const QString &addrPrefix)
static quint32 TYPE(int type)
QDateTimeEdit * dateTo
void setModel(AddressTableModel *model)
static const QDateTime MIN_DATE
Earliest date that can be represented (far in the past)
static const QDateTime MAX_DATE
Last date that can be represented (far in the future)
void setDateRange(const QDateTime &from, const QDateTime &to)
void changedAmount(const QString &amount)
void setMinAmount(qint64 minimum)
Date and time this transaction was created.
TransactionTableModel * getTransactionTableModel()
int getDisplayUnit()
Definition: optionsmodel.h:50
Qt model of the address book in the core.
TransactionFilterProxy * transactionProxyModel
void chooseDate(int idx)
void setModel(const QAbstractItemModel *model)
void setModel(WalletModel *model)
QLineEdit * amountWidget
QComboBox * typeWidget
QVariant data(const QModelIndex &index, int role) const
Filter the transaction list according to pre-specified rules.
void setAddress(const QString &address)
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:36
static const QString Receive
Specifies receive address.
Dialog for editing an address and associated information.
static bool parse(int unit, const QString &value, qint64 *val_out)
Parse string to coin amount.
QFrame * dateRangeWidget
Label of address related to transaction.
static const quint32 ALL_TYPES
Type filter bit field (all types)
QLineEdit * addressWidget
void contextualMenu(const QPoint &)
Formatted amount, without brackets when unconfirmed.
void copyEntryData(QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
Definition: guiutil.cpp:169
void chooseType(int idx)
QDateTimeEdit * dateFrom
bool write()
Perform export of the model to CSV.
void doubleClicked(const QModelIndex &)
void * arg
Definition: env_posix.cc:716
Type of address (Send or Receive)
WalletModel * model
OptionsModel * getOptionsModel()
QComboBox * dateWidget