package net.sf.f3270;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Map;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import org.h3270.host.Field;
import org.h3270.host.InputField;
import org.h3270.host.S3270;
public class TerminalWindow {
private S3270 s3270;
private int currentWidth;
private int currentHeight;
private Style styleInputChanged;
private Style styleInput;
private Style styleBlack;
private Style styleCommand;
private Style stylePunctuation;
private Style styleReturn;
private Style styleParamName;
private Style styleParamValue;
private final Font monospacedFont = new Font(Font.MONOSPACED, Font.PLAIN,
12);
private final Font sansFont = new Font(Font.SANS_SERIF, Font.PLAIN, 11);
private Color[] extendedColors = new Color[] { Color.cyan, Color.blue,
Color.red, Color.pink, Color.green, Color.magenta, Color.yellow,
new Color(198, 198, 198) };
private Map<String, Style> stylesFlyweight = new HashMap<String, Style>();
private JFrame frame;
private JTextPane textPane3270;
private JTextPane textPaneDebug;
private DefaultStyledDocument documentDebug;
private JTable fieldsTable;
private JTabbedPane tabbedPane;
public TerminalWindow(final S3270 s3270) {
this.s3270 = s3270;
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (final Exception e) {
throw new RuntimeException(e);
}
initializeStyles();
createFrame(s3270.getHostname());
}
private void initializeStyles() {
styleInputChanged = createStyle(Color.black, Color.red, false);
styleInput = createStyle(Color.green, Color.black, false);
styleCommand = createStyle(Color.black, Color.white, false);
stylePunctuation = createStyle(Color.gray, Color.white, false);
styleReturn = createStyle(Color.magenta, Color.white, false);
styleParamName = createStyle(new Color(128, 0, 0), Color.white, false);
styleParamValue = createStyle(Color.blue, Color.white, false);
}
public void update(final String command, final String returned,
final Parameter... parameters) {
updateTerminal();
updateDebug(command, returned, parameters);
updateFieldsTable();
}
private void updateTerminal() {
final DefaultStyledDocument doc = new DefaultStyledDocument();
for (Field f : s3270.getScreen().getFields()) {
final Style s = getStyle(f);
final String text = f.getText().replace('\u0000', ' ');
if ((f instanceof InputField) && text.startsWith(" ")) {
appendText(doc, " ", styleBlack);
appendText(doc, text.substring(1), s);
} else {
appendText(doc, text, s);
}
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
boolean sizeChanged = updateTextPane3270Size();
if (sizeChanged) {
updateTabbedPaneSize();
frame.pack();
}
textPane3270.setDocument(doc);
} catch (RuntimeException e) {
// do nothing
}
}
});
}
private void updateDebug(final String command, final String returned,
final Parameter... parameters) {
if (documentDebug.getLength() > 0) {
appendText(documentDebug, "\n", stylePunctuation);
}
appendText(documentDebug, command, styleCommand);
appendText(documentDebug, "(", stylePunctuation);
for (int i = 0; i < parameters.length; i++) {
appendText(documentDebug, parameters[i].getName(), styleParamName);
appendText(documentDebug, "=", stylePunctuation);
appendText(documentDebug, parameters[i].getValue(), styleParamValue);
if (i != parameters.length - 1) {
appendText(documentDebug, ", ", stylePunctuation);
}
}
appendText(documentDebug, ")", stylePunctuation);
if (returned != null) {
appendText(documentDebug, " = ", stylePunctuation);
appendText(documentDebug, "\"" + returned + "\"", styleReturn);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textPaneDebug.scrollRectToVisible(new Rectangle(0,
textPaneDebug.getHeight() * 2, 1, 1));
}
});
}
private void updateFieldsTable() {
((AbstractTableModel) fieldsTable.getModel()).fireTableDataChanged();
}
private Style getStyle(final Field f) {
final boolean isInput = f instanceof InputField;
if (isInput) {
final InputField inputField = (InputField) f;
if (inputField.isChanged()) {
return styleInputChanged;
} else {
return styleInput;
}
}
final int i = (f.getExtendedColor() == 0) ? 0
: f.getExtendedColor() - 0xf0;
Color foregroundColor = extendedColors[i];
Color backgroundColor = Color.black;
if (f.getExtendedHighlight() == Field.ATTR_EH_REV_VIDEO) {
final Color tmp = backgroundColor;
backgroundColor = foregroundColor;
foregroundColor = tmp;
}
boolean isUnderline = f.getExtendedHighlight() == Field.ATTR_EH_UNDERSCORE;
if (f.isIntensified()) {
foregroundColor = Color.white;
}
if (f.isHidden()) {
foregroundColor = Color.black;
backgroundColor = Color.black;
isUnderline = false;
}
return createStyle(foregroundColor, backgroundColor, isUnderline);
}
private void appendText(final DefaultStyledDocument doc, final String text,
final Style style) {
try {
doc.insertString(doc.getLength(), text, style);
} catch (final BadLocationException e) {
throw new RuntimeException(e);
}
}
private void createFrame(final String title) {
buildTextPane3270();
final JScrollPane tableScroller = buildFieldsTablePanel();
tabbedPane = new JTabbedPane();
tabbedPane.addTab("Terminal", null, textPane3270, "");
tabbedPane.addTab("Fields", null, tableScroller, "");
updateTabbedPaneSize();
final JPanel debugPanel = buildDebugPanel(monospacedFont, sansFont);
frame = new JFrame(title);
final Container contentPane = frame.getContentPane();
contentPane.setBackground(new Color(224, 224, 224));
contentPane.add(tabbedPane, BorderLayout.NORTH);
contentPane.add(debugPanel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void updateTabbedPaneSize() {
tabbedPane.setPreferredSize(new Dimension((int) textPane3270
.getPreferredSize().getWidth() + 40, (int) textPane3270
.getPreferredSize().getHeight() + 40));
}
private JPanel buildDebugPanel(final Font monospacedFont,
final Font sansFont) {
final JScrollPane textPaneDebugScroller = buildTextPaneDebug();
documentDebug = new DefaultStyledDocument();
textPaneDebug.setDocument(documentDebug);
final JPanel debugPanel = new JPanel();
final BoxLayout boxLayout = new BoxLayout(debugPanel,
BoxLayout.PAGE_AXIS);
debugPanel.setLayout(boxLayout);
debugPanel.setBackground(new Color(224, 224, 224));
debugPanel.setBorder(new EmptyBorder(3, 0, 0, 0));
debugPanel.add(textPaneDebugScroller);
return debugPanel;
}
private JScrollPane buildTextPaneDebug() {
textPaneDebug = createTextPane(sansFont, Color.white);
textPaneDebug.setAutoscrolls(true);
textPaneDebug.setBorder(new EmptyBorder(3, 3, 3, 3));
final FontMetrics fontMetricsSans = textPane3270
.getFontMetrics(monospacedFont);
final JScrollPane textPaneDebugScroller = new JScrollPane(textPaneDebug);
textPaneDebugScroller.setPreferredSize(new Dimension(textPane3270
.getWidth(), 3 + 10 * fontMetricsSans.getHeight()));
textPaneDebugScroller.setAlignmentX(JDialog.LEFT_ALIGNMENT);
textPaneDebugScroller.setBorder(new LineBorder(Color.gray));
textPaneDebugScroller.setAutoscrolls(true);
return textPaneDebugScroller;
}
private void buildTextPane3270() {
textPane3270 = createTextPane(monospacedFont, Color.black);
updateTextPane3270Size();
textPane3270.setAlignmentX(JDialog.LEFT_ALIGNMENT);
}
private boolean updateTextPane3270Size() {
final FontMetrics fontMetricsMonospaced = textPane3270
.getFontMetrics(monospacedFont);
int w = s3270.getScreen().getWidth();
int h = s3270.getScreen().getHeight();
if (w != currentWidth || h != currentHeight) {
textPane3270.setPreferredSize(new Dimension((w + 2)
* fontMetricsMonospaced.charWidth(' '), (h + 2)
* fontMetricsMonospaced.getHeight()));
currentWidth = w;
currentHeight = h;
return true;
}
return false;
}
private JScrollPane buildFieldsTablePanel() {
fieldsTable = new JTable(new AbstractTableModel() {
private static final long serialVersionUID = 5347188337180793036L;
private String[] columnNames = new String[] { "Id", "Type", "Value" };
public int getColumnCount() {
return 3;
}
public int getRowCount() {
try {
return s3270.getScreen().getFields().size();
} catch (Exception e) {
return 0;
}
}
@Override
public String getColumnName(final int column) {
return columnNames[column];
}
public Object getValueAt(final int rowIndex, final int columnIndex) {
if (columnIndex == 0) {
return rowIndex;
}
Field f;
try {
f = s3270.getScreen().getFields().get(rowIndex);
} catch (Exception e) {
// nasty hack to handle some random not connected exceptions from s3270
return "";
}
if (columnIndex == 1) {
return ((f instanceof InputField) ? "in" : "out")
+ (((f instanceof InputField) && ((InputField) f)
.isChanged()) ? " *" : "");
}
if (columnIndex == 2) {
return "[" + f.getValue().replace('\u0000', ' ') + "]";
}
throw new RuntimeException("unknown column index "
+ columnIndex);
}
public boolean isCellEditable(final int rowIndex,
final int columnIndex) {
return columnIndex == 2;
}
});
fieldsTable.getColumnModel().getColumn(0).setPreferredWidth(25);
fieldsTable.getColumnModel().getColumn(1).setPreferredWidth(35);
fieldsTable.getColumnModel().getColumn(2).setPreferredWidth(600);
// fieldsTable.setAutoCreateRowSorter(true);
final JScrollPane tableScroller = new JScrollPane(fieldsTable);
return tableScroller;
}
private JTextPane createTextPane(final Font font, final Color color) {
final JTextPane textPane = new JTextPane();
textPane.setFont(font);
textPane.setBackground(color);
textPane.setEditable(false);
return textPane;
}
private Style createStyle(final Color foregroundColor,
final Color backgrondColor, final boolean isItalic) {
final String key = String.format("%d-%d-%d %d-%d-%d %s",
foregroundColor.getRed(), foregroundColor.getGreen(),
foregroundColor.getBlue(), backgrondColor.getRed(),
backgrondColor.getGreen(), backgrondColor.getBlue(), isItalic);
Style style = stylesFlyweight.get(key);
if (style == null) {
style = StyleContext.getDefaultStyleContext().addStyle(null, null);
StyleConstants.setForeground(style, foregroundColor);
StyleConstants.setBackground(style, backgrondColor);
StyleConstants.setItalic(style, isItalic);
stylesFlyweight.put(key, style);
}
return style;
}
public void close() {
frame.setVisible(false);
}
}