package org.buzztroll.mud; import javax.swing.*; import javax.swing.text.*; import javax.swing.text.html.*; import javax.swing.border.*; import java.awt.*; import java.awt.event.*; import java.lang.*; import java.util.*; import java.text.*; public class TextDisplay extends DisplayInterface implements ComponentListener, MouseMotionListener, MouseListener, AdjustmentListener { protected TextCanvas textPane; protected DefaultStyledDocument doc; protected StyleSheet sc; protected JScrollPane scrollPane; protected Font defaultFont = null; protected Color backgroundColor = Color.black; protected Point lastMousePosition = null; private String ls = null; private ConfigFrame configFrame; public TextDisplay(ConfigFrame configFrame) { this.configFrame = configFrame; ls = System.getProperty("line.separator"); MutableAttributeSet attr; attr = new SimpleAttributeSet(); StyleConstants.ColorConstants.setBackground(attr, backgroundColor); StyleConstants.setBackground(attr, backgroundColor); sc = new StyleSheet(); doc = new DefaultStyledDocument(sc); this.setBackground(Color.black); this.setLayout(new BorderLayout()); textPane = new TextCanvas(doc); textPane.setCharacterAttributes(attr, true); textPane.setOpaque(true); textPane.setEditable(false); textPane.setBackground(backgroundColor); textPane.setForeground(backgroundColor); this.setBackground(Color.black); this.setOpaque(false); this.addComponentListener(this); textPane.addComponentListener(this); scrollPane = new JScrollPane(textPane); scrollPane.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBackground(Color.black); scrollPane.setOpaque(false); scrollPane.getVerticalScrollBar().addAdjustmentListener(this); int fontSize = StyleConstants.FontConstants.getFontSize(attr); String fontName = StyleConstants.FontConstants.getFontFamily(attr); defaultFont = new Font(fontName, Font.PLAIN, fontSize); this.add("Center", scrollPane); textPane.addMouseMotionListener(this); textPane.addMouseListener(this); bottomOut(); } public void setBackgroundColor(Color color) { this.backgroundColor = color; textPane.setBackground(backgroundColor); textPane.setForeground(backgroundColor); } public void addMouseListener( MouseListener l) { super.addMouseListener(l); textPane.addMouseListener(l); } public void addMessage( DisplayMessage dm) { String message; Color color; MutableAttributeSet attr; int start; String fontName; int fontSize; FontMetrics fm; Font f; message = dm.getString(); color = dm.getColor(); if(message == null || message.equals("")) { return; } start = doc.getLength(); attr = new SimpleAttributeSet(); StyleConstants.ColorConstants.setForeground(attr, color); StyleConstants.ParagraphConstants.setLineSpacing(attr, 5.0f); f = dm.getFont(); if(f == null) { f = defaultFont; } fontSize = f.getSize(); fontName = f.getFamily(); StyleConstants.FontConstants.setFontFamily(attr, fontName); StyleConstants.FontConstants.setFontSize(attr, fontSize); StyleConstants.FontConstants.setBold(attr, f.isBold()); StyleConstants.FontConstants.setItalic(attr, f.isItalic()); try { //textPane.repaint(); if (start == 0) { doc.insertString(start, message, attr); } else { doc.insertString(start, ls + message, attr); } } catch(BadLocationException e) { System.err.println(e); // e.printStackTrace(); } repaint(); } public void adjustmentValueChanged( AdjustmentEvent e) { } public void paintComponent( Graphics g) { super.paintComponent(g); bottomOut(); } public void setFont( Font f) { this.defaultFont = f; } public void clear() { textPane.setText(""); } public Font getFont() { return this.defaultFont; } protected void bottomOut() { JScrollBar jsb; jsb = scrollPane.getVerticalScrollBar(); jsb.setValue(jsb.getMaximum()); } public void componentHidden(ComponentEvent e) { } public void componentMoved(ComponentEvent e) { } public void componentResized(ComponentEvent e) { bottomOut(); } public void componentShown(ComponentEvent e) { bottomOut(); } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent event) {} public void mouseReleased(MouseEvent e) {} public void mouseClicked(MouseEvent e) { if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) == 0) { checkLinkClick(e); } } private void checkLinkClick(MouseEvent event) { String url = getText(event.getPoint()); if (url == null || url.indexOf("://") == -1) { return; } if (url.charAt(0) == '"' || url.charAt(0) == '\'') { url = url.substring(1); } int len = url.length(); if (len > 0 && (url.charAt(len-1) == '"' || url.charAt(len-1) == '\'')) { url = url.substring(0, len-1); } String cmdstr = this.configFrame.getUrlViewerCmd(); if (cmdstr == null || cmdstr.length() == 0) { // FIXME: display error? System.err.println("Url viewer cmd not defined"); return; } // on windows: rundll32 url.dll,FileProtocolHandler {0} String cmd = MessageFormat.format(cmdstr, new Object [] {url}); try { Process child = Runtime.getRuntime().exec(cmd); } catch (Exception e) { System.err.println("Error starting external viewer: " + e.getMessage()); e.printStackTrace(); } } public String getText() { return getText(lastMousePosition); } public String getText(Point p) { int pos = textPane.viewToModel(p); try { if (Character.isWhitespace(doc.getText(pos, 1).charAt(0))) { return null; } } catch (Exception ex) { return null; } // we should be over some text definitely now Element elem = doc.getParagraphElement(pos); int start = elem.getStartOffset(); int end = elem.getEndOffset(); int parOff = pos-start; String line = null; try { line = doc.getText(start, end-start); } catch (Exception ee) { return null; } int i = parOff; while( i < line.length() && !Character.isWhitespace(line.charAt(i)) ) { i++; } end = i; i = parOff; while( i > 0 && line.charAt(i-1) != ' ') { i--; } start = i; return line.substring(start, end); } class TextCanvas extends JTextPane { public TextCanvas( StyledDocument doc) { super(); this.setDocument(doc); this.setOpaque(true); this.setBackground(backgroundColor); } } // highlighting code public void mouseMoved(MouseEvent event) { lastMousePosition = event.getPoint(); int pos = textPane.viewToModel(lastMousePosition); try { if (Character.isWhitespace(doc.getText(pos, 1).charAt(0))) { if (highlight != null) { MutableAttributeSet attr = highlight.getAttribute(); StyleConstants.setUnderline(attr, false); doc.setCharacterAttributes(highlight.getPosition(), highlight.getLength(), attr, false); highlight = null; } return; } } catch (Exception ex) { return; } // we should be over some text definitely now if (highlight != null) { if (highlight.isHighlighted(pos)) { return; } else { MutableAttributeSet attr = highlight.getAttribute(); StyleConstants.setUnderline(attr, false); doc.setCharacterAttributes(highlight.getPosition(), highlight.getLength(), attr, false); highlight = null; } } Element elem = doc.getParagraphElement(pos); int start = elem.getStartOffset(); int end = elem.getEndOffset(); String line = null; try { line = doc.getText(start, end-start); } catch (Exception ee) { return; } int parOff = pos-start; int i = parOff; while( i < line.length() && !Character.isWhitespace(line.charAt(i)) ) { i++; } end = i; i = parOff; while( i > 0 && line.charAt(i-1) != ' ') { i--; } start = i; line = line.substring(start, end); // not an url if (line.indexOf("://") == -1) { return; } if (highlight == null) { highlight = new Highlight(); } MutableAttributeSet attr = new SimpleAttributeSet(elem.getAttributes()); highlight.setPosition(pos - (parOff -start)); highlight.setLength(end-start); highlight.setAttribute(attr); StyleConstants.setUnderline(attr, true); doc.setCharacterAttributes(pos - (parOff -start), end-start, attr, false); } public void mouseDragged(MouseEvent event) {} Highlight highlight; class Highlight { int pos; int len; MutableAttributeSet attr; public void setPosition(int pos) { this.pos = pos; } public void setLength(int len) { this.len = len; } public int getLength() { return this.len; } public int getPosition() { return this.pos; } public void setAttribute(MutableAttributeSet attr) { this.attr = attr; } public MutableAttributeSet getAttribute() { return this.attr; } public boolean isHighlighted(int off) { return (off > pos && off < pos + len); } } }