Update connection and chat handling
This commit is contained in:
@@ -29,6 +29,7 @@ import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -138,13 +139,30 @@ public final class ChatPanel extends JPanel {
|
||||
|
||||
/** Opens (or focuses) the private chat with {@code clientId}. */
|
||||
public void openPrivateChat(int clientId, String nickname) {
|
||||
openPrivateChat(clientId, "", nickname);
|
||||
}
|
||||
|
||||
/** Opens (or focuses) the private chat with {@code clientId}. */
|
||||
public void openPrivateChat(int clientId, String uniqueId, String nickname) {
|
||||
edt(() -> {
|
||||
Tab tab = privateTab(clientId, nickname);
|
||||
Tab tab = privateTab(clientId, uniqueId, nickname);
|
||||
tabs.setSelectedComponent(tab.scroll);
|
||||
input.requestFocusInWindow();
|
||||
});
|
||||
}
|
||||
|
||||
public void setServerHistory(List<String> htmlEntries) {
|
||||
edt(() -> serverTab.setHistory(htmlEntries));
|
||||
}
|
||||
|
||||
public void setChannelHistory(List<String> htmlEntries) {
|
||||
edt(() -> channelTab.setHistory(htmlEntries));
|
||||
}
|
||||
|
||||
public void setPrivateHistory(int clientId, String nickname, List<String> htmlEntries) {
|
||||
edt(() -> privateTab(clientId, "", nickname).setHistory(htmlEntries));
|
||||
}
|
||||
|
||||
/** Drops every private chat tab, e.g. after disconnecting. */
|
||||
public void closePrivateChats() {
|
||||
edt(() -> {
|
||||
@@ -214,17 +232,35 @@ public final class ChatPanel extends JPanel {
|
||||
+ BBCode.linksToHtml(text) + "</span>"));
|
||||
}
|
||||
|
||||
public void appendServerLogHtml(String html) {
|
||||
edt(() -> serverTab.appendRawHtml(html));
|
||||
}
|
||||
|
||||
public void appendServerMessage(int fromId, String from, String text) {
|
||||
edt(() -> serverTab.appendMessage(fromId, from, text));
|
||||
appendServerMessage(fromId, "", from, text);
|
||||
}
|
||||
|
||||
public void appendServerMessage(int fromId, String uniqueId, String from, String text) {
|
||||
edt(() -> serverTab.appendMessage(fromId, uniqueId, from, text));
|
||||
}
|
||||
|
||||
public void appendChannelMessage(int fromId, String from, String text) {
|
||||
edt(() -> channelTab.appendMessage(fromId, from, text));
|
||||
appendChannelMessage(fromId, "", from, text);
|
||||
}
|
||||
|
||||
public void appendChannelMessage(int fromId, String uniqueId, String from, String text) {
|
||||
edt(() -> channelTab.appendMessage(fromId, uniqueId, from, text));
|
||||
}
|
||||
|
||||
/** Appends to the private chat with {@code peerId}, creating the tab if needed. */
|
||||
public void appendPrivateMessage(int peerId, String peerName, int fromId, String from, String text) {
|
||||
edt(() -> privateTab(peerId, peerName).appendMessage(fromId, from, text));
|
||||
appendPrivateMessage(peerId, "", peerName, fromId, "", from, text);
|
||||
}
|
||||
|
||||
/** Appends to the private chat with {@code peerId}, creating the tab if needed. */
|
||||
public void appendPrivateMessage(int peerId, String peerUniqueId, String peerName,
|
||||
int fromId, String fromUniqueId, String from, String text) {
|
||||
edt(() -> privateTab(peerId, peerUniqueId, peerName).appendMessage(fromId, fromUniqueId, from, text));
|
||||
}
|
||||
|
||||
private String stamp() {
|
||||
@@ -232,11 +268,17 @@ public final class ChatPanel extends JPanel {
|
||||
}
|
||||
|
||||
private Tab privateTab(int clientId, String nickname) {
|
||||
return privateTab(clientId, "", nickname);
|
||||
}
|
||||
|
||||
private Tab privateTab(int clientId, String uniqueId, String nickname) {
|
||||
Tab tab = privateTabs.get(clientId);
|
||||
if (tab == null) {
|
||||
tab = new Tab(Target.PRIVATE, clientId, nickname, Icons.privateChat());
|
||||
tab = new Tab(Target.PRIVATE, clientId, uniqueId, nickname, Icons.privateChat());
|
||||
privateTabs.put(clientId, tab);
|
||||
addTab(tab, true);
|
||||
} else {
|
||||
tab.setClientUniqueId(uniqueId);
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
@@ -301,6 +343,7 @@ public final class ChatPanel extends JPanel {
|
||||
|
||||
final Target target;
|
||||
final int clientId;
|
||||
private String clientUniqueId;
|
||||
private String title;
|
||||
final JEditorPane log = HtmlStyles.pane("font-family:sans-serif; font-size:11px; margin:4px 6px;");
|
||||
final JScrollPane scroll;
|
||||
@@ -311,17 +354,23 @@ public final class ChatPanel extends JPanel {
|
||||
private JLabel titleLabel;
|
||||
|
||||
Tab(Target target, int clientId, String title, Icon icon) {
|
||||
this(target, clientId, title, icon, null, null);
|
||||
this(target, clientId, "", title, icon, null, null);
|
||||
}
|
||||
|
||||
Tab(Target target, int clientId, String clientUniqueId, String title, Icon icon) {
|
||||
this(target, clientId, clientUniqueId, title, icon, null, null);
|
||||
}
|
||||
|
||||
/** A static-content tab: no send target, closing it runs {@code onClose}. */
|
||||
Tab(String noteKey, Icon icon, String title, Runnable onClose) {
|
||||
this(null, 0, title, icon, noteKey, onClose);
|
||||
this(null, 0, "", title, icon, noteKey, onClose);
|
||||
}
|
||||
|
||||
private Tab(Target target, int clientId, String title, Icon icon, String noteKey, Runnable onClose) {
|
||||
private Tab(Target target, int clientId, String clientUniqueId, String title,
|
||||
Icon icon, String noteKey, Runnable onClose) {
|
||||
this.target = target;
|
||||
this.clientId = clientId;
|
||||
this.clientUniqueId = clientUniqueId == null ? "" : clientUniqueId;
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.noteKey = noteKey;
|
||||
@@ -338,6 +387,10 @@ public final class ChatPanel extends JPanel {
|
||||
scroll.setBorder(BorderFactory.createEmptyBorder());
|
||||
}
|
||||
|
||||
void setClientUniqueId(String uniqueId) {
|
||||
if (uniqueId != null && !uniqueId.isBlank()) clientUniqueId = uniqueId;
|
||||
}
|
||||
|
||||
private void onLink(String href) {
|
||||
if (href == null) return;
|
||||
TsLink.Ref ref = TsLink.parse(href);
|
||||
@@ -405,16 +458,27 @@ public final class ChatPanel extends JPanel {
|
||||
titleLabel.setForeground(unread ? Theme.accent() : null);
|
||||
}
|
||||
|
||||
void appendMessage(int fromId, String from, String text) {
|
||||
void appendMessage(int fromId, String fromUniqueId, String from, String text) {
|
||||
String name = BBCode.escape(from);
|
||||
String sender = fromId > 0
|
||||
? "<a class=\"" + BBCode.IDENTITY_LINK_CLASS + "\" href=\""
|
||||
+ BBCode.escape(TsLink.clientHref(fromId, "", from)) + "\">" + name + "</a>"
|
||||
+ BBCode.escape(TsLink.clientHref(fromId,
|
||||
fromUniqueId == null || fromUniqueId.isBlank() ? clientUniqueId : fromUniqueId,
|
||||
from)) + "\">" + name + "</a>"
|
||||
: "<span class=\"name\">" + name + "</span>";
|
||||
appendLine("<span class=\"muted\">" + stamp() + "</span>"
|
||||
+ sender + ": " + BBCode.toHtml(text));
|
||||
}
|
||||
|
||||
void setHistory(List<String> htmlEntries) {
|
||||
StringBuilder html = new StringBuilder();
|
||||
if (htmlEntries != null) {
|
||||
for (String entry : htmlEntries) html.append(normalizeTs3LogEntry(entry));
|
||||
}
|
||||
log.setText("<html><body><div id=\"chatlog\">" + html + "</div></body></html>");
|
||||
log.setCaretPosition(log.getDocument().getLength());
|
||||
}
|
||||
|
||||
/** Replaces the whole log with fixed content; used by static-content tabs. */
|
||||
void setStaticContent(String html) {
|
||||
log.setText("<html><body><div id=\"chatlog\">" + html + "</div></body></html>");
|
||||
@@ -422,13 +486,26 @@ public final class ChatPanel extends JPanel {
|
||||
}
|
||||
|
||||
void appendLine(String html) {
|
||||
appendRawHtml("<div>" + html + "</div>");
|
||||
}
|
||||
|
||||
void appendRawHtml(String html) {
|
||||
try {
|
||||
HTMLDocument doc = (HTMLDocument) log.getDocument();
|
||||
doc.insertBeforeEnd(doc.getElement("chatlog"), "<div>" + html + "</div>");
|
||||
doc.insertBeforeEnd(doc.getElement("chatlog"), normalizeTs3LogEntry(html));
|
||||
log.setCaretPosition(doc.getLength());
|
||||
} catch (BadLocationException | IOException ignored) {
|
||||
}
|
||||
if (tabs.getSelectedComponent() != scroll) setUnread(true);
|
||||
}
|
||||
|
||||
private String normalizeTs3LogEntry(String html) {
|
||||
if (html == null || html.isBlank()) return "";
|
||||
String normalized = html
|
||||
.replaceAll("(?i)<img\\b[^>]*>", "")
|
||||
.replaceFirst("(?i)^\\s*<p\\b", "<div")
|
||||
.replaceFirst("(?i)</p>\\s*$", "</div>");
|
||||
return normalized.startsWith("<div") ? normalized : "<div>" + normalized + "</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.ts3client.net.TeamspeakConnection;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Marshals {@link ConnectionListener} callbacks onto the EDT and fans them out to
|
||||
@@ -129,18 +130,34 @@ final class ServerTabConnectionEvents implements ConnectionListener {
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
public void onChat(ChatScope scope, int fromClientId, String fromUniqueId, String fromName, String message) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
switch (scope) {
|
||||
case PRIVATE:
|
||||
chatPanel.appendPrivateMessage(fromClientId, fromUniqueId, fromName,
|
||||
fromClientId, fromUniqueId, fromName, message);
|
||||
break;
|
||||
case SERVER:
|
||||
chatPanel.appendServerMessage(fromClientId, fromUniqueId, fromName, message);
|
||||
break;
|
||||
default:
|
||||
chatPanel.appendChannelMessage(fromClientId, fromUniqueId, fromName, message);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChatHistory(ChatScope scope, List<String> htmlEntries) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (scope == ChatScope.SERVER) chatPanel.setServerHistory(htmlEntries);
|
||||
else if (scope == ChatScope.CHANNEL) chatPanel.setChannelHistory(htmlEntries);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrivateChatHistory(int clientId, String nickname, List<String> htmlEntries) {
|
||||
SwingUtilities.invokeLater(() -> chatPanel.setPrivateHistory(clientId, nickname, htmlEntries));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,6 +182,11 @@ final class ServerTabConnectionEvents implements ConnectionListener {
|
||||
SwingUtilities.invokeLater(() -> chatPanel.appendServerLog(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerLogHtml(String html) {
|
||||
SwingUtilities.invokeLater(() -> chatPanel.appendServerLogHtml(html));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPoke(String fromName, String message) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
|
||||
@@ -123,7 +123,8 @@ final class ServerTabTreeActions implements ServerTreePanel.Actions {
|
||||
|
||||
@Override
|
||||
public void openPrivateChat(ClientEntry client) {
|
||||
chatPanel.openPrivateChat(client.id, client.nickname);
|
||||
chatPanel.openPrivateChat(client.id, client.uniqueId, client.nickname);
|
||||
conn.loadPrivateChatHistory(client.id, client.uniqueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user