Compare commits

..

2 commits

Author SHA1 Message Date
Lukas Brübach
07ebd1067b [Client] Fix alt badge and trail review findings
- Drop the dead VPN warning branch: rowVisible() already hides IP rows
  above the threshold, so setVpnThreshold(), its member and the spin-box
  connect never took effect.
- Dim IP rows at shared_count > 2 instead of > 1: the count already
  includes the investigated account, so every IP row was dimmed.
- Truncate backStack when a breadcrumb is clicked instead of pushing the
  current user again, so the trail keeps a single path and Back works.
- Word-wrap the trail label so a long chain cannot widen the tab.
- Extract the status/match pill painting into widgets/utility/pill_painter
  and use it from both delegates instead of duplicating it.
2026-11-01 12:21:16 +01:00
Lukas Brübach
45ac3919ae [Client] Alt badges, breadcrumb trail, investigate button
AltTableDelegate paints palette-tinted match badges with paint-through selection, style warning/critical icons on nonzero counts, and font/elision handling. TabAlts gains a clickable breadcrumb trail, an Investigate-this-user button, and bold usernames. Async alts responses are guarded against stale investigations.
2026-10-13 22:09:09 +02:00
7 changed files with 8 additions and 80 deletions

View file

@ -307,8 +307,6 @@ set(cockatrice_SOURCES
src/interface/widgets/utility/pill_painter.h
src/interface/widgets/utility/report_utils.cpp
src/interface/widgets/utility/report_utils.h
src/interface/widgets/utility/table_activation.cpp
src/interface/widgets/utility/table_activation.h
src/interface/widgets/utility/sequence_edit.cpp
src/interface/widgets/utility/visibility_change_listener.cpp
src/interface/widgets/utility/visibility_change_listener.h

View file

@ -230,8 +230,7 @@ void DlgMyReports::onSelectionChanged()
connect(pend, &PendingCommand::finished, this, &DlgMyReports::reportDetailsResponse);
client->sendCommand(pend);
// The cell text is the translated label; the raw status lives in UserRole.
const QString status = table->item(row, COL_STATUS)->data(Qt::UserRole).toString();
QString status = table->item(row, COL_STATUS)->text();
bool canComment = (status == "open" || status == "assigned");
commentButton->setEnabled(canComment);
commentInput->setEnabled(canComment);

View file

@ -1,6 +1,5 @@
#include "tab_alts.h"
#include "../utility/table_activation.h"
#include "abstract_client.h"
#include "alt_table_delegate.h"
#include "libcockatrice/protocol/pb/response.pb.h"
@ -152,7 +151,7 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
altsTable->setItemDelegateForColumn(COL_ALTS_VIA, altsDelegate);
altsTable->setItemDelegateForColumn(COL_ALTS_WARNS, altsDelegate);
altsTable->setItemDelegateForColumn(COL_ALTS_BANS, altsDelegate);
connectTableActivation(altsTable, this, [this](const QModelIndex &index) {
connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) {
if (!index.isValid()) {
return;
}

View file

@ -1,6 +1,5 @@
#include "tab_moderation.h"
#include "../utility/table_activation.h"
#include "abstract_client.h"
#include "libcockatrice/protocol/pb/admin_commands.pb.h"
#include "libcockatrice/protocol/pb/response.pb.h"
@ -170,7 +169,7 @@ TabModeration::TabModeration(TabSupervisor *_tabSupervisor, AbstractClient *_cli
altsTable = new QTableWidget(0, COL_ALTS_COUNT);
configureTable(altsTable);
connectTableActivation(altsTable, this, [this](const QModelIndex &index) {
connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) {
if (!index.isValid()) {
return;
}
@ -450,14 +449,7 @@ void TabModeration::altsResponse(const Response &response)
}
const Response_UserAlts &resp = response.GetExtension(Response_UserAlts::ext);
// The server always includes the frontier user as a depth-0 seed row.
int relatedCount = 0;
for (int i = 0; i < resp.alts_size(); ++i) {
if (!resp.alts(i).has_depth() || resp.alts(i).depth() > 0) {
++relatedCount;
}
}
cachedAltsCount = relatedCount;
cachedAltsCount = resp.alts_size();
applyAltsCount();
altsTable->setRowCount(resp.alts_size());
for (int i = 0; i < resp.alts_size(); ++i) {

View file

@ -471,9 +471,6 @@ void TabReport::applyFilters()
table->setSortingEnabled(false);
table->setRowCount(filteredReports.size());
QFont reportedFont = table->font();
reportedFont.setBold(true);
for (int row = 0; row < filteredReports.size(); ++row) {
const ServerInfo_Report &r = filteredReports[row];
@ -487,7 +484,11 @@ void TabReport::applyFilters()
table->setItem(row, COL_ROOM,
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);
}

View file

@ -1,30 +0,0 @@
#include "table_activation.h"
#include <QKeySequence>
#include <QShortcut>
#include <QTableWidget>
namespace
{
void addActivationShortcut(QTableWidget *table,
QObject *context,
int key,
const std::function<void(const QModelIndex &)> &handler)
{
auto *shortcut = new QShortcut(QKeySequence(key), table);
// The table's viewport takes focus, so match children as well.
shortcut->setContext(Qt::WidgetWithChildrenShortcut);
QObject::connect(shortcut, &QShortcut::activated, context, [table, handler] {
handler(table->currentIndex());
});
}
} // namespace
void connectTableActivation(QTableWidget *table,
QObject *context,
const std::function<void(const QModelIndex &)> &handler)
{
QObject::connect(table, &QTableWidget::doubleClicked, context, handler);
addActivationShortcut(table, context, Qt::Key_Return, handler);
addActivationShortcut(table, context, Qt::Key_Enter, handler);
}

View file

@ -1,31 +0,0 @@
/**
* @file table_activation.h
* @brief Row activation for tables that must not navigate on a single click.
*/
#ifndef TABLE_ACTIVATION_H
#define TABLE_ACTIVATION_H
#include <functional>
class QModelIndex;
class QObject;
class QTableWidget;
/**
* @brief Call @p handler on double-click or Enter, never on a single click.
*
* QAbstractItemView::activated fires on a single click on platforms where
* SH_ItemView_ActivateItemOnSingleClick is set, so navigation actions must not
* use it. This connects doubleClicked and installs Return/Enter shortcuts that
* forward the current index.
*
* @param table The table whose rows activate.
* @param context Object that owns the connections; the handler is disconnected
* with it.
* @param handler Receives the activated row's index, which may be invalid.
*/
void connectTableActivation(QTableWidget *table, QObject *context,
const std::function<void(const QModelIndex &)> &handler);
#endif // TABLE_ACTIVATION_H