Show each channel's own icon in the tree

Channels carry a channel_icon_id just like groups do; track it on
ChannelNode from the channel list and the create/edit events, and paint it
in the same right-aligned strip that already carries a client's group
icons. Spacers keep their bare look.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 07:09:21 +00:00
parent 7c86a1f166
commit 610dce1bd9
3 changed files with 38 additions and 18 deletions

View File

@@ -375,10 +375,10 @@ public final class ServerTreePanel extends JScrollPane {
private static final int BADGE_MARGIN = 4;
/**
* Paints every visible client's group icons flush with the right edge of the
* viewport, the way TeamSpeak lines them up. Drawing them here rather than in the
* cell renderer keeps the rows' measured widths (and thus the selection highlight)
* tied to the label alone.
* Paints the icons of every visible row — a client's group icons, a channel's own
* icon — flush with the right edge of the viewport, the way TeamSpeak lines them up.
* Drawing them here rather than in the cell renderer keeps the rows' measured widths
* (and thus the selection highlight) tied to the label alone.
*/
private void paintBadges(Graphics g, JTree tree) {
Rectangle visible = tree.getVisibleRect();
@@ -390,11 +390,7 @@ public final class ServerTreePanel extends JScrollPane {
TreePath path = tree.getPathForRow(row);
Object obj = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
if (!(obj instanceof ClientEntry)) continue;
ClientEntry cl = (ClientEntry) obj;
List<Icon> icons = groupIcons.iconsOf(
model.serverGroupsOf(cl.serverGroupIds), model.channelGroup(cl.channelGroupId));
List<Icon> icons = badgesOf(obj);
if (icons.isEmpty()) continue;
GroupIcons.Row strip = new GroupIcons.Row(icons);
@@ -403,6 +399,21 @@ public final class ServerTreePanel extends JScrollPane {
}
}
/** The icon strip a row shows on its right, empty when it has none (yet). */
private List<Icon> badgesOf(Object node) {
if (node instanceof ClientEntry) {
ClientEntry cl = (ClientEntry) node;
return groupIcons.iconsOf(
model.serverGroupsOf(cl.serverGroupIds), model.channelGroup(cl.channelGroupId));
}
if (node instanceof ChannelNode) {
ChannelNode ch = (ChannelNode) node;
Icon icon = Spacers.isSpacer(ch.name) ? null : groupIcons.icon(ch.iconId);
if (icon != null) return List.of(icon);
}
return List.of();
}
/**
* Draws where the drop will land: an insertion line between rows, or an outline
* around the row that will receive the dragged node.
@@ -564,10 +575,7 @@ public final class ServerTreePanel extends JScrollPane {
} else if (obj instanceof ClientEntry) {
ClientEntry cl = (ClientEntry) obj;
String label = cl.nickname;
boolean hasIcons = !groupIcons.iconsOf(
model.serverGroupsOf(cl.serverGroupIds),
model.channelGroup(cl.channelGroupId)).isEmpty();
if (!hasIcons) {
if (badgesOf(cl).isEmpty()) {
// No icons (yet): fall back to naming the primary group inline.
String primaryGroup = model.primaryServerGroupName(cl.serverGroupIds);
if (primaryGroup != null) label += " [" + primaryGroup + "]";