mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-28 00:42:19 -07:00
[UserList] Use an enum for the list sections
The section identifiers were stringly-typed: eleven hardcoded
QStringLiteral comparisons scattered through user_list_widget.cpp, and
the display path (sectionTitle) maps every id through tr() anyway, so
the raw strings were never shown. A typo compiled fine and silently
broke a section.
- enum class Section { Buddy, Online, Ignore } replaces the section
strings across the sectioned-list API (setSectioned, getSectionIds,
setSectionExpanded, the sectionExpanded signal and all membership
helpers), giving compile-time checks at every call site.
- sectionTitle becomes a switch over the enum and the dead raw-string
fallback is gone.
- The expanded-section state persists the same stable keys via the
panel widget boundary, so existing settings files survive unchanged.
- The divider reverse lookup in handleSectionExpansion no longer relies
on an empty-string sentinel from QMap::key; it scans the three
dividers and bails when the item is not one of them.
Took 12 minutes
# Commit time for manual adjustment:
# Took 2 minutes
This commit is contained in:
parent
829f56ccf0
commit
d400af5bc0
4 changed files with 126 additions and 95 deletions
|
|
@ -9,6 +9,24 @@
|
||||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||||
#include <libcockatrice/settings/interface_settings.h>
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// The persisted section keys are the serialization contract with the user's
|
||||||
|
// settings file, so the values must stay stable across versions.
|
||||||
|
QString sectionKey(UserListWidget::Section section)
|
||||||
|
{
|
||||||
|
switch (section) {
|
||||||
|
case UserListWidget::Section::Buddy:
|
||||||
|
return QStringLiteral("buddy");
|
||||||
|
case UserListWidget::Section::Online:
|
||||||
|
return QStringLiteral("online");
|
||||||
|
case UserListWidget::Section::Ignore:
|
||||||
|
return QStringLiteral("ignore");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
UserListPanelWidget::UserListPanelWidget(TabSupervisor *_tabSupervisor, AbstractClient *_client, QWidget *parent)
|
UserListPanelWidget::UserListPanelWidget(TabSupervisor *_tabSupervisor, AbstractClient *_client, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +39,8 @@ UserListPanelWidget::UserListPanelWidget(TabSupervisor *_tabSupervisor, Abstract
|
||||||
mainLayout->addWidget(searchBar);
|
mainLayout->addWidget(searchBar);
|
||||||
|
|
||||||
userList = new UserListWidget(_tabSupervisor, _client, UserListWidget::RoomList, this);
|
userList = new UserListWidget(_tabSupervisor, _client, UserListWidget::RoomList, this);
|
||||||
userList->setSectioned({QStringLiteral("buddy"), QStringLiteral("online"), QStringLiteral("ignore")});
|
userList->setSectioned(
|
||||||
|
{UserListWidget::Section::Buddy, UserListWidget::Section::Online, UserListWidget::Section::Ignore});
|
||||||
mainLayout->addWidget(userList, 1);
|
mainLayout->addWidget(userList, 1);
|
||||||
|
|
||||||
connect(searchBar, &QLineEdit::textChanged, userList, &UserListWidget::setFilterText);
|
connect(searchBar, &QLineEdit::textChanged, userList, &UserListWidget::setFilterText);
|
||||||
|
|
@ -31,8 +50,8 @@ UserListPanelWidget::UserListPanelWidget(TabSupervisor *_tabSupervisor, Abstract
|
||||||
|
|
||||||
// Restore the persisted expansion state, then apply it to the tree.
|
// Restore the persisted expansion state, then apply it to the tree.
|
||||||
const QStringList expandedSections = SettingsCache::instance().userInterface().getUserListExpandedSections();
|
const QStringList expandedSections = SettingsCache::instance().userInterface().getUserListExpandedSections();
|
||||||
for (const QString §ionId : userList->getSectionIds()) {
|
for (const UserListWidget::Section section : userList->getSectionIds()) {
|
||||||
userList->setSectionExpanded(sectionId, expandedSections.contains(sectionId));
|
userList->setSectionExpanded(section, expandedSections.contains(sectionKey(section)));
|
||||||
}
|
}
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
@ -43,15 +62,16 @@ void UserListPanelWidget::bind(UserListManager *manager)
|
||||||
userList->bind(manager);
|
userList->bind(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListPanelWidget::persistExpandedSections(const QString §ionId, bool expanded)
|
void UserListPanelWidget::persistExpandedSections(UserListWidget::Section section, bool expanded)
|
||||||
{
|
{
|
||||||
|
const QString key = sectionKey(section);
|
||||||
QStringList expandedSections = SettingsCache::instance().userInterface().getUserListExpandedSections();
|
QStringList expandedSections = SettingsCache::instance().userInterface().getUserListExpandedSections();
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
if (!expandedSections.contains(sectionId)) {
|
if (!expandedSections.contains(key)) {
|
||||||
expandedSections.append(sectionId);
|
expandedSections.append(key);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
expandedSections.removeAll(sectionId);
|
expandedSections.removeAll(key);
|
||||||
}
|
}
|
||||||
SettingsCache::instance().userInterface().setUserListExpandedSections(expandedSections);
|
SettingsCache::instance().userInterface().setUserListExpandedSections(expandedSections);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@
|
||||||
#ifndef COCKATRICE_USER_LIST_PANEL_WIDGET_H
|
#ifndef COCKATRICE_USER_LIST_PANEL_WIDGET_H
|
||||||
#define COCKATRICE_USER_LIST_PANEL_WIDGET_H
|
#define COCKATRICE_USER_LIST_PANEL_WIDGET_H
|
||||||
|
|
||||||
|
#include "user_list_widget.h"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class AbstractClient;
|
class AbstractClient;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class TabSupervisor;
|
class TabSupervisor;
|
||||||
class UserListManager;
|
class UserListManager;
|
||||||
class UserListWidget;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A unified user list: a search bar above a single tree whose section headers
|
* A unified user list: a search bar above a single tree whose section headers
|
||||||
|
|
@ -33,7 +34,7 @@ signals:
|
||||||
void openMessageDialog(const QString &userName, bool focus);
|
void openMessageDialog(const QString &userName, bool focus);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void persistExpandedSections(const QString §ionId, bool expanded);
|
void persistExpandedSections(UserListWidget::Section section, bool expanded);
|
||||||
|
|
||||||
QLineEdit *searchBar = nullptr;
|
QLineEdit *searchBar = nullptr;
|
||||||
UserListWidget *userList = nullptr;
|
UserListWidget *userList = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -805,13 +805,13 @@ void UserListWidget::bind(UserListManager *mgr)
|
||||||
connect(manager, &UserListManager::userLeftOnline, this,
|
connect(manager, &UserListManager::userLeftOnline, this,
|
||||||
[this](const QString &name) { handleOnlineChangeLeft(name); });
|
[this](const QString &name) { handleOnlineChangeLeft(name); });
|
||||||
connect(manager, &UserListManager::addedToBuddyList, this,
|
connect(manager, &UserListManager::addedToBuddyList, this,
|
||||||
[this](const ServerInfo_User &user) { handleListAdd(QStringLiteral("buddy"), user); });
|
[this](const ServerInfo_User &user) { handleListAdd(Section::Buddy, user); });
|
||||||
connect(manager, &UserListManager::removedFromBuddyList, this,
|
connect(manager, &UserListManager::removedFromBuddyList, this,
|
||||||
[this](const QString &name) { handleListRemove(QStringLiteral("buddy"), name); });
|
[this](const QString &name) { handleListRemove(Section::Buddy, name); });
|
||||||
connect(manager, &UserListManager::addedToIgnoreList, this,
|
connect(manager, &UserListManager::addedToIgnoreList, this,
|
||||||
[this](const ServerInfo_User &user) { handleListAdd(QStringLiteral("ignore"), user); });
|
[this](const ServerInfo_User &user) { handleListAdd(Section::Ignore, user); });
|
||||||
connect(manager, &UserListManager::removedFromIgnoreList, this,
|
connect(manager, &UserListManager::removedFromIgnoreList, this,
|
||||||
[this](const QString &name) { handleListRemove(QStringLiteral("ignore"), name); });
|
[this](const QString &name) { handleListRemove(Section::Ignore, name); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Popup button refresh ──────────────────────────────────────────────────
|
// ── Popup button refresh ──────────────────────────────────────────────────
|
||||||
|
|
@ -1201,8 +1201,8 @@ void UserListWidget::requestAvatarsForVisibleItems()
|
||||||
{
|
{
|
||||||
if (sectioned) {
|
if (sectioned) {
|
||||||
// Top level items are dividers, user rows hang below them.
|
// Top level items are dividers, user rows hang below them.
|
||||||
for (const QString §ionId : sectionIds) {
|
for (const Section section : sectionIds) {
|
||||||
QTreeWidgetItem *divider = sectionItems.value(sectionId);
|
QTreeWidgetItem *divider = sectionItems.value(section);
|
||||||
if (!divider) {
|
if (!divider) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1247,15 +1247,15 @@ void UserListWidget::rebuild()
|
||||||
beginBulkLoad();
|
beginBulkLoad();
|
||||||
const auto &onlineUsers = manager->getAllUsersList();
|
const auto &onlineUsers = manager->getAllUsersList();
|
||||||
for (auto it = onlineUsers.cbegin(); it != onlineUsers.cend(); ++it) {
|
for (auto it = onlineUsers.cbegin(); it != onlineUsers.cend(); ++it) {
|
||||||
processUserInfo(QStringLiteral("online"), it.value(), true);
|
processUserInfo(Section::Online, it.value(), true);
|
||||||
}
|
}
|
||||||
const auto &buddyUsers = manager->getBuddyList();
|
const auto &buddyUsers = manager->getBuddyList();
|
||||||
for (auto it = buddyUsers.cbegin(); it != buddyUsers.cend(); ++it) {
|
for (auto it = buddyUsers.cbegin(); it != buddyUsers.cend(); ++it) {
|
||||||
processUserInfo(QStringLiteral("buddy"), it.value(), manager->getOnlineUser(it.key()) != nullptr);
|
processUserInfo(Section::Buddy, it.value(), manager->getOnlineUser(it.key()) != nullptr);
|
||||||
}
|
}
|
||||||
const auto &ignoreUsers = manager->getIgnoreList();
|
const auto &ignoreUsers = manager->getIgnoreList();
|
||||||
for (auto it = ignoreUsers.cbegin(); it != ignoreUsers.cend(); ++it) {
|
for (auto it = ignoreUsers.cbegin(); it != ignoreUsers.cend(); ++it) {
|
||||||
processUserInfo(QStringLiteral("ignore"), it.value(), manager->getOnlineUser(it.key()) != nullptr);
|
processUserInfo(Section::Ignore, it.value(), manager->getOnlineUser(it.key()) != nullptr);
|
||||||
}
|
}
|
||||||
endBulkLoad();
|
endBulkLoad();
|
||||||
applyFilter();
|
applyFilter();
|
||||||
|
|
@ -1334,9 +1334,9 @@ void UserListWidget::processUserInfo(const ServerInfo_User &user, bool online)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::processUserInfo(const QString §ionId, const ServerInfo_User &user, bool online)
|
void UserListWidget::processUserInfo(Section section, const ServerInfo_User &user, bool online)
|
||||||
{
|
{
|
||||||
ensureSectionMembership(sectionId, user, online);
|
ensureSectionMembership(section, user, online);
|
||||||
if (!bulkLoading) {
|
if (!bulkLoading) {
|
||||||
sortItems();
|
sortItems();
|
||||||
applyFilter();
|
applyFilter();
|
||||||
|
|
@ -1349,9 +1349,9 @@ bool UserListWidget::deleteUser(const QString &userName)
|
||||||
if (sectioned) {
|
if (sectioned) {
|
||||||
// The user may own several rows (one per section). Drop them all.
|
// The user may own several rows (one per section). Drop them all.
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
const QStringList sections = sectionUsers.keys(); // snapshot: maps mutate
|
const QList<Section> sections = sectionUsers.keys(); // snapshot: maps mutate
|
||||||
for (const QString §ionId : sections) {
|
for (const Section section : sections) {
|
||||||
removed = dropSectionMembership(sectionId, userName) || removed;
|
removed = dropSectionMembership(section, userName) || removed;
|
||||||
}
|
}
|
||||||
if (removed && !bulkLoading) {
|
if (removed && !bulkLoading) {
|
||||||
sortItems();
|
sortItems();
|
||||||
|
|
@ -1430,8 +1430,8 @@ void UserListWidget::updateCount()
|
||||||
if (sectioned) {
|
if (sectioned) {
|
||||||
// The dividers carry the section titles
|
// The dividers carry the section titles
|
||||||
setTitle(QString());
|
setTitle(QString());
|
||||||
for (const QString §ionId : sectionIds) {
|
for (const Section section : sectionIds) {
|
||||||
updateSectionDivider(sectionId);
|
updateSectionDivider(section);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1467,8 +1467,8 @@ void UserListWidget::applyFilter()
|
||||||
if (sectioned) {
|
if (sectioned) {
|
||||||
const bool searching = !filterText.isEmpty();
|
const bool searching = !filterText.isEmpty();
|
||||||
const QString lower = filterText.toLower();
|
const QString lower = filterText.toLower();
|
||||||
for (const QString §ionId : sectionIds) {
|
for (const Section section : sectionIds) {
|
||||||
QTreeWidgetItem *divider = sectionItems.value(sectionId);
|
QTreeWidgetItem *divider = sectionItems.value(section);
|
||||||
if (!divider) {
|
if (!divider) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1490,9 +1490,9 @@ void UserListWidget::applyFilter()
|
||||||
setExpandedProgrammatically(divider, visible > 0);
|
setExpandedProgrammatically(divider, visible > 0);
|
||||||
} else {
|
} else {
|
||||||
divider->setHidden(false);
|
divider->setHidden(false);
|
||||||
setExpandedProgrammatically(divider, expandedSections.contains(sectionId));
|
setExpandedProgrammatically(divider, expandedSections.contains(section));
|
||||||
}
|
}
|
||||||
updateSectionDivider(sectionId);
|
updateSectionDivider(section);
|
||||||
}
|
}
|
||||||
requestAvatarsForVisibleItems();
|
requestAvatarsForVisibleItems();
|
||||||
userTree->viewport()->update();
|
userTree->viewport()->update();
|
||||||
|
|
@ -1552,7 +1552,7 @@ void UserListWidget::sortItems()
|
||||||
|
|
||||||
// Sectioned mode
|
// Sectioned mode
|
||||||
|
|
||||||
void UserListWidget::setSectioned(const QStringList &ids)
|
void UserListWidget::setSectioned(const QList<Section> &ids)
|
||||||
{
|
{
|
||||||
if (sectioned || ids.isEmpty()) {
|
if (sectioned || ids.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1561,8 +1561,8 @@ void UserListWidget::setSectioned(const QStringList &ids)
|
||||||
sectioned = true;
|
sectioned = true;
|
||||||
sectionIds = ids;
|
sectionIds = ids;
|
||||||
expandedSections.clear();
|
expandedSections.clear();
|
||||||
for (const QString §ionId : sectionIds) {
|
for (const Section section : sectionIds) {
|
||||||
expandedSections.insert(sectionId); // everything starts expanded
|
expandedSections.insert(section); // everything starts expanded
|
||||||
}
|
}
|
||||||
|
|
||||||
// The single tree owns scrolling and the dividers carry the section titles,
|
// The single tree owns scrolling and the dividers carry the section titles,
|
||||||
|
|
@ -1587,16 +1587,16 @@ void UserListWidget::createSectionItems()
|
||||||
{
|
{
|
||||||
sectionItems.clear();
|
sectionItems.clear();
|
||||||
QSignalBlocker blocker(userTree); // no expansion signals while building
|
QSignalBlocker blocker(userTree); // no expansion signals while building
|
||||||
for (const QString §ionId : sectionIds) {
|
for (const Section section : sectionIds) {
|
||||||
QTreeWidgetItem *divider = createSectionItem(sectionId);
|
QTreeWidgetItem *divider = createSectionItem(section);
|
||||||
sectionItems.insert(sectionId, divider);
|
sectionItems.insert(section, divider);
|
||||||
divider->setExpanded(expandedSections.contains(sectionId));
|
divider->setExpanded(expandedSections.contains(section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QTreeWidgetItem *UserListWidget::createSectionItem(const QString §ionId)
|
QTreeWidgetItem *UserListWidget::createSectionItem(Section section)
|
||||||
{
|
{
|
||||||
Q_UNUSED(sectionId);
|
Q_UNUSED(section);
|
||||||
auto *divider = new QTreeWidgetItem(SectionItemType);
|
auto *divider = new QTreeWidgetItem(SectionItemType);
|
||||||
// Selectable so keyboard navigation (Up/Down) can land on the dividers.
|
// Selectable so keyboard navigation (Up/Down) can land on the dividers.
|
||||||
// They act as collapsible section headers once they have focus.
|
// They act as collapsible section headers once they have focus.
|
||||||
|
|
@ -1618,23 +1618,22 @@ QTreeWidgetItem *UserListWidget::createSectionItem(const QString §ionId)
|
||||||
return divider;
|
return divider;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString UserListWidget::sectionTitle(const QString §ionId) const
|
QString UserListWidget::sectionTitle(Section section) const
|
||||||
{
|
{
|
||||||
if (sectionId == QLatin1String("buddy")) {
|
switch (section) {
|
||||||
return tr("Buddies");
|
case Section::Buddy:
|
||||||
|
return tr("Buddies");
|
||||||
|
case Section::Online:
|
||||||
|
return tr("Online");
|
||||||
|
case Section::Ignore:
|
||||||
|
return tr("Ignored");
|
||||||
}
|
}
|
||||||
if (sectionId == QLatin1String("online")) {
|
return {};
|
||||||
return tr("Online");
|
|
||||||
}
|
|
||||||
if (sectionId == QLatin1String("ignore")) {
|
|
||||||
return tr("Ignored");
|
|
||||||
}
|
|
||||||
return sectionId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::updateSectionDivider(const QString §ionId)
|
void UserListWidget::updateSectionDivider(Section section)
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *divider = sectionItems.value(sectionId);
|
QTreeWidgetItem *divider = sectionItems.value(section);
|
||||||
if (!divider) {
|
if (!divider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1647,7 +1646,7 @@ void UserListWidget::updateSectionDivider(const QString §ionId)
|
||||||
// The tree draws no branches (rows are flush), so the divider carries its
|
// The tree draws no branches (rows are flush), so the divider carries its
|
||||||
// own collapse arrow glyph.
|
// own collapse arrow glyph.
|
||||||
const QString arrow = divider->isExpanded() ? QStringLiteral("\u25BE") : QStringLiteral("\u25B8");
|
const QString arrow = divider->isExpanded() ? QStringLiteral("\u25BE") : QStringLiteral("\u25B8");
|
||||||
divider->setText(0, tr("%1 %2 (%3)").arg(arrow, sectionTitle(sectionId)).arg(visible));
|
divider->setText(0, tr("%1 %2 (%3)").arg(arrow, sectionTitle(section)).arg(visible));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::handleSectionExpansion(QTreeWidgetItem *item, bool expanded)
|
void UserListWidget::handleSectionExpansion(QTreeWidgetItem *item, bool expanded)
|
||||||
|
|
@ -1655,17 +1654,23 @@ void UserListWidget::handleSectionExpansion(QTreeWidgetItem *item, bool expanded
|
||||||
if (!sectioned || item->type() != SectionItemType) {
|
if (!sectioned || item->type() != SectionItemType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QString sectionId = sectionItems.key(item);
|
// Reverse lookup. Only three dividers exist, so a linear scan over the
|
||||||
if (sectionId.isEmpty()) {
|
// section map is cheaper than caching the section on each divider.
|
||||||
|
auto dividerIt = sectionItems.constBegin();
|
||||||
|
while (dividerIt != sectionItems.constEnd() && dividerIt.value() != item) {
|
||||||
|
++dividerIt;
|
||||||
|
}
|
||||||
|
if (dividerIt == sectionItems.constEnd()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const Section section = dividerIt.key();
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
expandedSections.insert(sectionId);
|
expandedSections.insert(section);
|
||||||
} else {
|
} else {
|
||||||
expandedSections.remove(sectionId);
|
expandedSections.remove(section);
|
||||||
}
|
}
|
||||||
updateSectionDivider(sectionId); // the arrow glyph follows the state
|
updateSectionDivider(section); // the arrow glyph follows the state
|
||||||
emit sectionExpanded(sectionId, expanded);
|
emit sectionExpanded(section, expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::setExpandedProgrammatically(QTreeWidgetItem *item, bool expanded)
|
void UserListWidget::setExpandedProgrammatically(QTreeWidgetItem *item, bool expanded)
|
||||||
|
|
@ -1674,23 +1679,23 @@ void UserListWidget::setExpandedProgrammatically(QTreeWidgetItem *item, bool exp
|
||||||
item->setExpanded(expanded);
|
item->setExpanded(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::setSectionExpanded(const QString §ionId, bool expanded)
|
void UserListWidget::setSectionExpanded(Section section, bool expanded)
|
||||||
{
|
{
|
||||||
if (!sectioned) {
|
if (!sectioned) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (expanded) {
|
if (expanded) {
|
||||||
expandedSections.insert(sectionId);
|
expandedSections.insert(section);
|
||||||
} else {
|
} else {
|
||||||
expandedSections.remove(sectionId);
|
expandedSections.remove(section);
|
||||||
}
|
}
|
||||||
QTreeWidgetItem *divider = sectionItems.value(sectionId);
|
QTreeWidgetItem *divider = sectionItems.value(section);
|
||||||
if (!divider) {
|
if (!divider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QSignalBlocker blocker(userTree);
|
QSignalBlocker blocker(userTree);
|
||||||
divider->setExpanded(expanded);
|
divider->setExpanded(expanded);
|
||||||
updateSectionDivider(sectionId); // the arrow glyph follows the state
|
updateSectionDivider(section); // the arrow glyph follows the state
|
||||||
userTree->viewport()->update();
|
userTree->viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1699,12 +1704,12 @@ void UserListWidget::handleOnlineChange(const ServerInfo_User &user)
|
||||||
// A user came online: they get a row in the "Online" section, plus (if
|
// A user came online: they get a row in the "Online" section, plus (if
|
||||||
// applicable) a row in the buddy/ignore sections, which flip to online.
|
// applicable) a row in the buddy/ignore sections, which flip to online.
|
||||||
const QString name = QString::fromStdString(user.name());
|
const QString name = QString::fromStdString(user.name());
|
||||||
ensureSectionMembership(QStringLiteral("online"), user, true);
|
ensureSectionMembership(Section::Online, user, true);
|
||||||
if (manager->isUserBuddy(name)) {
|
if (manager->isUserBuddy(name)) {
|
||||||
ensureSectionMembership(QStringLiteral("buddy"), user, true);
|
ensureSectionMembership(Section::Buddy, user, true);
|
||||||
}
|
}
|
||||||
if (manager->isUserIgnored(name)) {
|
if (manager->isUserIgnored(name)) {
|
||||||
ensureSectionMembership(QStringLiteral("ignore"), user, true);
|
ensureSectionMembership(Section::Ignore, user, true);
|
||||||
}
|
}
|
||||||
finishSectionedMutation();
|
finishSectionedMutation();
|
||||||
}
|
}
|
||||||
|
|
@ -1714,7 +1719,7 @@ void UserListWidget::handleOnlineChangeLeft(const QString &userName)
|
||||||
// The user is no longer online: their "Online" row disappears. Buddies and
|
// The user is no longer online: their "Online" row disappears. Buddies and
|
||||||
// ignored users keep their own section's row, marked offline. A plain user
|
// ignored users keep their own section's row, marked offline. A plain user
|
||||||
// has no rows left.
|
// has no rows left.
|
||||||
const bool dropped = dropSectionMembership(QStringLiteral("online"), userName);
|
const bool dropped = dropSectionMembership(Section::Online, userName);
|
||||||
const bool kept = manager->isUserBuddy(userName) || manager->isUserIgnored(userName);
|
const bool kept = manager->isUserBuddy(userName) || manager->isUserIgnored(userName);
|
||||||
if (kept) {
|
if (kept) {
|
||||||
setUserOnline(userName, false);
|
setUserOnline(userName, false);
|
||||||
|
|
@ -1724,40 +1729,40 @@ void UserListWidget::handleOnlineChangeLeft(const QString &userName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::handleListAdd(const QString §ionId, const ServerInfo_User &user)
|
void UserListWidget::handleListAdd(Section section, const ServerInfo_User &user)
|
||||||
{
|
{
|
||||||
const QString name = QString::fromStdString(user.name());
|
const QString name = QString::fromStdString(user.name());
|
||||||
const bool online = manager->getOnlineUser(name) != nullptr;
|
const bool online = manager->getOnlineUser(name) != nullptr;
|
||||||
ensureSectionMembership(sectionId, user, online);
|
ensureSectionMembership(section, user, online);
|
||||||
if (online) {
|
if (online) {
|
||||||
// The user belongs to the "Online" section as well. Make sure the row
|
// The user belongs to the "Online" section as well. Make sure the row
|
||||||
// exists even if the join event raced ahead of the list mutation.
|
// exists even if the join event raced ahead of the list mutation.
|
||||||
ensureSectionMembership(QStringLiteral("online"), user, true);
|
ensureSectionMembership(Section::Online, user, true);
|
||||||
}
|
}
|
||||||
finishSectionedMutation();
|
finishSectionedMutation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListWidget::handleListRemove(const QString §ionId, const QString &userName)
|
void UserListWidget::handleListRemove(Section section, const QString &userName)
|
||||||
{
|
{
|
||||||
// Only the row of the removed section disappears: an online user keeps
|
// Only the row of the removed section disappears: an online user keeps
|
||||||
// their "Online" row, and other list memberships keep theirs.
|
// their "Online" row, and other list memberships keep theirs.
|
||||||
if (dropSectionMembership(sectionId, userName)) {
|
if (dropSectionMembership(section, userName)) {
|
||||||
finishSectionedMutation();
|
finishSectionedMutation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UserListTWI *UserListWidget::ensureSectionMembership(const QString §ionId, const ServerInfo_User &user, bool online)
|
UserListTWI *UserListWidget::ensureSectionMembership(Section section, const ServerInfo_User &user, bool online)
|
||||||
{
|
{
|
||||||
const QString userName = QString::fromStdString(user.name());
|
const QString userName = QString::fromStdString(user.name());
|
||||||
|
|
||||||
updateCardArtParams(user, userName);
|
updateCardArtParams(user, userName);
|
||||||
|
|
||||||
QTreeWidgetItem *divider = sectionItems.value(sectionId);
|
QTreeWidgetItem *divider = sectionItems.value(section);
|
||||||
if (!divider) {
|
if (!divider) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, UserListTWI *> §ionMap = sectionUsers[sectionId];
|
QMap<QString, UserListTWI *> §ionMap = sectionUsers[section];
|
||||||
UserListTWI *item = sectionMap.value(userName);
|
UserListTWI *item = sectionMap.value(userName);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
item = new UserListTWI(user);
|
item = new UserListTWI(user);
|
||||||
|
|
@ -1781,9 +1786,9 @@ UserListTWI *UserListWidget::ensureSectionMembership(const QString §ionId, c
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UserListWidget::dropSectionMembership(const QString §ionId, const QString &userName)
|
bool UserListWidget::dropSectionMembership(Section section, const QString &userName)
|
||||||
{
|
{
|
||||||
QMap<QString, UserListTWI *> §ionMap = sectionUsers[sectionId];
|
QMap<QString, UserListTWI *> §ionMap = sectionUsers[section];
|
||||||
UserListTWI *item = sectionMap.take(userName);
|
UserListTWI *item = sectionMap.take(userName);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStringList>
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
|
@ -150,6 +149,12 @@ public:
|
||||||
BuddyList,
|
BuddyList,
|
||||||
IgnoreList
|
IgnoreList
|
||||||
};
|
};
|
||||||
|
enum class Section
|
||||||
|
{
|
||||||
|
Buddy,
|
||||||
|
Online,
|
||||||
|
Ignore
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UserListManager *manager = nullptr;
|
UserListManager *manager = nullptr;
|
||||||
|
|
@ -181,31 +186,31 @@ private:
|
||||||
|
|
||||||
// Sectioned mode (single tree with inline dividers)
|
// Sectioned mode (single tree with inline dividers)
|
||||||
bool sectioned = false;
|
bool sectioned = false;
|
||||||
QStringList sectionIds;
|
QList<Section> sectionIds;
|
||||||
QMap<QString, QTreeWidgetItem *> sectionItems;
|
QMap<Section, QTreeWidgetItem *> sectionItems;
|
||||||
// One row per (section, user): a user that is online AND a buddy appears in
|
// One row per (section, user): a user that is online AND a buddy appears in
|
||||||
// both the "Online" and the "Buddies" sections, so the same user can own
|
// both the "Online" and the "Buddies" sections, so the same user can own
|
||||||
// several rows, each hanging off its section's divider.
|
// several rows, each hanging off its section's divider.
|
||||||
QMap<QString, QMap<QString, UserListTWI *>> sectionUsers;
|
QMap<Section, QMap<QString, UserListTWI *>> sectionUsers;
|
||||||
QSet<QString> expandedSections;
|
QSet<Section> expandedSections;
|
||||||
void createSectionItems();
|
void createSectionItems();
|
||||||
QTreeWidgetItem *createSectionItem(const QString §ionId);
|
QTreeWidgetItem *createSectionItem(Section section);
|
||||||
[[nodiscard]] QString sectionTitle(const QString §ionId) const;
|
[[nodiscard]] QString sectionTitle(Section section) const;
|
||||||
void updateSectionDivider(const QString §ionId);
|
void updateSectionDivider(Section section);
|
||||||
void handleSectionExpansion(QTreeWidgetItem *item, bool expanded);
|
void handleSectionExpansion(QTreeWidgetItem *item, bool expanded);
|
||||||
void setExpandedProgrammatically(QTreeWidgetItem *item, bool expanded);
|
void setExpandedProgrammatically(QTreeWidgetItem *item, bool expanded);
|
||||||
void handleOnlineChange(const ServerInfo_User &user);
|
void handleOnlineChange(const ServerInfo_User &user);
|
||||||
void handleOnlineChangeLeft(const QString &userName);
|
void handleOnlineChangeLeft(const QString &userName);
|
||||||
void handleListAdd(const QString §ionId, const ServerInfo_User &user);
|
void handleListAdd(Section section, const ServerInfo_User &user);
|
||||||
void handleListRemove(const QString §ionId, const QString &userName);
|
void handleListRemove(Section section, const QString &userName);
|
||||||
/** Creates or updates the row for @p user in @p sectionId. */
|
/** Creates or updates the row for @p user in @p section. */
|
||||||
UserListTWI *ensureSectionMembership(const QString §ionId, const ServerInfo_User &user, bool online);
|
UserListTWI *ensureSectionMembership(Section section, const ServerInfo_User &user, bool online);
|
||||||
/** Removes and deletes the row for @p userName in @p sectionId. */
|
/** Removes and deletes the row for @p userName in @p section. */
|
||||||
bool dropSectionMembership(const QString §ionId, const QString &userName);
|
bool dropSectionMembership(Section section, const QString &userName);
|
||||||
/** Sorts, refilters and repaints after a sectioned mode mutation. */
|
/** Sorts, refilters and repaints after a sectioned mode mutation. */
|
||||||
void finishSectionedMutation();
|
void finishSectionedMutation();
|
||||||
void updateCardArtParams(const ServerInfo_User &user, const QString &userName);
|
void updateCardArtParams(const ServerInfo_User &user, const QString &userName);
|
||||||
void processUserInfo(const QString §ionId, const ServerInfo_User &user, bool online);
|
void processUserInfo(Section section, const ServerInfo_User &user, bool online);
|
||||||
|
|
||||||
QMap<QString, UserListTWI *> users;
|
QMap<QString, UserListTWI *> users;
|
||||||
TabSupervisor *tabSupervisor;
|
TabSupervisor *tabSupervisor;
|
||||||
|
|
@ -231,7 +236,7 @@ signals:
|
||||||
void addIgnore(const QString &userName);
|
void addIgnore(const QString &userName);
|
||||||
void removeIgnore(const QString &userName);
|
void removeIgnore(const QString &userName);
|
||||||
void joinGameRequested(int gameId, int roomId, bool asSpectator);
|
void joinGameRequested(int gameId, int roomId, bool asSpectator);
|
||||||
void sectionExpanded(const QString §ionId, bool expanded);
|
void sectionExpanded(Section section, bool expanded);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UserListWidget(TabSupervisor *_tabSupervisor,
|
UserListWidget(TabSupervisor *_tabSupervisor,
|
||||||
|
|
@ -251,9 +256,9 @@ public:
|
||||||
void setUserOnline(const QString &userName, bool online);
|
void setUserOnline(const QString &userName, bool online);
|
||||||
void setFilterText(const QString &text);
|
void setFilterText(const QString &text);
|
||||||
void setShowTitle(bool showTitle);
|
void setShowTitle(bool showTitle);
|
||||||
void setSectioned(const QStringList &ids);
|
void setSectioned(const QList<Section> &ids);
|
||||||
void setSectionExpanded(const QString §ionId, bool expanded);
|
void setSectionExpanded(Section section, bool expanded);
|
||||||
[[nodiscard]] const QStringList &getSectionIds() const
|
[[nodiscard]] const QList<Section> &getSectionIds() const
|
||||||
{
|
{
|
||||||
return sectionIds;
|
return sectionIds;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue