From 08e6c51e9001d031477db0550bc2ca0a41dea1bf Mon Sep 17 00:00:00 2001 From: ericek111 Date: Wed, 19 Aug 2026 19:50:03 +0000 Subject: [PATCH] Leave a talking client's name alone, and rename from the whole row Bolding the name of whoever is speaking re-measures the row while the label keeps its old width, so a nickname spent every utterance clipped to an ellipsis. Talking already shows in the client's icon, which is where TeamSpeak shows it too, so the name keeps its normal weight and colour. Renaming now starts from the tree's own double-click handling, which works a row by its whole line, instead of Swing's, which only sees clicks that land on the label. Co-Authored-By: Claude Opus 5 --- .../com/ts3client/ui/NicknameCellEditor.java | 16 ++++------------ .../com/ts3client/ui/ServerTreeCellRenderer.java | 7 +++++-- .../java/com/ts3client/ui/ServerTreePanel.java | 8 ++++++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ts3-client/swing/src/main/java/com/ts3client/ui/NicknameCellEditor.java b/ts3-client/swing/src/main/java/com/ts3client/ui/NicknameCellEditor.java index 66bca82..789fd57 100644 --- a/ts3-client/swing/src/main/java/com/ts3client/ui/NicknameCellEditor.java +++ b/ts3-client/swing/src/main/java/com/ts3client/ui/NicknameCellEditor.java @@ -54,15 +54,13 @@ final class NicknameCellEditor extends DefaultTreeCellEditor { } /** - * Starts on a plain double click, rather than the click-pause-click (and its timer) - * that a file browser renames with — the tree's other double clicks act at once too. + * Editing is started by the tree's own double-click handling, which works a row by + * its whole line; Swing's would only see clicks that land on the label, and its + * click-pause-click timer would rename on clicks meant as a selection. */ @Override public boolean isCellEditable(EventObject event) { - if (!(event instanceof MouseEvent)) return false; - MouseEvent e = (MouseEvent) event; - if (e.getClickCount() != 2 || !SwingUtilities.isLeftMouseButton(e)) return false; - return editsPath(tree.getPathForRow(rowAt(e))); + return !(event instanceof MouseEvent); } @Override @@ -109,12 +107,6 @@ final class NicknameCellEditor extends DefaultTreeCellEditor { return text == null ? "" : text.trim(); } - private int rowAt(MouseEvent e) { - return tree instanceof DropIndicatorTree - ? ((DropIndicatorTree) tree).rowAt(e.getY()) - : tree.getRowForLocation(e.getX(), e.getY()); - } - private static ClientEntry clientOf(TreePath path) { return path == null ? null : clientOf(path.getLastPathComponent()); } diff --git a/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreeCellRenderer.java b/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreeCellRenderer.java index c89b0a6..c1fc4e8 100644 --- a/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreeCellRenderer.java +++ b/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreeCellRenderer.java @@ -45,8 +45,11 @@ final class ServerTreeCellRenderer extends DefaultTreeCellRenderer { if (cl.away && !cl.awayMessage.isEmpty()) label += " [" + cl.awayMessage + "]"; setText(label); setIcon(iconFor(cl)); - setForeground(cl.talking ? Theme.TALKING : Theme.TREE_TEXT); - setFont(cl.talking ? Theme.UI_BOLD : Theme.UI_FONT); + // Talking shows in the client's icon, as it does in TeamSpeak. Marking the + // name as well would also re-measure the row mid-speech, which leaves the + // nickname clipped to an ellipsis for as long as it lasts. + setForeground(Theme.TREE_TEXT); + setFont(Theme.UI_FONT); } else { // root / server setText(String.valueOf(obj)); diff --git a/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreePanel.java b/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreePanel.java index ae48399..40463f2 100644 --- a/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreePanel.java +++ b/ts3-client/swing/src/main/java/com/ts3client/ui/ServerTreePanel.java @@ -200,8 +200,12 @@ public final class ServerTreePanel extends JScrollPane { if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) { if (obj instanceof ChannelNode && !Spacers.isSpacer(((ChannelNode) obj).name)) { actions.joinChannel(((ChannelNode) obj).id); - } else if (obj instanceof ClientEntry && ((ClientEntry) obj).id != selfClientId) { - actions.openPrivateChat((ClientEntry) obj); + } else if (obj instanceof ClientEntry) { + if (((ClientEntry) obj).id == selfClientId) { + tree.startEditingAtPath(tree.pathAt(e.getY())); + } else { + actions.openPrivateChat((ClientEntry) obj); + } } } else if (SwingUtilities.isMiddleMouseButton(e) && obj instanceof ClientEntry) { actions.showConnectionInfo((ClientEntry) obj);