The official client creates and edits channels with one dialog, so ChannelEditDialog becomes ChannelDialog with two entry points. Creating starts from caller-chosen defaults instead of a channelinfo and sends a channelcreate carrying only what deviates from a plain new channel — TeamSpeak checks a create permission per property that is present. The server row now has a context menu with "Create Channel" and "Create Spacer" (pre-filled with the lowest free [spacerN], since channel names must be unique), and a channel's menu offers "Create Channel" and "Create Sub-Channel", both starting out temporary. Verified against the test server: a temporary channel is created, and a permanent one a guest may not create reports the server's refusal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
3.4 KiB
Java
80 lines
3.4 KiB
Java
package com.ts3client.ui;
|
|
|
|
import com.ts3client.net.ChannelNode;
|
|
import com.ts3client.net.ChannelSettings;
|
|
|
|
import javax.swing.JMenuItem;
|
|
import javax.swing.JPopupMenu;
|
|
|
|
/**
|
|
* The context menu for a channel, shared by the server tree and channel links
|
|
* in the chat log.
|
|
*/
|
|
final class ChannelMenu {
|
|
|
|
private ChannelMenu() {
|
|
}
|
|
|
|
static JPopupMenu build(ChannelNode channel, ServerTreePanel.Actions actions) {
|
|
JPopupMenu menu = new JPopupMenu();
|
|
JMenuItem join = new JMenuItem("Join channel", Icons.of("CHANNEL_SWITCH"));
|
|
join.addActionListener(a -> actions.joinChannel(channel.id));
|
|
menu.add(join);
|
|
menu.addSeparator();
|
|
// Both start out temporary: a channel made from another channel's menu is
|
|
// usually a throwaway one, and a permanent channel is a deliberate choice.
|
|
JMenuItem create = new JMenuItem("Create Channel", Icons.of("CHANNEL_CREATE"));
|
|
create.addActionListener(a -> actions.createChannel(null, ChannelSettings.Type.TEMPORARY));
|
|
menu.add(create);
|
|
JMenuItem createSub = new JMenuItem("Create Sub-Channel", Icons.of("CHANNEL_CREATE_SUB"));
|
|
createSub.addActionListener(a -> actions.createChannel(channel, ChannelSettings.Type.TEMPORARY));
|
|
menu.add(createSub);
|
|
JMenuItem edit = new JMenuItem("Edit Channel", Icons.of("CHANNEL_EDIT"));
|
|
edit.addActionListener(a -> actions.editChannel(channel));
|
|
menu.add(edit);
|
|
menu.addSeparator();
|
|
addSubscriptionItems(menu, channel, actions);
|
|
JMenuItem files = new JMenuItem("Browse files", Icons.of("FILETRANSFER"));
|
|
files.addActionListener(a -> actions.browseFiles(channel));
|
|
menu.add(files);
|
|
return menu;
|
|
}
|
|
|
|
/**
|
|
* The subscription entries, offered the way the official client does: the channel
|
|
* itself toggles, and the family entries appear only where they would do something.
|
|
*/
|
|
private static void addSubscriptionItems(JPopupMenu menu, ChannelNode channel,
|
|
ServerTreePanel.Actions actions) {
|
|
if (channel.subscribed) {
|
|
add(menu, "Unsubscribe from Channel",
|
|
() -> actions.setChannelSubscribed(channel, false, false),
|
|
"UNSUBSCRIBE_FROM_CHANNEL");
|
|
} else {
|
|
add(menu, "Subscribe to Channel",
|
|
() -> actions.setChannelSubscribed(channel, false, true),
|
|
"SUBSCRIBE_TO_CHANNEL");
|
|
}
|
|
if (!channel.children.isEmpty()) {
|
|
if (!channel.allSubscribed()) {
|
|
add(menu, "Subscribe to Channel Family",
|
|
() -> actions.setChannelSubscribed(channel, true, true),
|
|
"SUBSCRIBE_TO_CHANNEL_FAMILY", "SUBSCRIBE_TO_ALL_CHANNELS");
|
|
}
|
|
if (channel.anySubscribed()) {
|
|
add(menu, "Unsubscribe from Channel Family",
|
|
() -> actions.setChannelSubscribed(channel, true, false),
|
|
"UNSUBSCRIBE_FROM_CHANNEL_FAMILY", "UNSUBSCRIBE_FROM_ALL_CHANNELS");
|
|
}
|
|
}
|
|
menu.addSeparator();
|
|
}
|
|
|
|
/** Adds an item, icon-less when the pack has none of the given keys. */
|
|
private static void add(JPopupMenu menu, String text, Runnable action, String... iconKeys) {
|
|
JMenuItem item = new JMenuItem(text, Icons.ofAny(iconKeys));
|
|
item.addActionListener(a -> action.run());
|
|
menu.add(item);
|
|
}
|
|
}
|