mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[Client] Report queue dashboard and status pills
TabReport becomes a dashboard: selected-report identity header (display-size user, bold status, category/time/room subline), Description/Chat/Comments/Reported-user tabbed sections with tab memory, always-visible user context with empty cues, and bold reported users. ReportStatusDelegate paints palette-tinted status pills with paint-through selection, translated status strings, and font/elision handling. report_utils gains formatReportStatus plus an opt-out status-color flag so the delegate owns color in the mod queue while the user dialog keeps its colors. Async responses stay guarded; retranslation re-applies header and comment states.
This commit is contained in:
parent
080798b0e1
commit
31878eb880
7 changed files with 262 additions and 45 deletions
|
|
@ -376,6 +376,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
|
src/interface/widgets/tabs/api/edhrec/display/top_tags/edhrec_top_tags_api_response_display_widget.cpp
|
||||||
src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp
|
src/interface/widgets/tabs/api/edhrec/tab_edhrec.cpp
|
||||||
src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp
|
src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp
|
||||||
|
src/interface/widgets/tabs/report_status_delegate.cpp
|
||||||
src/interface/widgets/tabs/tab.cpp
|
src/interface/widgets/tabs/tab.cpp
|
||||||
src/interface/widgets/tabs/tab_account.cpp
|
src/interface/widgets/tabs/tab_account.cpp
|
||||||
src/interface/widgets/tabs/tab_admin.cpp
|
src/interface/widgets/tabs/tab_admin.cpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "report_status_delegate.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStyleOptionViewItem>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr qreal PILL_ALPHA = 0.30;
|
||||||
|
constexpr int PILL_PAD_X = 10;
|
||||||
|
constexpr int PILL_PAD_Y = 4;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ReportStatusDelegate::ReportStatusDelegate(QObject *parent) : QStyledItemDelegate(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const bool selected = (option.state & QStyle::State_Selected) != 0;
|
||||||
|
QString status = index.data(Qt::UserRole).toString();
|
||||||
|
if (status.isEmpty()) {
|
||||||
|
status = index.data(Qt::DisplayRole).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPalette::ColorRole tintRole = QPalette::NoRole;
|
||||||
|
if (status == QStringLiteral("open")) {
|
||||||
|
tintRole = QPalette::Highlight;
|
||||||
|
} else if (status == QStringLiteral("assigned")) {
|
||||||
|
tintRole = QPalette::Link;
|
||||||
|
} else if (status == QStringLiteral("resolved")) {
|
||||||
|
tintRole = QPalette::PlaceholderText;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStyleOptionViewItem opt(option);
|
||||||
|
initStyleOption(&opt, index);
|
||||||
|
painter->setFont(opt.font);
|
||||||
|
|
||||||
|
if (tintRole == QPalette::NoRole) {
|
||||||
|
const QPalette::ColorRole textRole = selected ? QPalette::HighlightedText : QPalette::PlaceholderText;
|
||||||
|
QStyle *fallbackStyle = opt.widget != nullptr ? opt.widget->style() : QApplication::style();
|
||||||
|
fallbackStyle->drawItemText(painter, opt.rect, Qt::AlignLeft | Qt::AlignVCenter, opt.palette, true, opt.text,
|
||||||
|
textRole);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QRect pillRect = opt.rect.adjusted(PILL_PAD_X / 2, PILL_PAD_Y / 2, -PILL_PAD_X / 2, -PILL_PAD_Y / 2);
|
||||||
|
if (pillRect.width() <= 0 || pillRect.height() <= 0) {
|
||||||
|
QStyledItemDelegate::paint(painter, opt, index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selected) {
|
||||||
|
painter->save();
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
QColor pill = opt.palette.color(tintRole);
|
||||||
|
pill.setAlphaF(PILL_ALPHA);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(pill);
|
||||||
|
painter->drawRoundedRect(pillRect, pillRect.height() / 2.0, pillRect.height() / 2.0);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString elided =
|
||||||
|
opt.fontMetrics.elidedText(opt.text.isEmpty() ? status : opt.text, opt.textElideMode, pillRect.width());
|
||||||
|
const QPalette::ColorRole textRole = selected ? QPalette::HighlightedText : QPalette::WindowText;
|
||||||
|
QStyle *style = opt.widget != nullptr ? opt.widget->style() : QApplication::style();
|
||||||
|
style->drawItemText(painter, pillRect, Qt::AlignCenter, opt.palette, true, elided, textRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ReportStatusDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const QSize hint = QStyledItemDelegate::sizeHint(option, index);
|
||||||
|
return hint + QSize(PILL_PAD_X, PILL_PAD_Y);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef REPORT_STATUS_DELEGATE_H
|
||||||
|
#define REPORT_STATUS_DELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status pill for the report queue table. Paints the status text on a
|
||||||
|
* translucent badge tinted with a palette role per status, so the colors
|
||||||
|
* always follow the active theme. Falls back to default painting for
|
||||||
|
* selected rows and unknown statuses.
|
||||||
|
*/
|
||||||
|
class ReportStatusDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ReportStatusDelegate(QObject *parent = nullptr);
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
[[nodiscard]] QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REPORT_STATUS_DELEGATE_H
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../utility/report_utils.h"
|
#include "../utility/report_utils.h"
|
||||||
#include "abstract_client.h"
|
#include "abstract_client.h"
|
||||||
#include "libcockatrice/protocol/pb/response.pb.h"
|
#include "libcockatrice/protocol/pb/response.pb.h"
|
||||||
|
#include "report_status_delegate.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
|
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
|
|
@ -22,7 +23,7 @@
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
#include <QSplitter>
|
#include <QTabWidget>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
#include <QTableWidgetItem>
|
#include <QTableWidgetItem>
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
|
|
@ -124,25 +125,42 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
connect(table, &QTableWidget::itemSelectionChanged, this, &TabReport::onSelectionChanged);
|
connect(table, &QTableWidget::itemSelectionChanged, this, &TabReport::onSelectionChanged);
|
||||||
table->setContextMenuPolicy(Qt::CustomContextMenu);
|
table->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(table, &QTableWidget::customContextMenuRequested, this, &TabReport::showTableContextMenu);
|
connect(table, &QTableWidget::customContextMenuRequested, this, &TabReport::showTableContextMenu);
|
||||||
|
table->setItemDelegateForColumn(COL_STATUS, new ReportStatusDelegate(table));
|
||||||
userContextMenu = new UserContextMenu(tabSupervisor, this);
|
userContextMenu = new UserContextMenu(tabSupervisor, this);
|
||||||
connect(userContextMenu, &UserContextMenu::openMessageDialog, this, &TabReport::openMessageDialog);
|
connect(userContextMenu, &UserContextMenu::openMessageDialog, this, &TabReport::openMessageDialog);
|
||||||
|
|
||||||
descGroup = new QGroupBox;
|
reportHeaderName = new QLabel;
|
||||||
|
QFont displayFont = reportHeaderName->font();
|
||||||
|
displayFont.setPointSize(displayFont.pointSize() + 6);
|
||||||
|
displayFont.setBold(true);
|
||||||
|
reportHeaderName->setFont(displayFont);
|
||||||
|
reportHeaderStatus = new QLabel;
|
||||||
|
QFont statusFont = reportHeaderStatus->font();
|
||||||
|
statusFont.setBold(true);
|
||||||
|
reportHeaderStatus->setFont(statusFont);
|
||||||
|
reportHeaderSubline = new QLabel;
|
||||||
|
|
||||||
|
auto *reportIdentityRow = new QHBoxLayout;
|
||||||
|
reportIdentityRow->addWidget(reportHeaderName);
|
||||||
|
reportIdentityRow->addStretch();
|
||||||
|
reportIdentityRow->addWidget(reportHeaderStatus);
|
||||||
|
|
||||||
|
auto *descPage = new QWidget;
|
||||||
descriptionEdit = new QTextEdit;
|
descriptionEdit = new QTextEdit;
|
||||||
descriptionEdit->setReadOnly(true);
|
descriptionEdit->setReadOnly(true);
|
||||||
auto *descLayout = new QVBoxLayout(descGroup);
|
auto *descLayout = new QVBoxLayout(descPage);
|
||||||
descLayout->setContentsMargins(4, 4, 4, 4);
|
descLayout->setContentsMargins(4, 4, 4, 4);
|
||||||
descLayout->addWidget(descriptionEdit);
|
descLayout->addWidget(descriptionEdit);
|
||||||
|
|
||||||
chatGroup = new QGroupBox;
|
auto *chatPage = new QWidget;
|
||||||
chatLogEdit = new QTextEdit;
|
chatLogEdit = new QTextEdit;
|
||||||
chatLogEdit->setReadOnly(true);
|
chatLogEdit->setReadOnly(true);
|
||||||
chatLogEdit->setFont(QtUtils::monospaceFont());
|
chatLogEdit->setFont(QtUtils::monospaceFont());
|
||||||
auto *chatLayout = new QVBoxLayout(chatGroup);
|
auto *chatLayout = new QVBoxLayout(chatPage);
|
||||||
chatLayout->setContentsMargins(4, 4, 4, 4);
|
chatLayout->setContentsMargins(4, 4, 4, 4);
|
||||||
chatLayout->addWidget(chatLogEdit);
|
chatLayout->addWidget(chatLogEdit);
|
||||||
|
|
||||||
commentsGroup = new QGroupBox;
|
auto *commentsPage = new QWidget;
|
||||||
commentsEdit = new QTextEdit;
|
commentsEdit = new QTextEdit;
|
||||||
commentsEdit->setReadOnly(true);
|
commentsEdit->setReadOnly(true);
|
||||||
auto *commentInputRow = new QHBoxLayout;
|
auto *commentInputRow = new QHBoxLayout;
|
||||||
|
|
@ -153,12 +171,12 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
connect(commentInput, &QLineEdit::returnPressed, this, &TabReport::addComment);
|
connect(commentInput, &QLineEdit::returnPressed, this, &TabReport::addComment);
|
||||||
commentInputRow->addWidget(commentInput);
|
commentInputRow->addWidget(commentInput);
|
||||||
commentInputRow->addWidget(commentButton);
|
commentInputRow->addWidget(commentButton);
|
||||||
auto *commentsLayout = new QVBoxLayout(commentsGroup);
|
auto *commentsLayout = new QVBoxLayout(commentsPage);
|
||||||
commentsLayout->setContentsMargins(4, 4, 4, 4);
|
commentsLayout->setContentsMargins(4, 4, 4, 4);
|
||||||
commentsLayout->addWidget(commentsEdit);
|
commentsLayout->addWidget(commentsEdit);
|
||||||
commentsLayout->addLayout(commentInputRow);
|
commentsLayout->addLayout(commentInputRow);
|
||||||
|
|
||||||
userContextGroup = new QGroupBox;
|
auto *userPage = new QWidget;
|
||||||
userContextName = new QLabel;
|
userContextName = new QLabel;
|
||||||
userContextAccountAge = new QLabel;
|
userContextAccountAge = new QLabel;
|
||||||
userContextReports = new QLabel;
|
userContextReports = new QLabel;
|
||||||
|
|
@ -177,7 +195,7 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
userContextWarnsLabel = new QLabel;
|
userContextWarnsLabel = new QLabel;
|
||||||
userContextNotesLabel = new QLabel;
|
userContextNotesLabel = new QLabel;
|
||||||
userContextRecentReportsLabel = new QLabel;
|
userContextRecentReportsLabel = new QLabel;
|
||||||
auto *ucLayout = new QGridLayout(userContextGroup);
|
auto *ucLayout = new QGridLayout(userPage);
|
||||||
ucLayout->setContentsMargins(8, 8, 8, 8);
|
ucLayout->setContentsMargins(8, 8, 8, 8);
|
||||||
ucLayout->addWidget(userContextUserLabel, 0, 0);
|
ucLayout->addWidget(userContextUserLabel, 0, 0);
|
||||||
ucLayout->addWidget(userContextName, 0, 1, 1, 3);
|
ucLayout->addWidget(userContextName, 0, 1, 1, 3);
|
||||||
|
|
@ -193,7 +211,6 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
ucLayout->addWidget(userContextNotes, 3, 1, 1, 3);
|
ucLayout->addWidget(userContextNotes, 3, 1, 1, 3);
|
||||||
ucLayout->addWidget(userContextRecentReportsLabel, 4, 0, 1, 4);
|
ucLayout->addWidget(userContextRecentReportsLabel, 4, 0, 1, 4);
|
||||||
ucLayout->addWidget(userContextRecentReports, 5, 0, 1, 4);
|
ucLayout->addWidget(userContextRecentReports, 5, 0, 1, 4);
|
||||||
userContextGroup->setVisible(false);
|
|
||||||
|
|
||||||
statsGroup = new QGroupBox;
|
statsGroup = new QGroupBox;
|
||||||
statsGroup->setCheckable(true);
|
statsGroup->setCheckable(true);
|
||||||
|
|
@ -220,13 +237,11 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
detailSplitter = new QSplitter(Qt::Vertical);
|
detailTabs = new QTabWidget;
|
||||||
detailSplitter->addWidget(descGroup);
|
detailTabs->addTab(descPage, QString());
|
||||||
detailSplitter->addWidget(chatGroup);
|
detailTabs->addTab(chatPage, QString());
|
||||||
detailSplitter->addWidget(commentsGroup);
|
detailTabs->addTab(commentsPage, QString());
|
||||||
detailSplitter->setStretchFactor(0, 1);
|
detailTabs->addTab(userPage, QString());
|
||||||
detailSplitter->setStretchFactor(1, 1);
|
|
||||||
detailSplitter->setStretchFactor(2, 2);
|
|
||||||
|
|
||||||
assignButton = new QPushButton;
|
assignButton = new QPushButton;
|
||||||
resolveButton = new QPushButton;
|
resolveButton = new QPushButton;
|
||||||
|
|
@ -258,12 +273,14 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
||||||
layout->addLayout(topBar);
|
layout->addLayout(topBar);
|
||||||
layout->addWidget(statsLabel);
|
layout->addWidget(statsLabel);
|
||||||
layout->addWidget(table, 2);
|
layout->addWidget(table, 2);
|
||||||
layout->addWidget(detailSplitter, 1);
|
layout->addLayout(reportIdentityRow);
|
||||||
layout->addWidget(userContextGroup);
|
layout->addWidget(reportHeaderSubline);
|
||||||
|
layout->addWidget(detailTabs, 2);
|
||||||
layout->addWidget(statsGroup);
|
layout->addWidget(statsGroup);
|
||||||
layout->addLayout(actionBar);
|
layout->addLayout(actionBar);
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
clearReportHeader();
|
||||||
|
|
||||||
setActionsEnabled(false);
|
setActionsEnabled(false);
|
||||||
refreshList();
|
refreshList();
|
||||||
|
|
@ -285,18 +302,18 @@ void TabReport::retranslateUi()
|
||||||
table->setHorizontalHeaderLabels({tr("#"), tr("Time"), tr("Reporter"), tr("Reported User"), tr("Category"),
|
table->setHorizontalHeaderLabels({tr("#"), tr("Time"), tr("Reporter"), tr("Reported User"), tr("Category"),
|
||||||
tr("Game ID"), tr("Status"), tr("Assigned To"), tr("Replay"), tr("Room")});
|
tr("Game ID"), tr("Status"), tr("Assigned To"), tr("Replay"), tr("Room")});
|
||||||
|
|
||||||
descGroup->setTitle(tr("Description"));
|
detailTabs->setTabText(0, tr("Description"));
|
||||||
chatGroup->setTitle(tr("Chat Log Context"));
|
detailTabs->setTabText(1, tr("Chat Log Context"));
|
||||||
chatGroup->setToolTip(
|
detailTabs->setTabToolTip(1, tr("Chat log attached by the reporter. It is captured from their client and may be "
|
||||||
tr("Chat log attached by the reporter. It is captured from their client and may be incomplete or edited."));
|
"incomplete or edited."));
|
||||||
commentsGroup->setTitle(tr("Comments / Thread"));
|
detailTabs->setTabText(2, tr("Comments / Thread"));
|
||||||
|
detailTabs->setTabText(3, tr("Reported User"));
|
||||||
descriptionEdit->setPlaceholderText(tr("No description."));
|
descriptionEdit->setPlaceholderText(tr("No description."));
|
||||||
chatLogEdit->setPlaceholderText(tr("No chat log attached."));
|
chatLogEdit->setPlaceholderText(tr("No chat log attached."));
|
||||||
commentsEdit->setPlaceholderText(tr("No comments yet."));
|
commentsEdit->setPlaceholderText(tr("No comments yet."));
|
||||||
commentInput->setPlaceholderText(tr("Type a reply..."));
|
commentInput->setPlaceholderText(tr("Type a reply..."));
|
||||||
commentButton->setText(tr("Send"));
|
commentButton->setText(tr("Send"));
|
||||||
|
|
||||||
userContextGroup->setTitle(tr("Reported User Context"));
|
|
||||||
userContextUserLabel->setText(tr("User:"));
|
userContextUserLabel->setText(tr("User:"));
|
||||||
userContextAgeLabel->setText(tr("Account Age:"));
|
userContextAgeLabel->setText(tr("Account Age:"));
|
||||||
userContextReportsLabel->setText(tr("Reports:"));
|
userContextReportsLabel->setText(tr("Reports:"));
|
||||||
|
|
@ -304,10 +321,18 @@ void TabReport::retranslateUi()
|
||||||
userContextWarnsLabel->setText(tr("Warns:"));
|
userContextWarnsLabel->setText(tr("Warns:"));
|
||||||
userContextNotesLabel->setText(tr("Admin Notes:"));
|
userContextNotesLabel->setText(tr("Admin Notes:"));
|
||||||
userContextRecentReportsLabel->setText(tr("Recent Reports Against User:"));
|
userContextRecentReportsLabel->setText(tr("Recent Reports Against User:"));
|
||||||
userContextAccountAge->setText(QString());
|
|
||||||
userContextReports->setText(QString());
|
if (headerReportId >= 0) {
|
||||||
userContextBans->setText(QString());
|
for (const ServerInfo_Report &r : filteredReports) {
|
||||||
userContextWarns->setText(QString());
|
if (r.report_id() == headerReportId) {
|
||||||
|
updateReportHeader(r);
|
||||||
|
const QString status = QString::fromStdString(r.status());
|
||||||
|
const bool canComment = (status == "open" || status == "assigned");
|
||||||
|
commentInput->setPlaceholderText(canComment ? tr("Type a reply...") : tr("This report is closed."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
statsGroup->setTitle(tr("Report Statistics"));
|
statsGroup->setTitle(tr("Report Statistics"));
|
||||||
|
|
||||||
|
|
@ -400,7 +425,8 @@ void TabReport::reportListResponse(const Response &response)
|
||||||
chatLogEdit->clear();
|
chatLogEdit->clear();
|
||||||
commentsEdit->clear();
|
commentsEdit->clear();
|
||||||
setActionsEnabled(false);
|
setActionsEnabled(false);
|
||||||
userContextGroup->setVisible(false);
|
clearReportHeader();
|
||||||
|
clearUserContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,7 +467,7 @@ void TabReport::applyFilters()
|
||||||
const ServerInfo_Report &r = filteredReports[row];
|
const ServerInfo_Report &r = filteredReports[row];
|
||||||
|
|
||||||
report_utils::fillReportTableRow(table, row, r, COL_ID, COL_TIME, COL_REPORTED, COL_CATEGORY, COL_GAMEID,
|
report_utils::fillReportTableRow(table, row, r, COL_ID, COL_TIME, COL_REPORTED, COL_CATEGORY, COL_GAMEID,
|
||||||
COL_STATUS, COL_ASSIGNED);
|
COL_STATUS, COL_ASSIGNED, false);
|
||||||
|
|
||||||
table->setItem(row, COL_REPORTER, new QTableWidgetItem(QString::fromStdString(r.reporter_name())));
|
table->setItem(row, COL_REPORTER, new QTableWidgetItem(QString::fromStdString(r.reporter_name())));
|
||||||
|
|
||||||
|
|
@ -452,10 +478,32 @@ void TabReport::applyFilters()
|
||||||
new QTableWidgetItem(r.has_room_id() && r.room_id() > 0 ? QString::number(r.room_id()) : ""));
|
new QTableWidgetItem(r.has_room_id() && r.room_id() > 0 ? QString::number(r.room_id()) : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFont reportedFont = table->font();
|
||||||
|
reportedFont.setBold(true);
|
||||||
|
for (int row = 0; row < filteredReports.size(); ++row) {
|
||||||
|
if (auto *reportedItem = table->item(row, COL_REPORTED)) {
|
||||||
|
reportedItem->setFont(reportedFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table->setSortingEnabled(true);
|
table->setSortingEnabled(true);
|
||||||
table->resizeColumnsToContents();
|
table->resizeColumnsToContents();
|
||||||
table->horizontalHeader()->setSectionResizeMode(COL_REPORTED, QHeaderView::Stretch);
|
table->horizontalHeader()->setSectionResizeMode(COL_REPORTED, QHeaderView::Stretch);
|
||||||
|
|
||||||
|
if (headerReportId >= 0) {
|
||||||
|
bool stillVisible = false;
|
||||||
|
for (const ServerInfo_Report &r : filteredReports) {
|
||||||
|
if (r.report_id() == headerReportId) {
|
||||||
|
stillVisible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!stillVisible) {
|
||||||
|
clearReportHeader();
|
||||||
|
clearUserContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
statusLabel->setText(tr("%1 report(s)").arg(filteredReports.size()));
|
statusLabel->setText(tr("%1 report(s)").arg(filteredReports.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,6 +530,31 @@ void TabReport::updateStats()
|
||||||
.arg(dismissed));
|
.arg(dismissed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabReport::updateReportHeader(const ServerInfo_Report &report)
|
||||||
|
{
|
||||||
|
reportHeaderName->setText(QString::fromStdString(report.reported_user_name()));
|
||||||
|
reportHeaderStatus->setText(report_utils::formatReportStatus(QString::fromStdString(report.status())));
|
||||||
|
|
||||||
|
QStringList parts;
|
||||||
|
parts << QString::fromStdString(report.category());
|
||||||
|
parts << QDateTime::fromSecsSinceEpoch(report.report_time()).toLocalTime().toString("yyyy-MM-dd HH:mm");
|
||||||
|
if (report.has_room_id() && report.room_id() > 0) {
|
||||||
|
parts << tr("Room %1").arg(report.room_id());
|
||||||
|
}
|
||||||
|
if (report.game_id() > 0) {
|
||||||
|
parts << tr("Game %1").arg(report.game_id());
|
||||||
|
}
|
||||||
|
reportHeaderSubline->setText(parts.join(QStringLiteral(" · ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TabReport::clearReportHeader()
|
||||||
|
{
|
||||||
|
headerReportId = -1;
|
||||||
|
reportHeaderName->setText(tr("Select a report to inspect."));
|
||||||
|
reportHeaderStatus->clear();
|
||||||
|
reportHeaderSubline->clear();
|
||||||
|
}
|
||||||
|
|
||||||
void TabReport::onSelectionChanged()
|
void TabReport::onSelectionChanged()
|
||||||
{
|
{
|
||||||
const int row = table->currentRow();
|
const int row = table->currentRow();
|
||||||
|
|
@ -492,7 +565,8 @@ void TabReport::onSelectionChanged()
|
||||||
commentInput->clear();
|
commentInput->clear();
|
||||||
commentButton->setEnabled(false);
|
commentButton->setEnabled(false);
|
||||||
setActionsEnabled(false);
|
setActionsEnabled(false);
|
||||||
userContextGroup->setVisible(false);
|
clearReportHeader();
|
||||||
|
clearUserContext();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,6 +575,18 @@ void TabReport::onSelectionChanged()
|
||||||
updateActionStates();
|
updateActionStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabReport::clearUserContext()
|
||||||
|
{
|
||||||
|
lastRequestedUser.clear();
|
||||||
|
userContextName->setText(tr("—"));
|
||||||
|
userContextAccountAge->clear();
|
||||||
|
userContextReports->clear();
|
||||||
|
userContextBans->clear();
|
||||||
|
userContextWarns->clear();
|
||||||
|
userContextNotes->setPlainText(tr("Select a report to inspect."));
|
||||||
|
userContextRecentReports->clear();
|
||||||
|
}
|
||||||
|
|
||||||
void TabReport::showTableContextMenu(const QPoint &pos)
|
void TabReport::showTableContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QTableWidgetItem *clickedItem = table->itemAt(pos);
|
QTableWidgetItem *clickedItem = table->itemAt(pos);
|
||||||
|
|
@ -538,12 +624,17 @@ void TabReport::loadReportDetails(int reportId)
|
||||||
for (const ServerInfo_Report &r : filteredReports) {
|
for (const ServerInfo_Report &r : filteredReports) {
|
||||||
if (r.report_id() == reportId) {
|
if (r.report_id() == reportId) {
|
||||||
descriptionEdit->setPlainText(QString::fromStdString(r.description()));
|
descriptionEdit->setPlainText(QString::fromStdString(r.description()));
|
||||||
|
updateReportHeader(r);
|
||||||
|
if (headerReportId != reportId) {
|
||||||
|
headerReportId = reportId;
|
||||||
|
detailTabs->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
QString reportedUser = QString::fromStdString(r.reported_user_name());
|
QString reportedUser = QString::fromStdString(r.reported_user_name());
|
||||||
if (!reportedUser.isEmpty()) {
|
if (!reportedUser.isEmpty()) {
|
||||||
requestUserInfo(reportedUser);
|
requestUserInfo(reportedUser);
|
||||||
} else {
|
} else {
|
||||||
userContextGroup->setVisible(false);
|
clearUserContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString status = QString::fromStdString(r.status());
|
QString status = QString::fromStdString(r.status());
|
||||||
|
|
@ -863,12 +954,11 @@ void TabReport::addCommentResponse(const Response &response)
|
||||||
void TabReport::requestUserInfo(const QString &userName)
|
void TabReport::requestUserInfo(const QString &userName)
|
||||||
{
|
{
|
||||||
if (userName.isEmpty()) {
|
if (userName.isEmpty()) {
|
||||||
userContextGroup->setVisible(false);
|
clearUserContext();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastRequestedUser = userName;
|
lastRequestedUser = userName;
|
||||||
userContextGroup->setVisible(true);
|
|
||||||
userContextName->setText(userName);
|
userContextName->setText(userName);
|
||||||
userContextAccountAge->setText(tr("Loading..."));
|
userContextAccountAge->setText(tr("Loading..."));
|
||||||
userContextReports->clear();
|
userContextReports->clear();
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ class QGroupBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QSplitter;
|
|
||||||
class QTableWidget;
|
class QTableWidget;
|
||||||
|
class QTabWidget;
|
||||||
class QTextEdit;
|
class QTextEdit;
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class GameReplay;
|
class GameReplay;
|
||||||
|
|
@ -71,6 +71,9 @@ private:
|
||||||
void applyFilters();
|
void applyFilters();
|
||||||
void updateStats();
|
void updateStats();
|
||||||
void loadReportDetails(int reportId);
|
void loadReportDetails(int reportId);
|
||||||
|
void updateReportHeader(const ServerInfo_Report &report);
|
||||||
|
void clearReportHeader();
|
||||||
|
void clearUserContext();
|
||||||
|
|
||||||
AbstractClient *client;
|
AbstractClient *client;
|
||||||
|
|
||||||
|
|
@ -80,10 +83,10 @@ private:
|
||||||
QPushButton *refreshButton;
|
QPushButton *refreshButton;
|
||||||
QLabel *statsLabel;
|
QLabel *statsLabel;
|
||||||
QTableWidget *table;
|
QTableWidget *table;
|
||||||
QSplitter *detailSplitter;
|
QLabel *reportHeaderName;
|
||||||
QGroupBox *descGroup;
|
QLabel *reportHeaderStatus;
|
||||||
QGroupBox *chatGroup;
|
QLabel *reportHeaderSubline;
|
||||||
QGroupBox *commentsGroup;
|
QTabWidget *detailTabs;
|
||||||
QTextEdit *descriptionEdit;
|
QTextEdit *descriptionEdit;
|
||||||
QTextEdit *chatLogEdit;
|
QTextEdit *chatLogEdit;
|
||||||
QTextEdit *commentsEdit;
|
QTextEdit *commentsEdit;
|
||||||
|
|
@ -99,7 +102,6 @@ private:
|
||||||
QTimer *refreshTimer;
|
QTimer *refreshTimer;
|
||||||
UserContextMenu *userContextMenu;
|
UserContextMenu *userContextMenu;
|
||||||
|
|
||||||
QGroupBox *userContextGroup;
|
|
||||||
QLabel *userContextName;
|
QLabel *userContextName;
|
||||||
QLabel *userContextAccountAge;
|
QLabel *userContextAccountAge;
|
||||||
QLabel *userContextReports;
|
QLabel *userContextReports;
|
||||||
|
|
@ -124,6 +126,7 @@ private:
|
||||||
|
|
||||||
QList<ServerInfo_Report> allReports;
|
QList<ServerInfo_Report> allReports;
|
||||||
QList<ServerInfo_Report> filteredReports;
|
QList<ServerInfo_Report> filteredReports;
|
||||||
|
int headerReportId = -1;
|
||||||
int detailsRequestedReportId = -1;
|
int detailsRequestedReportId = -1;
|
||||||
int detailsRequestSeq = 0;
|
int detailsRequestSeq = 0;
|
||||||
int selectedReportIdBeforeRefresh = -1;
|
int selectedReportIdBeforeRefresh = -1;
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,23 @@ QString formatReportTime(qint64 secondsSinceEpoch)
|
||||||
return dt.toString("yyyy-MM-dd hh:mm");
|
return dt.toString("yyyy-MM-dd hh:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString formatReportStatus(const QString &status)
|
||||||
|
{
|
||||||
|
if (status == QStringLiteral("open")) {
|
||||||
|
return QObject::tr("Open");
|
||||||
|
}
|
||||||
|
if (status == QStringLiteral("assigned")) {
|
||||||
|
return QObject::tr("Assigned");
|
||||||
|
}
|
||||||
|
if (status == QStringLiteral("resolved")) {
|
||||||
|
return QObject::tr("Resolved");
|
||||||
|
}
|
||||||
|
if (status == QStringLiteral("dismissed")) {
|
||||||
|
return QObject::tr("Dismissed");
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
void fillReportTableRow(QTableWidget *table,
|
void fillReportTableRow(QTableWidget *table,
|
||||||
int row,
|
int row,
|
||||||
const ServerInfo_Report &report,
|
const ServerInfo_Report &report,
|
||||||
|
|
@ -73,7 +90,8 @@ void fillReportTableRow(QTableWidget *table,
|
||||||
int categoryColumn,
|
int categoryColumn,
|
||||||
int gameIdColumn,
|
int gameIdColumn,
|
||||||
int statusColumn,
|
int statusColumn,
|
||||||
int assignedColumn)
|
int assignedColumn,
|
||||||
|
bool colorizeStatus)
|
||||||
{
|
{
|
||||||
auto *idItem = new QTableWidgetItem(QString::number(report.report_id()));
|
auto *idItem = new QTableWidgetItem(QString::number(report.report_id()));
|
||||||
idItem->setData(Qt::UserRole, report.report_id());
|
idItem->setData(Qt::UserRole, report.report_id());
|
||||||
|
|
@ -86,8 +104,12 @@ void fillReportTableRow(QTableWidget *table,
|
||||||
table->setItem(row, gameIdColumn,
|
table->setItem(row, gameIdColumn,
|
||||||
new QTableWidgetItem(report.game_id() > 0 ? QString::number(report.game_id()) : QString()));
|
new QTableWidgetItem(report.game_id() > 0 ? QString::number(report.game_id()) : QString()));
|
||||||
|
|
||||||
auto *statusItem = new QTableWidgetItem(QString::fromStdString(report.status()));
|
const QString rawStatus = QString::fromStdString(report.status());
|
||||||
setReportStatusItemColor(statusItem, QString::fromStdString(report.status()));
|
auto *statusItem = new QTableWidgetItem(formatReportStatus(rawStatus));
|
||||||
|
statusItem->setData(Qt::UserRole, rawStatus);
|
||||||
|
if (colorizeStatus) {
|
||||||
|
setReportStatusItemColor(statusItem, rawStatus);
|
||||||
|
}
|
||||||
table->setItem(row, statusColumn, statusItem);
|
table->setItem(row, statusColumn, statusItem);
|
||||||
|
|
||||||
table->setItem(row, assignedColumn, new QTableWidgetItem(QString::fromStdString(report.assigned_mod_name())));
|
table->setItem(row, assignedColumn, new QTableWidgetItem(QString::fromStdString(report.assigned_mod_name())));
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace report_utils
|
||||||
|
|
||||||
QString formatReportCategory(const QString &category);
|
QString formatReportCategory(const QString &category);
|
||||||
QString formatReportTime(qint64 secondsSinceEpoch);
|
QString formatReportTime(qint64 secondsSinceEpoch);
|
||||||
|
QString formatReportStatus(const QString &status);
|
||||||
|
|
||||||
void fillReportTableRow(QTableWidget *table,
|
void fillReportTableRow(QTableWidget *table,
|
||||||
int row,
|
int row,
|
||||||
|
|
@ -23,7 +24,8 @@ void fillReportTableRow(QTableWidget *table,
|
||||||
int categoryColumn,
|
int categoryColumn,
|
||||||
int gameIdColumn,
|
int gameIdColumn,
|
||||||
int statusColumn,
|
int statusColumn,
|
||||||
int assignedColumn);
|
int assignedColumn,
|
||||||
|
bool colorizeStatus = true);
|
||||||
|
|
||||||
void renderReportDetails(QTextEdit *chatLogEdit,
|
void renderReportDetails(QTextEdit *chatLogEdit,
|
||||||
QTextEdit *commentsEdit,
|
QTextEdit *commentsEdit,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue