Split ServerTreePanel into focused collaborator classes
Extract cell rendering, right-aligned group-icon-strip painting, the drop-indicator JTree subclass, and drag-and-drop handling out of ServerTreePanel into ServerTreeCellRenderer, DropIndicatorTree, and ServerTreeDragAndDrop, leaving ServerTreePanel as the coordinator (706 -> 284 lines). Pure refactor, no behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package com.ts3client.ui;
|
||||
|
||||
import com.ts3client.net.ChannelNode;
|
||||
import com.ts3client.net.ClientEntry;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import java.awt.Component;
|
||||
|
||||
/**
|
||||
* Draws a {@link ServerTreePanel} row: the status icon and the label. The group
|
||||
* icon strip is painted separately, right-aligned, by {@link DropIndicatorTree}.
|
||||
*/
|
||||
final class ServerTreeCellRenderer extends DefaultTreeCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
|
||||
boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
|
||||
setBackgroundNonSelectionColor(Theme.TREE_BG);
|
||||
setBackgroundSelectionColor(Theme.TREE_SELECTION);
|
||||
setBorderSelectionColor(Theme.TREE_SELECTION);
|
||||
|
||||
Object obj = ((DefaultMutableTreeNode) value).getUserObject();
|
||||
if (obj instanceof ChannelNode) {
|
||||
ChannelNode c = (ChannelNode) obj;
|
||||
Spacers.Spacer spacer = Spacers.parse(c.name);
|
||||
if (spacer != null) {
|
||||
setText(Spacers.render(spacer, 40));
|
||||
setIcon(null);
|
||||
setForeground(Theme.IDLE_CLIENT);
|
||||
setFont(Theme.UI_FONT);
|
||||
} else {
|
||||
setText(c.name);
|
||||
setIcon(iconFor(c));
|
||||
setForeground(Theme.CHANNEL_TEXT);
|
||||
setFont(Theme.UI_BOLD);
|
||||
}
|
||||
} else if (obj instanceof ClientEntry) {
|
||||
ClientEntry cl = (ClientEntry) obj;
|
||||
String label = cl.nickname;
|
||||
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);
|
||||
} else {
|
||||
// root / server
|
||||
setText(String.valueOf(obj));
|
||||
setIcon(Icons.server());
|
||||
setForeground(Theme.SERVER_TEXT);
|
||||
setFont(Theme.UI_BOLD);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private ImageIcon iconFor(ChannelNode c) {
|
||||
if (c.hasPassword) return Icons.channelLocked(c.subscribed);
|
||||
if (c.maxClients >= 0 && c.clients.size() >= c.maxClients) return Icons.channelFull(c.subscribed);
|
||||
return Icons.channel(c.subscribed);
|
||||
}
|
||||
|
||||
/** The client's state, in the order the official client gives them priority. */
|
||||
private ImageIcon iconFor(ClientEntry cl) {
|
||||
if (cl.isQuery()) return Icons.clientQuery();
|
||||
if (!cl.outputHardware) return Icons.speakerDisabled();
|
||||
if (cl.outputMuted) return Icons.speakerMuted();
|
||||
if (!cl.inputHardware) return Icons.micDisabled();
|
||||
if (cl.inputMuted) return Icons.micMuted();
|
||||
if (cl.away) return Icons.clientAway();
|
||||
if (cl.channelCommander) {
|
||||
return cl.talking ? Icons.clientCommanderTalking() : Icons.clientCommander();
|
||||
}
|
||||
if (cl.talking) return Icons.clientTalking();
|
||||
return Icons.clientIdle();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user