mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-15 12:51:00 +02:00
Among the context menu actions for each transaction in the transactionview is the 'Edit Label' action. While all other actions apply directly to the selected transaction, the 'Edit Label' action applies to the address of the selected transaction. This creates a confusing UX scenario where the outcome of the action is ambiguous. The action of Editing a Label should instead be reserved for the Send and Receive tabs. This PR removes the 'Edit Label' action from the transactionview context menu. Since the 'Edit Label' action will no longer be utilized in the transactionview, the 'Edit Label' function logic is also removed.
605 lines
23 KiB
C++
605 lines
23 KiB
C++
// Copyright (c) 2011-2019 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <qt/transactionview.h>
|
|
|
|
#include <qt/addresstablemodel.h>
|
|
#include <qt/bitcoinunits.h>
|
|
#include <qt/csvmodelwriter.h>
|
|
#include <qt/editaddressdialog.h>
|
|
#include <qt/guiutil.h>
|
|
#include <qt/optionsmodel.h>
|
|
#include <qt/platformstyle.h>
|
|
#include <qt/transactiondescdialog.h>
|
|
#include <qt/transactionfilterproxy.h>
|
|
#include <qt/transactionrecord.h>
|
|
#include <qt/transactiontablemodel.h>
|
|
#include <qt/walletmodel.h>
|
|
|
|
#include <node/ui_interface.h>
|
|
|
|
#include <QApplication>
|
|
#include <QComboBox>
|
|
#include <QDateTimeEdit>
|
|
#include <QDesktopServices>
|
|
#include <QDoubleValidator>
|
|
#include <QHBoxLayout>
|
|
#include <QHeaderView>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QMenu>
|
|
#include <QPoint>
|
|
#include <QScrollBar>
|
|
#include <QTableView>
|
|
#include <QTimer>
|
|
#include <QUrl>
|
|
#include <QVBoxLayout>
|
|
|
|
TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
|
|
QWidget(parent)
|
|
{
|
|
// Build filter row
|
|
setContentsMargins(0,0,0,0);
|
|
|
|
QHBoxLayout *hlayout = new QHBoxLayout();
|
|
hlayout->setContentsMargins(0,0,0,0);
|
|
|
|
if (platformStyle->getUseExtraSpacing()) {
|
|
hlayout->setSpacing(5);
|
|
hlayout->addSpacing(26);
|
|
} else {
|
|
hlayout->setSpacing(0);
|
|
hlayout->addSpacing(23);
|
|
}
|
|
|
|
watchOnlyWidget = new QComboBox(this);
|
|
watchOnlyWidget->setFixedWidth(24);
|
|
watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All);
|
|
watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
|
|
watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
|
|
hlayout->addWidget(watchOnlyWidget);
|
|
|
|
dateWidget = new QComboBox(this);
|
|
if (platformStyle->getUseExtraSpacing()) {
|
|
dateWidget->setFixedWidth(121);
|
|
} else {
|
|
dateWidget->setFixedWidth(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);
|
|
if (platformStyle->getUseExtraSpacing()) {
|
|
typeWidget->setFixedWidth(121);
|
|
} else {
|
|
typeWidget->setFixedWidth(120);
|
|
}
|
|
|
|
typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
|
|
typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
|
|
TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther));
|
|
typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
|
|
TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
|
|
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);
|
|
|
|
search_widget = new QLineEdit(this);
|
|
search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
|
|
hlayout->addWidget(search_widget);
|
|
|
|
amountWidget = new QLineEdit(this);
|
|
amountWidget->setPlaceholderText(tr("Min amount"));
|
|
if (platformStyle->getUseExtraSpacing()) {
|
|
amountWidget->setFixedWidth(97);
|
|
} else {
|
|
amountWidget->setFixedWidth(100);
|
|
}
|
|
QDoubleValidator *amountValidator = new QDoubleValidator(0, 1e20, 8, this);
|
|
QLocale amountLocale(QLocale::C);
|
|
amountLocale.setNumberOptions(QLocale::RejectGroupSeparator);
|
|
amountValidator->setLocale(amountLocale);
|
|
amountWidget->setValidator(amountValidator);
|
|
hlayout->addWidget(amountWidget);
|
|
|
|
// Delay before filtering transactions in ms
|
|
static const int input_filter_delay = 200;
|
|
|
|
QTimer* amount_typing_delay = new QTimer(this);
|
|
amount_typing_delay->setSingleShot(true);
|
|
amount_typing_delay->setInterval(input_filter_delay);
|
|
|
|
QTimer* prefix_typing_delay = new QTimer(this);
|
|
prefix_typing_delay->setSingleShot(true);
|
|
prefix_typing_delay->setInterval(input_filter_delay);
|
|
|
|
QVBoxLayout *vlayout = new QVBoxLayout(this);
|
|
vlayout->setContentsMargins(0,0,0,0);
|
|
vlayout->setSpacing(0);
|
|
|
|
QTableView *view = new QTableView(this);
|
|
vlayout->addLayout(hlayout);
|
|
vlayout->addWidget(createDateRangeWidget());
|
|
vlayout->addWidget(view);
|
|
vlayout->setSpacing(0);
|
|
int width = view->verticalScrollBar()->sizeHint().width();
|
|
// Cover scroll bar width with spacing
|
|
if (platformStyle->getUseExtraSpacing()) {
|
|
hlayout->addSpacing(width+2);
|
|
} else {
|
|
hlayout->addSpacing(width);
|
|
}
|
|
// Always show scroll bar
|
|
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
|
view->setTabKeyNavigation(false);
|
|
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
view->installEventFilter(this);
|
|
|
|
transactionView = view;
|
|
transactionView->setObjectName("transactionView");
|
|
|
|
// Actions
|
|
abandonAction = new QAction(tr("Abandon transaction"), this);
|
|
bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
|
|
bumpFeeAction->setObjectName("bumpFeeAction");
|
|
copyAddressAction = new QAction(tr("Copy address"), this);
|
|
copyLabelAction = new QAction(tr("Copy label"), this);
|
|
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
|
|
QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
|
|
QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
|
|
QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
|
|
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
|
|
|
|
contextMenu = new QMenu(this);
|
|
contextMenu->setObjectName("contextMenu");
|
|
contextMenu->addAction(copyAddressAction);
|
|
contextMenu->addAction(copyLabelAction);
|
|
contextMenu->addAction(copyAmountAction);
|
|
contextMenu->addAction(copyTxIDAction);
|
|
contextMenu->addAction(copyTxHexAction);
|
|
contextMenu->addAction(copyTxPlainText);
|
|
contextMenu->addAction(showDetailsAction);
|
|
contextMenu->addSeparator();
|
|
contextMenu->addAction(bumpFeeAction);
|
|
contextMenu->addAction(abandonAction);
|
|
|
|
connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate);
|
|
connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType);
|
|
connect(watchOnlyWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseWatchonly);
|
|
connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
|
|
connect(amount_typing_delay, &QTimer::timeout, this, &TransactionView::changedAmount);
|
|
connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
|
|
connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch);
|
|
|
|
connect(view, &QTableView::doubleClicked, this, &TransactionView::doubleClicked);
|
|
connect(view, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu);
|
|
|
|
connect(bumpFeeAction, &QAction::triggered, this, &TransactionView::bumpFee);
|
|
connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx);
|
|
connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress);
|
|
connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel);
|
|
connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount);
|
|
connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID);
|
|
connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex);
|
|
connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText);
|
|
connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails);
|
|
// Double-clicking on a transaction on the transaction history page shows details
|
|
connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails);
|
|
// Highlight transaction after fee bump
|
|
connect(this, &TransactionView::bumpedFee, [this](const uint256& txid) {
|
|
focusTransaction(txid);
|
|
});
|
|
}
|
|
|
|
void TransactionView::setModel(WalletModel *_model)
|
|
{
|
|
this->model = _model;
|
|
if(_model)
|
|
{
|
|
transactionProxyModel = new TransactionFilterProxy(this);
|
|
transactionProxyModel->setSourceModel(_model->getTransactionTableModel());
|
|
transactionProxyModel->setDynamicSortFilter(true);
|
|
transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
|
transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
|
|
transactionProxyModel->setSortRole(Qt::EditRole);
|
|
|
|
transactionView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
transactionView->setModel(transactionProxyModel);
|
|
transactionView->setAlternatingRowColors(true);
|
|
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
transactionView->horizontalHeader()->setSortIndicator(TransactionTableModel::Date, Qt::DescendingOrder);
|
|
transactionView->setSortingEnabled(true);
|
|
transactionView->verticalHeader()->hide();
|
|
|
|
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
|
|
transactionView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH);
|
|
transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH);
|
|
transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
|
|
transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
|
|
|
|
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this);
|
|
|
|
if (_model->getOptionsModel())
|
|
{
|
|
// Add third party transaction URLs to context menu
|
|
QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
|
|
for (int i = 0; i < listUrls.size(); ++i)
|
|
{
|
|
QString url = listUrls[i].trimmed();
|
|
QString host = QUrl(url, QUrl::StrictMode).host();
|
|
if (!host.isEmpty())
|
|
{
|
|
QAction *thirdPartyTxUrlAction = new QAction(host, this); // use host as menu item label
|
|
if (i == 0)
|
|
contextMenu->addSeparator();
|
|
contextMenu->addAction(thirdPartyTxUrlAction);
|
|
connect(thirdPartyTxUrlAction, &QAction::triggered, [this, url] { openThirdPartyTxUrl(url); });
|
|
}
|
|
}
|
|
}
|
|
|
|
// show/hide column Watch-only
|
|
updateWatchOnlyColumn(_model->wallet().haveWatchOnly());
|
|
|
|
// Watch-only signal
|
|
connect(_model, &WalletModel::notifyWatchonlyChanged, this, &TransactionView::updateWatchOnlyColumn);
|
|
}
|
|
}
|
|
|
|
void TransactionView::chooseDate(int idx)
|
|
{
|
|
if (!transactionProxyModel) return;
|
|
QDate current = QDate::currentDate();
|
|
dateRangeWidget->setVisible(false);
|
|
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).addMonths(-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:
|
|
dateRangeWidget->setVisible(true);
|
|
dateRangeChanged();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TransactionView::chooseType(int idx)
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
transactionProxyModel->setTypeFilter(
|
|
typeWidget->itemData(idx).toInt());
|
|
}
|
|
|
|
void TransactionView::chooseWatchonly(int idx)
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
transactionProxyModel->setWatchOnlyFilter(
|
|
static_cast<TransactionFilterProxy::WatchOnlyFilter>(watchOnlyWidget->itemData(idx).toInt()));
|
|
}
|
|
|
|
void TransactionView::changedSearch()
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
transactionProxyModel->setSearchString(search_widget->text());
|
|
}
|
|
|
|
void TransactionView::changedAmount()
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
CAmount amount_parsed = 0;
|
|
if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
|
|
transactionProxyModel->setMinAmount(amount_parsed);
|
|
}
|
|
else
|
|
{
|
|
transactionProxyModel->setMinAmount(0);
|
|
}
|
|
}
|
|
|
|
void TransactionView::exportClicked()
|
|
{
|
|
if (!model || !model->getOptionsModel()) {
|
|
return;
|
|
}
|
|
|
|
// CSV is currently the only supported format
|
|
QString filename = GUIUtil::getSaveFileName(this,
|
|
tr("Export Transaction History"), QString(),
|
|
tr("Comma separated file (*.csv)"), nullptr);
|
|
|
|
if (filename.isNull())
|
|
return;
|
|
|
|
CSVModelWriter writer(filename);
|
|
|
|
// name, column, role
|
|
writer.setModel(transactionProxyModel);
|
|
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
|
|
if (model->wallet().haveWatchOnly())
|
|
writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
|
|
writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
|
|
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
|
|
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
|
|
writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
|
|
writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole);
|
|
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxHashRole);
|
|
|
|
if(!writer.write()) {
|
|
Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
|
|
CClientUIInterface::MSG_ERROR);
|
|
}
|
|
else {
|
|
Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
|
|
CClientUIInterface::MSG_INFORMATION);
|
|
}
|
|
}
|
|
|
|
void TransactionView::contextualMenu(const QPoint &point)
|
|
{
|
|
QModelIndex index = transactionView->indexAt(point);
|
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
|
|
if (selection.empty())
|
|
return;
|
|
|
|
// check if transaction can be abandoned, disable context menu action in case it doesn't
|
|
uint256 hash;
|
|
hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
|
|
abandonAction->setEnabled(model->wallet().transactionCanBeAbandoned(hash));
|
|
bumpFeeAction->setEnabled(model->wallet().transactionCanBeBumped(hash));
|
|
copyAddressAction->setEnabled(GUIUtil::hasEntryData(transactionView, 0, TransactionTableModel::AddressRole));
|
|
copyLabelAction->setEnabled(GUIUtil::hasEntryData(transactionView, 0, TransactionTableModel::LabelRole));
|
|
|
|
if (index.isValid()) {
|
|
GUIUtil::PopupMenu(contextMenu, transactionView->viewport()->mapToGlobal(point));
|
|
}
|
|
}
|
|
|
|
void TransactionView::abandonTx()
|
|
{
|
|
if(!transactionView || !transactionView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
|
|
|
|
// get the hash from the TxHashRole (QVariant / QString)
|
|
uint256 hash;
|
|
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
|
|
hash.SetHex(hashQStr.toStdString());
|
|
|
|
// Abandon the wallet transaction over the walletModel
|
|
model->wallet().abandonTransaction(hash);
|
|
|
|
// Update the table
|
|
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
|
|
}
|
|
|
|
void TransactionView::bumpFee()
|
|
{
|
|
if(!transactionView || !transactionView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
|
|
|
|
// get the hash from the TxHashRole (QVariant / QString)
|
|
uint256 hash;
|
|
QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
|
|
hash.SetHex(hashQStr.toStdString());
|
|
|
|
// Bump tx fee over the walletModel
|
|
uint256 newHash;
|
|
if (model->bumpFee(hash, newHash)) {
|
|
// Update the table
|
|
transactionView->selectionModel()->clearSelection();
|
|
model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, true);
|
|
|
|
qApp->processEvents();
|
|
Q_EMIT bumpedFee(newHash);
|
|
}
|
|
}
|
|
|
|
void TransactionView::copyAddress()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
|
|
}
|
|
|
|
void TransactionView::copyLabel()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::LabelRole);
|
|
}
|
|
|
|
void TransactionView::copyAmount()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole);
|
|
}
|
|
|
|
void TransactionView::copyTxID()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHashRole);
|
|
}
|
|
|
|
void TransactionView::copyTxHex()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole);
|
|
}
|
|
|
|
void TransactionView::copyTxPlainText()
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
|
|
}
|
|
|
|
void TransactionView::showDetails()
|
|
{
|
|
if(!transactionView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows();
|
|
if(!selection.isEmpty())
|
|
{
|
|
TransactionDescDialog *dlg = new TransactionDescDialog(selection.at(0));
|
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
|
dlg->show();
|
|
}
|
|
}
|
|
|
|
void TransactionView::openThirdPartyTxUrl(QString url)
|
|
{
|
|
if(!transactionView || !transactionView->selectionModel())
|
|
return;
|
|
QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
|
|
if(!selection.isEmpty())
|
|
QDesktopServices::openUrl(QUrl::fromUserInput(url.replace("%s", selection.at(0).data(TransactionTableModel::TxHashRole).toString())));
|
|
}
|
|
|
|
QWidget *TransactionView::createDateRangeWidget()
|
|
{
|
|
dateRangeWidget = new QFrame();
|
|
dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
|
|
dateRangeWidget->setContentsMargins(1,1,1,1);
|
|
QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
|
|
layout->setContentsMargins(0,0,0,0);
|
|
layout->addSpacing(23);
|
|
layout->addWidget(new QLabel(tr("Range:")));
|
|
|
|
dateFrom = new QDateTimeEdit(this);
|
|
dateFrom->setDisplayFormat("dd/MM/yy");
|
|
dateFrom->setCalendarPopup(true);
|
|
dateFrom->setMinimumWidth(100);
|
|
dateFrom->setDate(QDate::currentDate().addDays(-7));
|
|
layout->addWidget(dateFrom);
|
|
layout->addWidget(new QLabel(tr("to")));
|
|
|
|
dateTo = new QDateTimeEdit(this);
|
|
dateTo->setDisplayFormat("dd/MM/yy");
|
|
dateTo->setCalendarPopup(true);
|
|
dateTo->setMinimumWidth(100);
|
|
dateTo->setDate(QDate::currentDate());
|
|
layout->addWidget(dateTo);
|
|
layout->addStretch();
|
|
|
|
// Hide by default
|
|
dateRangeWidget->setVisible(false);
|
|
|
|
// Notify on change
|
|
connect(dateFrom, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged);
|
|
connect(dateTo, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged);
|
|
|
|
return dateRangeWidget;
|
|
}
|
|
|
|
void TransactionView::dateRangeChanged()
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
transactionProxyModel->setDateRange(
|
|
QDateTime(dateFrom->date()),
|
|
QDateTime(dateTo->date()).addDays(1));
|
|
}
|
|
|
|
void TransactionView::focusTransaction(const QModelIndex &idx)
|
|
{
|
|
if(!transactionProxyModel)
|
|
return;
|
|
QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
|
|
transactionView->scrollTo(targetIdx);
|
|
transactionView->setCurrentIndex(targetIdx);
|
|
transactionView->setFocus();
|
|
}
|
|
|
|
void TransactionView::focusTransaction(const uint256& txid)
|
|
{
|
|
if (!transactionProxyModel)
|
|
return;
|
|
|
|
const QModelIndexList results = this->model->getTransactionTableModel()->match(
|
|
this->model->getTransactionTableModel()->index(0,0),
|
|
TransactionTableModel::TxHashRole,
|
|
QString::fromStdString(txid.ToString()), -1);
|
|
|
|
transactionView->setFocus();
|
|
transactionView->selectionModel()->clearSelection();
|
|
for (const QModelIndex& index : results) {
|
|
const QModelIndex targetIndex = transactionProxyModel->mapFromSource(index);
|
|
transactionView->selectionModel()->select(
|
|
targetIndex,
|
|
QItemSelectionModel::Rows | QItemSelectionModel::Select);
|
|
// Called once per destination to ensure all results are in view, unless
|
|
// transactions are not ordered by (ascending or descending) date.
|
|
transactionView->scrollTo(targetIndex);
|
|
// scrollTo() does not scroll far enough the first time when transactions
|
|
// are ordered by ascending date.
|
|
if (index == results[0]) transactionView->scrollTo(targetIndex);
|
|
}
|
|
}
|
|
|
|
// We override the virtual resizeEvent of the QWidget to adjust tables column
|
|
// sizes as the tables width is proportional to the dialogs width.
|
|
void TransactionView::resizeEvent(QResizeEvent* event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
|
|
}
|
|
|
|
// Need to override default Ctrl+C action for amount as default behaviour is just to copy DisplayRole text
|
|
bool TransactionView::eventFilter(QObject *obj, QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::KeyPress)
|
|
{
|
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
|
if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier))
|
|
{
|
|
GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
|
|
return true;
|
|
}
|
|
}
|
|
return QWidget::eventFilter(obj, event);
|
|
}
|
|
|
|
// show/hide column Watch-only
|
|
void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly)
|
|
{
|
|
watchOnlyWidget->setVisible(fHaveWatchOnly);
|
|
transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly);
|
|
}
|