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 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 19:50:03 +00:00
parent acd438dd14
commit 08e6c51e90
3 changed files with 15 additions and 16 deletions

View File

@@ -54,15 +54,13 @@ final class NicknameCellEditor extends DefaultTreeCellEditor {
} }
/** /**
* Starts on a plain double click, rather than the click-pause-click (and its timer) * Editing is started by the tree's own double-click handling, which works a row by
* that a file browser renames with — the tree's other double clicks act at once too. * 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 @Override
public boolean isCellEditable(EventObject event) { public boolean isCellEditable(EventObject event) {
if (!(event instanceof MouseEvent)) return false; return !(event instanceof MouseEvent);
MouseEvent e = (MouseEvent) event;
if (e.getClickCount() != 2 || !SwingUtilities.isLeftMouseButton(e)) return false;
return editsPath(tree.getPathForRow(rowAt(e)));
} }
@Override @Override
@@ -109,12 +107,6 @@ final class NicknameCellEditor extends DefaultTreeCellEditor {
return text == null ? "" : text.trim(); 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) { private static ClientEntry clientOf(TreePath path) {
return path == null ? null : clientOf(path.getLastPathComponent()); return path == null ? null : clientOf(path.getLastPathComponent());
} }

View File

@@ -45,8 +45,11 @@ final class ServerTreeCellRenderer extends DefaultTreeCellRenderer {
if (cl.away && !cl.awayMessage.isEmpty()) label += " [" + cl.awayMessage + "]"; if (cl.away && !cl.awayMessage.isEmpty()) label += " [" + cl.awayMessage + "]";
setText(label); setText(label);
setIcon(iconFor(cl)); setIcon(iconFor(cl));
setForeground(cl.talking ? Theme.TALKING : Theme.TREE_TEXT); // Talking shows in the client's icon, as it does in TeamSpeak. Marking the
setFont(cl.talking ? Theme.UI_BOLD : Theme.UI_FONT); // 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 { } else {
// root / server // root / server
setText(String.valueOf(obj)); setText(String.valueOf(obj));

View File

@@ -200,9 +200,13 @@ public final class ServerTreePanel extends JScrollPane {
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) { if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
if (obj instanceof ChannelNode && !Spacers.isSpacer(((ChannelNode) obj).name)) { if (obj instanceof ChannelNode && !Spacers.isSpacer(((ChannelNode) obj).name)) {
actions.joinChannel(((ChannelNode) obj).id); actions.joinChannel(((ChannelNode) obj).id);
} else if (obj instanceof ClientEntry && ((ClientEntry) obj).id != selfClientId) { } else if (obj instanceof ClientEntry) {
if (((ClientEntry) obj).id == selfClientId) {
tree.startEditingAtPath(tree.pathAt(e.getY()));
} else {
actions.openPrivateChat((ClientEntry) obj); actions.openPrivateChat((ClientEntry) obj);
} }
}
} else if (SwingUtilities.isMiddleMouseButton(e) && obj instanceof ClientEntry) { } else if (SwingUtilities.isMiddleMouseButton(e) && obj instanceof ClientEntry) {
actions.showConnectionInfo((ClientEntry) obj); actions.showConnectionInfo((ClientEntry) obj);
} }