Add Set Server/Channel Group context menus and dialog
Lets moderators assign or revoke server and channel groups for a client directly from its context menu, with per-group checkboxes gated by the client's actual TS3 permissions (i_group_needed_member_ add/remove_power vs. each group's n_member_addp/removep, including TS3's -1 "unlimited" sentinel). A "Server Groups Dialog..." entry shows every server group, graying out ones the client can't touch. Group membership changes now update ClientEntry locally instead of only logging them, so the checkboxes and dialog reflect a change immediately instead of needing a reconnect. The server's default channel group (e.g. "Guest") is hidden from the channel-group menu since it's not something you assign directly.
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
package com.ts3client.ui;
|
||||
|
||||
import com.ts3client.net.ClientEntry;
|
||||
import com.ts3client.net.Group;
|
||||
import com.ts3client.net.ServerModel;
|
||||
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The context menu for a client, shared by the server tree and the clickable
|
||||
@@ -14,7 +19,8 @@ final class ClientMenu {
|
||||
private ClientMenu() {
|
||||
}
|
||||
|
||||
static JPopupMenu build(ClientEntry client, boolean self, ServerTreePanel.Actions actions) {
|
||||
static JPopupMenu build(ClientEntry client, boolean self, ServerModel model, GroupIcons groupIcons,
|
||||
ServerTreePanel.Actions actions) {
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
if (!self) {
|
||||
JMenuItem pm = new JMenuItem("Open text chat", Icons.of("PLAYER_CHAT"));
|
||||
@@ -44,6 +50,9 @@ final class ClientMenu {
|
||||
menu.add(me);
|
||||
}
|
||||
menu.addSeparator();
|
||||
menu.add(buildServerGroupMenu(client, model, groupIcons, actions));
|
||||
menu.add(buildChannelGroupMenu(client, model, groupIcons, actions));
|
||||
menu.addSeparator();
|
||||
JMenuItem findInTree = new JMenuItem("Find Client in Channel Tree", Icons.of("PLAYER_ON"));
|
||||
findInTree.addActionListener(a -> actions.findClientInTree(client));
|
||||
menu.add(findInTree);
|
||||
@@ -58,4 +67,68 @@ final class ClientMenu {
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
private static JMenu buildServerGroupMenu(ClientEntry client, ServerModel model, GroupIcons groupIcons,
|
||||
ServerTreePanel.Actions actions) {
|
||||
JMenu menu = new JMenu("Set Server Groups");
|
||||
menu.setIcon(Icons.of("PERMISSIONS_SERVER_GROUPS"));
|
||||
JMenuItem dialog = new JMenuItem("Server Groups Dialog...");
|
||||
dialog.addActionListener(a -> actions.showServerGroupsDialog(client));
|
||||
menu.add(dialog);
|
||||
menu.addSeparator();
|
||||
|
||||
int addPower = model.selfPermissionValue("i_group_needed_member_add_power");
|
||||
int removePower = model.selfPermissionValue("i_group_needed_member_remove_power");
|
||||
for (Group g : model.allServerGroups()) {
|
||||
boolean assigned = contains(client.serverGroupIds, g.id);
|
||||
if (!canAssign(g, assigned, addPower, removePower)) continue;
|
||||
JCheckBoxMenuItem item = new JCheckBoxMenuItem(g.name, groupIcons.iconOf(g));
|
||||
item.setSelected(assigned);
|
||||
item.addActionListener(a -> actions.setClientServerGroup(client, g, !assigned));
|
||||
menu.add(item);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
private static JMenu buildChannelGroupMenu(ClientEntry client, ServerModel model, GroupIcons groupIcons,
|
||||
ServerTreePanel.Actions actions) {
|
||||
JMenu menu = new JMenu("Set Channel Group");
|
||||
menu.setIcon(Icons.of("PERMISSIONS_CHANNEL_GROUPS"));
|
||||
int addPower = model.selfPermissionValue("i_group_needed_member_add_power");
|
||||
int removePower = model.selfPermissionValue("i_group_needed_member_remove_power");
|
||||
int defaultGroupId = model.defaultChannelGroupId();
|
||||
for (Group g : model.allChannelGroups()) {
|
||||
if (g.id == defaultGroupId) continue;
|
||||
boolean assigned = client.channelGroupId == g.id;
|
||||
if (!canAssign(g, assigned, addPower, removePower)) continue;
|
||||
JCheckBoxMenuItem item = new JCheckBoxMenuItem(g.name, groupIcons.iconOf(g));
|
||||
item.setSelected(assigned);
|
||||
item.addActionListener(a -> actions.setClientChannelGroup(client, g));
|
||||
menu.add(item);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the local client has enough power to (un)assign this group: the add
|
||||
* power always gates the checkbox, and the remove power additionally gates
|
||||
* unassigning an already-held group. {@code -1} is TS3's "unlimited" sentinel on
|
||||
* either side: an unlimited local power always passes, and a group that needs
|
||||
* unlimited power can only be touched by a local client that has it.
|
||||
*/
|
||||
static boolean canAssign(Group g, boolean assigned, int addPower, int removePower) {
|
||||
return hasPower(g.neededMemberAddPower, addPower)
|
||||
&& (!assigned || hasPower(g.neededMemberRemovePower, removePower));
|
||||
}
|
||||
|
||||
private static boolean hasPower(int needed, int own) {
|
||||
if (own == -1) return true;
|
||||
if (needed == -1) return false;
|
||||
return own >= needed;
|
||||
}
|
||||
|
||||
private static boolean contains(int[] ids, int id) {
|
||||
for (int i : ids) if (i == id) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user