package call.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.border.EtchedBorder;
import javax.swing.text.DefaultCaret;
import call.AbstractId;
import call.ChatCapture;
import call.Config;
import call.Contact;
import call.ContactList;
import call.ContactListUpdateListener;
import call.Ping;
import call.PingClient;
import call.Util;
public class ChatTab extends AbstractId implements PingClient.Listener, ContactListUpdateListener, Runnable {
// instances
private static final Map<Contact, ChatTab> instances = new HashMap<>();
private int generation = 1;
public static synchronized ChatTab getInstance(Contact c) {
if (instances.containsKey(c)) {
return instances.get(c);
} else {
ChatTab instance = new ChatTab(c);
new Thread(instance, "ChatTab").start();
instances.put(c, instance);
return instance;
}
}
// gui elements
private final JTextPane area;
private final ChatTabComponent panel;
private final Contact contact;
private final JHoverButton callbutton;
private final JHoverButton chatbutton;
private final CallAction callaction;
private final ChatAction chataction;
private final JTextField chatfield;
private final JLabel infolabelping;
private final JLabel infolabeluptime;
private final JLabel infolabelincoming;
private final JLabel infolabeloutgoing;
// info data
private Ping ping;
private ChatTab(Contact contact) {
this.contact = contact;
// Util.log(contact, "new ChatTab");
panel = new ChatTabComponent(this);
panel.setBorder(BorderFactory.createEmptyBorder());
panel.setLayout(setNoGaps(new BorderLayout()));
area = new JTextPane();
// area
new JTextPaneMessageOutput(contact, area);
area.setPreferredSize(new Dimension(650, 350));
area.setFont(Resources.FONT_TEXT);
area.setEditable(false);
DefaultCaret caret = (DefaultCaret) area.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
restoreChatlog();
// scrollpane
JScrollPane areaPane = new JScrollPane(area);
panel.add(BorderLayout.CENTER, areaPane);
// call panel
JPanel buttonpanel = new JPanel();
buttonpanel.setLayout(setNoGaps(new BorderLayout()));
buttonpanel.setBorder(BorderFactory.createEmptyBorder());
panel.add(BorderLayout.NORTH, buttonpanel);
// call button
callbutton = new JHoverButton(Resources.ICON_START_CALL, Resources.ICON_START_CALL_HOVER);
callaction = new CallAction(contact, callbutton);
callbutton.addActionListener(callaction.getActionListener());
buttonpanel.add(BorderLayout.WEST, callbutton);
callbutton.setBorderPainted(false);
callbutton.setFocusPainted(false);
callbutton.setContentAreaFilled(false);
// info panel
JPanel infopanel = new JPanel();
FlowLayout flow = new FlowLayout();
flow.setVgap(0);
infopanel.setLayout(flow);
infopanel.setBorder(BorderFactory.createEmptyBorder());
infopanel
.add(createTwoRowsPanel(new JLabel(Resources.LABEL_PING), new JLabel(Resources.LABEL_UPTIME)));
infolabelping = createInfoField(Resources.TEXT_PING_UNKNOWN);
infolabeluptime = createInfoField(Resources.TEXT_PING_UNKNOWN);
infopanel.add(createTwoRowsPanel(infolabelping, infolabeluptime));
infopanel.add(createTwoRowsPanel(new JLabel(Resources.LABEL_INCOMING), new JLabel(
Resources.LABEL_OUTGOING)));
infolabelincoming = createInfoField(Resources.TEXT_CALLSTATS_INCOMING);
infolabeloutgoing = createInfoField(Resources.TEXT_CALLSTATS_OUTGOING);
infopanel.add(createTwoRowsPanel(infolabelincoming, infolabeloutgoing));
updateCallStats(0, 0, 0, 0);
buttonpanel.add(BorderLayout.EAST, infopanel);
// chat panel
JPanel chatpanel = new JPanel();
chatpanel.setLayout(setNoGaps(new BorderLayout()));
chatpanel.setBorder(BorderFactory.createEmptyBorder());
// chat field
chatfield = new JTextField();
chatfield.setFont(Resources.FONT_TEXT);
// chatfield.setPreferredSize(new Dimension(500, 50));
// addEnterAction(chatfield, chataction.getActionListener());
chatpanel.add(BorderLayout.CENTER, chatfield);
// chat button
chatbutton = new JHoverButton(Resources.ICON_START_CHAT, Resources.ICON_START_CHAT_HOVER);
chatpanel.add(BorderLayout.EAST, chatbutton);
chatbutton.setBorderPainted(false);
chatbutton.setFocusPainted(false);
chatbutton.setContentAreaFilled(false);
chatbutton.setBorder(null);
chatbutton.setMargin(new Insets(0, 0, 0, 0));
// chat action
chataction = new ChatAction(contact, chatfield, chatbutton);
chatfield.addKeyListener(chataction.getKeyListener());
chatbutton.addActionListener(chataction.getActionListener());
panel.add(BorderLayout.SOUTH, chatpanel);
// add listeners
PingClient.addListener(contact, this);
ContactList.addListener(this);
}
private JLabel createInfoField(String text) {
JLabel info = new JLabel();
info.setText(text);
info.setBackground(Color.white);
info.setOpaque(true);
info.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(EtchedBorder.LOWERED),
BorderFactory.createMatteBorder(0, 3, 0, 3, Color.white)));
return info;
}
private Component createTwoRowsPanel(JComponent c1, JComponent c2) {
JPanel panel = new JPanel();
panel.setLayout(setNoGaps(new GridLayout(2, 1)));
panel.add(c1);
panel.add(c2);
return panel;
}
private LayoutManager setNoGaps(GridLayout layout) {
layout.setHgap(0);
layout.setVgap(0);
return layout;
}
private BorderLayout setNoGaps(BorderLayout layout) {
layout.setHgap(0);
layout.setVgap(0);
return layout;
}
@SuppressWarnings("unused")
private FlowLayout setNoGaps(FlowLayout layout) {
layout.setHgap(0);
layout.setVgap(0);
return layout;
}
@SuppressWarnings("unused")
private void addEnterAction(JTextArea textarea, Action action) {
InputMap input = textarea.getInputMap();
KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
input.put(shiftEnter, "insert-break");
input.put(enter, "text-submit");
ActionMap actions = textarea.getActionMap();
actions.put("text-submit", action);
}
public JComponent getComponent() {
return panel;
}
public Contact getContact() {
return contact;
}
public CallAction getCallaction() {
return callaction;
}
public ChatAction getChataction() {
return chataction;
}
public void focus() {
chatfield.requestFocusInWindow();
}
@Override
public void onPingUpdate(Contact contact) {
ping = PingClient.getPing(contact);
}
@Override
public void onContactUpdate(Contact contact) {}
@Override
public void onAnyContactUpdate() {}
@Override
public void run() {
final int currentGeneration = generation;
while (currentGeneration == generation) {
if (ContactList.isOnline(contact)) {
if (ping != null) {
infolabelping.setText(ping.toString());
infolabeluptime.setText(Util.formatMilliSecondsHumanReadable(System.currentTimeMillis()
- ping.getUptime()));
}
Util.sleep(5_000);
} else if (contact.isLoop()) {
infolabelping.setText(Resources.TEXT_PING_NOT_SUPPORTED);
infolabelping.setForeground(Color.RED);
infolabeluptime.setText(Util.formatMilliSecondsHumanReadable(System.currentTimeMillis()
- Config.CURRENT_UPTIME));
Util.sleep(5_000);
} else {
infolabelping.setText(Resources.TEXT_PING_OFFLINE);
infolabeluptime.setText(Resources.TEXT_PING_OFFLINE);
Util.sleep(15_000);
}
}
}
private void restoreChatlog() {
// deserialize chat log!
new ChatCapture(contact).deserialize(Util.msg(contact).getMessageOutput());
}
public void updateCallStats(float incomingSpeed, long incomingTotal, float outgoingSpeed,
long outgoingTotal) {
if (incomingSpeed != -1) {
String text = Util.formatBytesHumanReadable(incomingSpeed) + "/s";
if (!text.equals(infolabelincoming.getText()))
infolabelincoming.setText(text);
}
if (outgoingSpeed != -1) {
String text = Util.formatBytesHumanReadable(outgoingSpeed) + "/s";
if (!text.equals(infolabeloutgoing.getText()))
infolabeloutgoing.setText(text);
}
}
@Override
public boolean equals(Object obj) {
if (obj != null) {
return hashCode() == obj.hashCode();
}
return false;
}
@Override
public int hashCode() {
return contact.hashCode() + 17;
}
public class ChatTabComponent extends JPanel {
private static final long serialVersionUID = -2089483699485903634L;
private ChatTab chattab;
public ChatTabComponent(ChatTab chattab) {
this.chattab = chattab;
}
public ChatTab getChatTab() {
return chattab;
}
}
@Override
public String getId() {
return "ChatTab";
}
}