Files
ts3java/ts3-client/swing/src/main/java/com/ts3client/ui/ChannelMenu.java
ericek111 f2885d33ad Add the Create Channel dialog
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>
2026-08-19 15:31:07 +00:00

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);
}
}