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.
162 lines
5.2 KiB
Java
162 lines
5.2 KiB
Java
package com.ts3client.ui;
|
|
|
|
import com.ts3client.net.ConnectionListener;
|
|
import com.ts3client.net.TeamspeakConnection;
|
|
|
|
import javax.swing.JOptionPane;
|
|
import javax.swing.SwingUtilities;
|
|
|
|
/**
|
|
* Marshals {@link ConnectionListener} callbacks onto the EDT and fans them out to
|
|
* this tab's views (tree, chat, info panel) and to {@link MainFrame}.
|
|
*
|
|
* <p>Constructed before the {@link TeamspeakConnection} it listens to exists — the
|
|
* connection's constructor needs a listener up front — so {@link #attach} wires the
|
|
* rest of the tab in once everything else has been built.
|
|
*/
|
|
final class ServerTabConnectionEvents implements ConnectionListener {
|
|
|
|
/** The handful of {@link ServerTab} fields this class updates but can't reach directly. */
|
|
interface Listener {
|
|
void setStatus(String status);
|
|
|
|
void setTitle(String title);
|
|
|
|
void setConnecting(boolean connecting);
|
|
}
|
|
|
|
private final MainFrame host;
|
|
private final ServerTab tab;
|
|
private final Listener listener;
|
|
|
|
private TeamspeakConnection conn;
|
|
private ServerTreePanel treePanel;
|
|
private ChatPanel chatPanel;
|
|
private ServerTabSelfState selfState;
|
|
private ServerTabTreeActions treeActions;
|
|
|
|
ServerTabConnectionEvents(MainFrame host, ServerTab tab, Listener listener) {
|
|
this.host = host;
|
|
this.tab = tab;
|
|
this.listener = listener;
|
|
}
|
|
|
|
void attach(TeamspeakConnection conn, ServerTreePanel treePanel, ChatPanel chatPanel,
|
|
ServerTabSelfState selfState, ServerTabTreeActions treeActions) {
|
|
this.conn = conn;
|
|
this.treePanel = treePanel;
|
|
this.chatPanel = chatPanel;
|
|
this.selfState = selfState;
|
|
this.treeActions = treeActions;
|
|
}
|
|
|
|
@Override
|
|
public void onStatus(String text) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
listener.setStatus(text);
|
|
host.tabUpdated(tab);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onConnected() {
|
|
SwingUtilities.invokeLater(() -> {
|
|
listener.setConnecting(false);
|
|
treePanel.setSelfClientId(conn.getSelfClientId());
|
|
selfState.resetOnConnect();
|
|
chatPanel.setInputEnabled(true);
|
|
chatPanel.appendSystem("Connected.");
|
|
host.tabConnected(tab);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onDisconnected(String reason) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
listener.setConnecting(false);
|
|
conn.getModel().clear();
|
|
treePanel.showDisconnected();
|
|
treeActions.clearSelection();
|
|
chatPanel.setInputEnabled(false);
|
|
chatPanel.closePrivateChats();
|
|
chatPanel.closeNoteTabs();
|
|
chatPanel.appendSystem("Disconnected" + (reason == null || reason.isEmpty() ? "." : ": " + reason));
|
|
host.tabDisconnected(tab);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onModelChanged() {
|
|
SwingUtilities.invokeLater(() -> {
|
|
treePanel.rebuild();
|
|
treeActions.renderInfo();
|
|
treeActions.refreshGroupsDialog();
|
|
String name = conn.getModel().getServerName();
|
|
if (conn.isConnected() && name != null && !name.isBlank() && !name.equals(tab.title())) {
|
|
listener.setTitle(name);
|
|
host.tabUpdated(tab);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onInfoUpdated() {
|
|
SwingUtilities.invokeLater(treeActions::renderInfo);
|
|
}
|
|
|
|
@Override
|
|
public void onIconsUpdated() {
|
|
SwingUtilities.invokeLater(() -> {
|
|
treePanel.refreshRowSizes();
|
|
treeActions.renderInfo();
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onChat(ChatScope scope, int fromClientId, String fromName, String message) {
|
|
switch (scope) {
|
|
case PRIVATE:
|
|
chatPanel.appendPrivateMessage(fromClientId, fromName, fromClientId, fromName, message);
|
|
break;
|
|
case SERVER:
|
|
chatPanel.appendServerMessage(fromClientId, fromName, message);
|
|
break;
|
|
default:
|
|
chatPanel.appendChannelMessage(fromClientId, fromName, message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onTalkStateChanged(int clientId, boolean talking) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
treePanel.refreshVisual();
|
|
if (clientId == conn.getSelfClientId()) host.selfStateChanged(tab);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onError(String message) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
chatPanel.appendSystem("Error: " + message);
|
|
listener.setStatus(message);
|
|
host.tabUpdated(tab);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void onServerLog(String message) {
|
|
SwingUtilities.invokeLater(() -> chatPanel.appendServerLog(message));
|
|
}
|
|
|
|
@Override
|
|
public void onPoke(String fromName, String message) {
|
|
SwingUtilities.invokeLater(() -> {
|
|
chatPanel.appendSystem("You were poked by " + fromName + ": " + message);
|
|
host.selectTab(tab);
|
|
JOptionPane.showMessageDialog(host, fromName + " poked you:\n\n" + message,
|
|
"Poke", JOptionPane.INFORMATION_MESSAGE);
|
|
});
|
|
}
|
|
}
|