Log server activity, scrollable chat tabs, and move info panel to a chat tab
Native TS3 logs client joins/leaves/moves, group changes and channel edits to the server tab; minor local-only notices (mic mute, tray) no longer spam the log. Chat tabs scroll by mouse wheel like server tabs. The info panel can now be moved into a persistent, generically-labelled chat tab that tracks tree selection and collapses the panel's space entirely; a tree rebuild no longer briefly fires a null selection that reset this. Added "Find Client in Channel Tree" to the client context menu, and tree selection now survives model rebuilds. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,9 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
private final ChatPanel chatPanel;
|
||||
private final InfoPanel infoPanel = new InfoPanel();
|
||||
private final JComponent component;
|
||||
private JSplitPane leftColumn;
|
||||
private int normalDividerSize;
|
||||
private int savedDividerLocation = -1;
|
||||
|
||||
/** Label shown in the tab bar: the server name once known, the address before that. */
|
||||
private String title = "New connection";
|
||||
@@ -82,9 +85,27 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
});
|
||||
chatPanel.setInputEnabled(false);
|
||||
|
||||
JSplitPane leftColumn = new JSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, infoPanel);
|
||||
infoPanel.setDescriptionHandler(new InfoPanel.DescriptionHandler() {
|
||||
@Override
|
||||
public void showInfoTab(String html, Runnable onClose) {
|
||||
chatPanel.openDescriptionTab("info", Icons.channelClientPair(), "", html, onClose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeInfoTab() {
|
||||
chatPanel.closeNoteTab("info");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelHidden(boolean hidden) {
|
||||
ServerTab.this.setInfoPanelHidden(hidden);
|
||||
}
|
||||
});
|
||||
|
||||
leftColumn = new JSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, infoPanel);
|
||||
leftColumn.setResizeWeight(0.68);
|
||||
leftColumn.setContinuousLayout(true);
|
||||
normalDividerSize = leftColumn.getDividerSize();
|
||||
|
||||
JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftColumn, chatPanel);
|
||||
split.setResizeWeight(0.55);
|
||||
@@ -234,21 +255,18 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
void setMicMuted(boolean muted) {
|
||||
micMuted = muted;
|
||||
conn.setMicMuted(muted);
|
||||
chatPanel.appendSystem(muted ? "Microphone muted." : "Microphone active.");
|
||||
}
|
||||
|
||||
/** TS3's "Local Mic Mute": silences capture without publishing a status change. */
|
||||
void setMicLocalMuted(boolean muted) {
|
||||
micLocalMuted = muted;
|
||||
conn.setMicLocalMuted(muted);
|
||||
chatPanel.appendSystem(muted ? "Microphone locally muted." : "Microphone locally unmuted.");
|
||||
}
|
||||
|
||||
void setDeafened(boolean deaf) {
|
||||
deafened = deaf;
|
||||
conn.setDeafened(deaf);
|
||||
if (deaf) micMuted = true;
|
||||
chatPanel.appendSystem(deaf ? "Speakers muted (deafened)." : "Speakers active.");
|
||||
}
|
||||
|
||||
/** Hands the capture device to (or takes it from) this connection. */
|
||||
@@ -264,8 +282,6 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
this.away = away;
|
||||
if (message != null) this.awayMessage = message;
|
||||
conn.setAway(away, awayMessage);
|
||||
chatPanel.appendSystem(!away ? "No longer away."
|
||||
: awayMessage.isEmpty() ? "Away." : "Away: " + awayMessage);
|
||||
}
|
||||
|
||||
void setCommander(boolean commander) {
|
||||
@@ -425,7 +441,12 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
if (conn.getPlayback() == null) return;
|
||||
boolean now = !conn.getPlayback().isClientMuted(client.id);
|
||||
conn.getPlayback().setClientMuted(client.id, now);
|
||||
chatPanel.appendSystem((now ? "Muted " : "Unmuted ") + client.nickname + ".");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findClientInTree(ClientEntry client) {
|
||||
host.selectTab(this);
|
||||
treePanel.selectClient(client.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -481,6 +502,22 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
}
|
||||
}
|
||||
|
||||
/** Collapses the info panel to nothing while its content lives in the chat tab, or restores it. */
|
||||
private void setInfoPanelHidden(boolean hidden) {
|
||||
if (hidden == !infoPanel.isVisible()) return;
|
||||
if (hidden) {
|
||||
savedDividerLocation = leftColumn.getDividerLocation();
|
||||
infoPanel.setVisible(false);
|
||||
leftColumn.setDividerSize(0);
|
||||
leftColumn.setDividerLocation(1.0);
|
||||
} else {
|
||||
infoPanel.setVisible(true);
|
||||
leftColumn.setDividerSize(normalDividerSize);
|
||||
if (savedDividerLocation >= 0) leftColumn.setDividerLocation(savedDividerLocation);
|
||||
}
|
||||
leftColumn.revalidate();
|
||||
}
|
||||
|
||||
// ---- ConnectionListener (marshal to EDT) ----
|
||||
|
||||
@Override
|
||||
@@ -518,6 +555,7 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
infoPanel.clear();
|
||||
chatPanel.setInputEnabled(false);
|
||||
chatPanel.closePrivateChats();
|
||||
chatPanel.closeNoteTabs();
|
||||
chatPanel.appendSystem("Disconnected" + (reason == null || reason.isEmpty() ? "." : ": " + reason));
|
||||
host.tabDisconnected(this);
|
||||
});
|
||||
@@ -581,6 +619,11 @@ final class ServerTab implements ConnectionListener, ServerTreePanel.Actions {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerLog(String message) {
|
||||
SwingUtilities.invokeLater(() -> chatPanel.appendServerLog(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPoke(String fromName, String message) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
|
||||
Reference in New Issue
Block a user