feather/src/model/HistoryView.cpp
2024-01-01 18:07:58 +01:00

224 lines
No EOL
7.3 KiB
C++

// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2020-2024 The Monero Project
#include "HistoryView.h"
#include "TransactionHistoryProxyModel.h"
#include "utils/Utils.h"
#include "utils/config.h"
#include <QHeaderView>
#include <QMenu>
HistoryView::HistoryView(QWidget *parent)
: QTreeView(parent)
, m_model(nullptr)
, m_headerMenu(new QMenu(this))
{
setUniformRowHeights(true);
setRootIsDecorated(false);
setAlternatingRowColors(true);
setDragEnabled(true);
setSortingEnabled(true);
header()->setStretchLastSection(false);
header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(showHeaderMenu(QPoint)));
}
void HistoryView::setHistoryModel(TransactionHistoryProxyModel *model) {
m_model = model;
m_model->setSortCaseSensitivity(Qt::CaseInsensitive);
m_model->setSortRole(Qt::UserRole);
m_model->setDynamicSortFilter(true);
m_model->setSortLocaleAware(true);
QTreeView::setModel(m_model);
resetViewToDefaults();
m_headerMenu->clear();
// Actions to toggle column visibility, each carrying the corresponding
// column index as data
m_columnActions = new QActionGroup(this);
m_columnActions->setExclusive(false);
for (int visualIndex = 1; visualIndex < header()->count(); ++visualIndex) {
int logicalIndex = header()->logicalIndex(visualIndex);
QString caption = m_model->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString();
if (caption.isEmpty()) {
caption = m_model->headerData(logicalIndex, Qt::Horizontal, Qt::ToolTipRole).toString();
}
auto action = m_headerMenu->addAction(caption);
action->setCheckable(true);
action->setData(logicalIndex);
m_columnActions->addAction(action);
}
connect(m_columnActions, &QActionGroup::triggered, this, &HistoryView::toggleColumnVisibility);
m_headerMenu->addSeparator();
auto action = m_headerMenu->addAction("Show full txid", this, &HistoryView::showFullTxid);
action->setCheckable(true);
action->setChecked(conf()->get(Config::historyShowFullTxid).toBool());
m_headerMenu->addSeparator();
m_headerMenu->addAction(tr("Fit to window"), this, &HistoryView::fitColumnsToWindow);
m_headerMenu->addAction(tr("Fit to contents"), this, &HistoryView::fitColumnsToContents);
m_headerMenu->addSeparator();
m_headerMenu->addAction(tr("Reset to defaults"), this, &HistoryView::resetViewToDefaults);
fitColumnsToWindow();
}
TransactionHistoryModel* HistoryView::sourceModel()
{
return dynamic_cast<TransactionHistoryModel *>(m_model->sourceModel());
}
TransactionRow* HistoryView::currentEntry()
{
QModelIndexList list = selectionModel()->selectedRows();
if (list.size() == 1) {
return this->sourceModel()->entryFromIndex(m_model->mapToSource(list.first()));
} else {
return nullptr;
}
}
void HistoryView::setSearchMode(bool mode) {
if (!m_inSearchMode) {
m_showTxidColumn = !header()->isSectionHidden(TransactionHistoryModel::TxID);
}
m_inSearchMode = mode;
if (mode) {
header()->showSection(TransactionHistoryModel::TxID);
}
else if (!m_showTxidColumn) {
header()->hideSection(TransactionHistoryModel::TxID);
}
}
QByteArray HistoryView::viewState() const
{
return header()->saveState();
}
bool HistoryView::setViewState(const QByteArray& state)
{
// Reset to unsorted first (https://bugreports.qt.io/browse/QTBUG-86694)
header()->setSortIndicator(-1, Qt::AscendingOrder);
bool status = header()->restoreState(state);
m_columnsNeedRelayout = state.isEmpty();
m_showTxidColumn = !header()->isSectionHidden(TransactionHistoryModel::TxID);
return status;
}
void HistoryView::showHeaderMenu(const QPoint& position)
{
const QList<QAction*> actions = m_columnActions->actions();
for (auto& action : actions) {
Q_ASSERT(static_cast<QMetaType::Type>(action->data().type()) == QMetaType::Int);
if (static_cast<QMetaType::Type>(action->data().type()) != QMetaType::Int) {
continue;
}
int columnIndex = action->data().toInt();
action->setChecked(!isColumnHidden(columnIndex));
}
m_headerMenu->popup(mapToGlobal(position));
}
void HistoryView::toggleColumnVisibility(QAction* action)
{
// Verify action carries a column index as data. Since QVariant.toInt()
// below will accept anything that's interpretable as int, perform a type
// check here to make sure data actually IS int
Q_ASSERT(static_cast<QMetaType::Type>(action->data().type()) == QMetaType::Int);
if (static_cast<QMetaType::Type>(action->data().type()) != QMetaType::Int) {
return;
}
// Toggle column visibility. Visible columns will only be hidden if at
// least one visible column remains, as the table header will disappear
// entirely when all columns are hidden
int columnIndex = action->data().toInt();
if (action->isChecked()) {
header()->showSection(columnIndex);
if (header()->sectionSize(columnIndex) == 0) {
header()->resizeSection(columnIndex, header()->defaultSectionSize());
}
return;
}
if ((header()->count() - header()->hiddenSectionCount()) > 1) {
header()->hideSection(columnIndex);
return;
}
action->setChecked(true);
}
void HistoryView::showFullTxid(bool enabled) {
conf()->set(Config::historyShowFullTxid, enabled);
this->reset();
if (!enabled) {
this->resizeColumnToContents(TransactionHistoryModel::TxID);
}
}
void HistoryView::fitColumnsToWindow()
{
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
header()->setSectionResizeMode(TransactionHistoryModel::Description, QHeaderView::Stretch);
header()->setStretchLastSection(false);
QCoreApplication::processEvents();
}
void HistoryView::fitColumnsToContents()
{
header()->setSectionResizeMode(QHeaderView::ResizeToContents);
QCoreApplication::processEvents();
header()->setSectionResizeMode(QHeaderView::Interactive);
}
void HistoryView::resetViewToDefaults()
{
if (m_inSearchMode) {
header()->showSection(TransactionHistoryModel::TxID);
} else {
header()->hideSection(TransactionHistoryModel::TxID);
}
header()->showSection(TransactionHistoryModel::Date);
header()->showSection(TransactionHistoryModel::Description);
header()->showSection(TransactionHistoryModel::Amount);
header()->showSection(TransactionHistoryModel::FiatAmount);
// Reset column order to logical indices
for (int i = 0; i < header()->count(); ++i) {
header()->moveSection(header()->visualIndex(i), i);
}
m_model->sort(TransactionHistoryModel::Date, Qt::DescendingOrder);
sortByColumn(TransactionHistoryModel::Date, Qt::DescendingOrder);
// The following call only relayouts reliably if the widget has been shown
// already, so only do it if the widget is visible and let showEvent() handle
// the initial default layout.
if (isVisible()) {
fitColumnsToWindow();
}
}
void HistoryView::keyPressEvent(QKeyEvent *event) {
TransactionRow* tx = this->currentEntry();
if (event->matches(QKeySequence::Copy) && tx) {
Utils::copyToClipboard(tx->hash());
}
else {
QTreeView::keyPressEvent(event);
}
}