package common.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import common.Face;
public class DisplayPanel extends JPanel {
private static final long serialVersionUID = 3833181437003642169L;
private static final int DEFAULT_DIVIDER_SIZE = new JSplitPane().getDividerSize();
private JTextPane chatArea; private JTextPane bufferArea; private JScrollPane chatScroll; private JSplitPane chatSplit; private JScrollPane bufferScroll; private JScrollBar scrollBar; private boolean split; private Runnable onText; private static StyledDocument doc; private static Style defStyle;
public DisplayPanel() {
super(new BorderLayout());
chatArea = makeDisplayPane();
bufferArea = makeDisplayPane();
bufferArea.setFocusable(false);
doc = chatArea.getStyledDocument();
bufferArea.setStyledDocument(doc);
defStyle = chatArea.addStyle("default", null);
StyleConstants.setForeground(defStyle, Color.lightGray);
bufferScroll = new JScrollPane(bufferArea);
chatScroll = new JScrollPane(chatArea);
scrollBar = chatScroll.getVerticalScrollBar();
chatSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, chatScroll, null);
chatSplit.setDividerSize(0);
bufferScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
chatScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
add(chatSplit, BorderLayout.CENTER);
add(scrollBar, BorderLayout.EAST);
bufferArea.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
if (e.getDot() != doc.getLength()) {
bufferArea.setCaretPosition(doc.getLength());
}
}
});
chatArea.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
if (split) {
if (e.getDot() == doc.getLength() && e.getDot() > 0) {
chatArea.setCaretPosition(e.getDot() - 1);
}
} else {
if (e.getDot() != doc.getLength()) {
bufferArea.setCaretPosition(doc.getLength());
}
}
}
});
scrollBar.addAdjustmentListener(new AdjustmentListener() {
boolean firstTime = true;
private int lastValue = -1;
private int lastMax = -1;
public void adjustmentValueChanged(AdjustmentEvent e) {
if (doc.getLength() == 0) {
return;
}
if (!split && chatArea.getCaretPosition() != doc.getLength()) {
chatArea.setCaretPosition(doc.getLength());
}
if (lastValue == e.getValue() && lastMax == e.getAdjustable().getMaximum() && !firstTime) {
if (e.getAdjustable().getVisibleAmount() + e.getValue() >= e
.getAdjustable().getMaximum()) { split(false);
} else { split(true);
}
}
lastValue = e.getValue();
lastMax = e.getAdjustable().getMaximum();
firstTime = false;
}
});
chatSplit.addPropertyChangeListener("lastDividerLocation",
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (doc.getLength() > 0) {
chatArea.setCaretPosition(doc.getLength() - 1);
}
chatArea.setCaretPosition(doc.getLength());
}
});
}
private void split(boolean newSplit) {
if (split == newSplit) {
return;
}
split = newSplit;
if (newSplit) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatSplit.setBottomComponent(bufferScroll);
chatSplit.setDividerLocation(0.8);
chatSplit.setDividerSize(DEFAULT_DIVIDER_SIZE);
chatArea.setCaretPosition(doc.getLength() - 1); bufferArea.setCaretPosition(doc.getLength() - 1); bufferArea.setCaretPosition(doc.getLength()); }
});
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
chatSplit.remove(bufferScroll);
chatSplit.setDividerSize(0);
chatArea.setCaretPosition(doc.getLength()); }
});
}
}
public void sendFace(Face face, String... text) {
send(face, null, text);
}
public void sendImage(String filename, String... text) {
send(null, filename, text);
}
private void send(final Face face, final String image, final String... text) {
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
send(face, image, text);
}
});
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return;
}
final JLabel imageLabel = new JLabel();
if (face != null) {
imageLabel.setIcon(FaceIcon.LOADING_IMAGE);
}
if (text.length == 0) {
println("");
chatArea.setCaretPosition(doc.getLength());
chatArea.insertComponent(imageLabel);
}
else {
JPanel imagePanel = new JPanel(new BorderLayout());
imagePanel.setOpaque(false);
JTextPane textPane = makeDisplayPane();
imagePanel.add(imageLabel, BorderLayout.WEST);
imagePanel.add(textPane, BorderLayout.CENTER);
StringBuffer sb = new StringBuffer();
for (String s : text) {
if (sb.length() > 0) {
sb.append("\n\n");
}
sb.append(s);
}
println("");
println(textPane.getStyledDocument(), sb.toString());
chatArea.setCaretPosition(doc.getLength());
chatArea.insertComponent(imagePanel);
}
println("");
new Thread() {
@Override
public void run() {
try {
final Icon icon;
if (image != null) {
icon = GameClient.getImageIcon("graphics/" + image);
}
else {
icon = new FaceIcon(face);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
imageLabel.setIcon(icon);
chatArea.setCaretPosition(doc.getLength() - 1);
chatArea.setCaretPosition(doc.getLength());
}
});
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}.start();
}
public void printTable(final String[][] data, final String[] headers, final int[] sizes) {
TableModel myModel = new AbstractTableModel() {
private static final long serialVersionUID = 3256719597939275573L;
@Override
public String getColumnName(int column) {
return headers[column];
}
public Object getValueAt(int rowIndex, int columnIndex) {
return data[rowIndex][columnIndex];
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return headers.length;
}
};
final JTable table = new JTable(myModel);
final JTextArea area = new JTextArea();
area.setLineWrap(true);
area.setWrapStyleWord(true);
area.setForeground(Color.white);
area.setOpaque(true);
area.setBorder(new EmptyBorder(0, 1, 0, 1));
area.setBackground(new Color(15, 15, 80));
final TableCellRenderer oldRenderer = table.getDefaultRenderer(Object.class);
table.setDefaultRenderer(Object.class, new TableCellRenderer() {
public Component getTableCellRendererComponent(JTable t, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
area.setText((String) value);
area.setSize(
t.getColumnModel().getColumn(column).getWidth(),
Integer.MAX_VALUE);
int height = area.getPreferredSize().height;
if (t.getRowHeight(row) < height) {
t.setRowHeight(row, height);
}
return area;
}
int height = t.getRowHeight();
if (t.getRowHeight(row) != height) {
t.setRowHeight(row, height);
}
return oldRenderer.getTableCellRendererComponent(
t, value, isSelected, hasFocus, row, column);
}
});
JTableHeader header = table.getTableHeader();
final JPanel headerPanel = new JPanel(new BorderLayout(5, 5));
headerPanel.setBackground(Color.black);
headerPanel.setOpaque(true);
headerPanel.setBorder(new CompoundBorder(new LineBorder(Color.white, 1), new EmptyBorder(5, 5, 5, 5)));
final JLabel headerLabel = new JLabel();
final JLabel arrowLabel = new JLabel("\u21E7");
Font font = headerLabel.getFont();
font = font.deriveFont(Font.BOLD, font.getSize2D() + 2.0f);
headerLabel.setFont(font);
arrowLabel.setFont(font);
headerLabel.setForeground(Color.white);
arrowLabel.setForeground(Color.cyan);
headerPanel.add(arrowLabel, BorderLayout.WEST);
headerPanel.add(headerLabel, BorderLayout.CENTER);
header.setDefaultRenderer(new TableCellRenderer() {
public Component getTableCellRendererComponent(JTable jtable, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
headerLabel.setText((String) value);
return headerPanel;
}
});
table.setBackground(Color.black);
table.setForeground(Color.white);
table.setBorder(new LineBorder(Color.white, 1));
JPanel p = new JPanel(new BorderLayout());
p.add(table, BorderLayout.CENTER);
p.add(table.getTableHeader(), BorderLayout.SOUTH);
println("");
chatArea.setCaretPosition(doc.getLength());
chatArea.insertComponent(p);
println("");
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int total = 0;
int remaining = table.getWidth();
if (sizes != null) {
TableColumnModel columnModel = table.getColumnModel();
for (int i = 0; i < sizes.length; i++) {
if (sizes[i] >= 0) {
TableColumn column = table.getColumnModel().getColumn(i);
column.setWidth(sizes[i]);
column.setMinWidth(sizes[i]);
column.setMaxWidth(sizes[i]);
column.setPreferredWidth(sizes[i]);
remaining -= sizes[i];
total++;
}
}
if (remaining < 0) {
remaining = 0;
}
int count = columnModel.getColumnCount();
total = count - total; remaining /= total; for (int i = 0; i < count; i++) {
if (i >= sizes.length || sizes[i] < 0) {
TableColumn column = table.getColumnModel().getColumn(i);
column.setWidth(remaining);
column.setMinWidth(remaining);
column.setMaxWidth(remaining);
column.setPreferredWidth(remaining);
}
}
}
int count = table.getColumnModel().getColumnCount();
for (int i = 0; i < count; i++) {
TableColumn column = table.getColumnModel().getColumn(i);
column.setMinWidth(0);
column.setMaxWidth(Integer.MAX_VALUE);
}
}
});
}
public void println(String text) {
print(doc, text + '\n');
}
public void print(String text) {
print(doc, text);
}
private void println(StyledDocument sd, String text) {
print(sd, text + '\n');
}
private void print(final StyledDocument sd, final String text) {
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
print(sd, text);
}
});
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return;
}
int defaultAttributes = 0;
int defaultBackground = 0;
int defaultForeground = 7;
try {
Style style = defStyle; char[] c = text.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < c.length; i++) {
if (c[i] == '@' && i <= c.length - 4) {
try {
Style newStyle = sd.addStyle(null, null);
int foreground = parseColor(c[i + 3], defaultForeground);
int background = parseColor(c[i + 2], defaultBackground);
int attributes = parseColor(c[i + 1], defaultAttributes);
Color foregroundColor = null;
Color backgroundColor = null;
switch (background * 16 + foreground) {
case 0x00:
foreground = 7;
break;
case 0x11:
foreground = 9;
break;
case 0x22:
foreground = 10;
break;
case 0x33:
foreground = 11;
break;
case 0x44:
foreground = 12;
backgroundColor = new Color(0, 0, 32);
break;
case 0x55:
foreground = 13;
break;
case 0x66:
foreground = 14;
break;
case 0x77:
foreground = 15;
break;
case 0x88:
foreground = 0;
break;
case 0x99:
foreground = 1;
break;
case 0xAA:
foreground = 2;
break;
case 0xBB:
foreground = 3;
break;
case 0xCC:
foregroundColor = new Color(0, 0, 32);
break;
case 0xDD:
foreground = 5;
break;
case 0xEE:
foreground = 6;
break;
case 0xFF:
foreground = 8;
break;
case 0x38:
foreground = 7;
break;
case 0x83:
foreground = 11;
break;
case 0xAE:
foreground = 6;
break;
case 0xEA:
foreground = 2;
break;
case 0xBF:
foreground = 8;
break;
case 0xFB:
foreground = 3;
break;
case 0xAB:
foreground = 3;
break;
case 0xBA:
foreground = 2;
break;
}
if (foregroundColor == null) {
foregroundColor = colorForNumber(foreground);
}
if (backgroundColor == null) {
backgroundColor = colorForNumber(background);
}
StyleConstants.setForeground(newStyle, foregroundColor);
StyleConstants.setBackground(newStyle, backgroundColor);
boolean bold = attributes % 2 == 1;
StyleConstants.setBold(newStyle, bold);
boolean italic = (attributes >> 1) % 2 == 1;
StyleConstants.setItalic(newStyle, italic);
boolean underline = (attributes >> 2) % 2 == 1;
StyleConstants.setUnderline(newStyle, underline);
if (i == 0) { defaultForeground = foreground;
defaultBackground = background;
defaultAttributes = attributes;
}
i += 3; if (sb.length() > 0) {
sd.insertString(sd.getLength(), sb.toString(),
style);
sb = new StringBuffer();
}
style = newStyle;
continue;
} catch (NumberFormatException ex) {
}
}
sb.append(c[i]);
}
sd.insertString(sd.getLength(), sb.toString(), style);
if (onText != null) {
onText.run();
}
} catch (BadLocationException ex) {
throw new RuntimeException(ex);
}
}
private Color colorForNumber(int n) {
switch (n % 16) {
case 1:
return new Color(128, 0, 0); case 2:
return new Color(0, 179, 0); case 3:
return new Color(128, 128, 0); case 4:
return new Color(0, 0, 128); case 5:
return new Color(128, 0, 128); case 6:
return new Color(0, 128, 128); case 7:
return new Color(192, 192, 192); case 8:
return new Color(128, 128, 128); case 9:
return new Color(255, 0, 0); case 10:
return new Color(0, 255, 0); case 11:
return new Color(255, 255, 0); case 12:
return new Color(64, 64, 255); case 13:
return new Color(255, 0, 255); case 14:
return new Color(0, 255, 255); case 15:
return new Color(255, 255, 255); default:
return new Color(0, 0, 0); }
}
private JTextPane makeDisplayPane() {
JTextPane ret = new JTextPane();
ret.setBackground(Color.black);
ret.setFont(new Font("Monospaced", Font.PLAIN, 14));
ret.setEditable(false);
return ret;
}
public void clear() {
chatArea.setText("");
}
private int parseColor(char c, int def) {
if (c == 'Z' || c == 'z') {
return def;
} else {
return Integer.parseInt(String.valueOf(c), 16);
}
}
public void setOnText(Runnable r) {
this.onText = r;
}
}