// TextViewer.java package net.sf.gogui.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; /** Dialog for displaying text. Allows syntax highlighting for analyze commands of type <i>hstring</i>. */ public final class TextViewer extends JDialog { /** Callback for events generated by TextViewer. */ public interface Listener { /** Callback if some text is selected. If text is unselected again this function will be called with the complete text content of the window. */ void textSelected(String text); } public TextViewer(Frame owner, String title, String text, boolean highlight, Listener listener) { super(owner, title); initialize(text, highlight, listener); } public TextViewer(Dialog owner, String title, String text, boolean highlight, Listener listener) { super(owner, title); initialize(text, highlight, listener); } public void setText(String title, String text, boolean highlight) { setTitle(title); insertText(text); if (highlight) doSyntaxHighlight(); } private JTextPane m_textPane; private Listener m_listener; private void insertText(String text) { Document doc = m_textPane.getDocument(); while (text.charAt(text.length() - 1) == '\n') text = text.substring(0, text.length() - 1); try { doc.remove(0, doc.getLength()); doc.insertString(0, text, null); } catch (BadLocationException e) { assert false; } } private void doSyntaxHighlight() { GuiUtil.addStyle(m_textPane, "title", null, null, true); GuiUtil.addStyle(m_textPane, "point", new Color(0.25f, 0.5f, 0.7f)); GuiUtil.addStyle(m_textPane, "number", new Color(0f, 0.54f, 0f)); GuiUtil.addStyle(m_textPane, "const", new Color(0.8f, 0f, 0f)); GuiUtil.addStyle(m_textPane, "color", new Color(0.54f, 0f, 0.54f)); m_textPane.setEditable(true); highlight("number", "\\b-?\\d+\\.?\\d*([Ee][+-]\\d+)?\\b"); highlight("const", "\\b[A-Z_][A-Z_]+[A-Z]\\b"); highlight("color", "\\b([Bb][Ll][Aa][Cc][Kk]|[Ww][Hh][Ii][Tt][Ee])\\b"); highlight("point", "\\b([Pp][Aa][Ss][Ss]|[A-Ta-t](1\\d|[1-9]))\\b"); highlight("title", "^\\S+:(\\s|$)"); m_textPane.setEditable(false); } private void highlight(String styleName, String regex) { Document doc = m_textPane.getDocument(); Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); try { CharSequence text = doc.getText(0, doc.getLength()); Matcher matcher = pattern.matcher(text); while (matcher.find()) { int start = matcher.start(); int end = matcher.end(); GuiUtil.setStyle(m_textPane, start, end - start, styleName); } } catch (BadLocationException e) { assert false; } } private void initialize(String text, boolean highlight, Listener listener) { m_listener = listener; JPanel panel = new JPanel(new BorderLayout()); Container contentPane = getContentPane(); contentPane.add(panel, BorderLayout.CENTER); m_textPane = new JTextPane(); GuiUtil.setMonospacedFont(m_textPane); insertText(text); JScrollPane scrollPane = new JScrollPane(m_textPane); panel.add(scrollPane, BorderLayout.CENTER); setDefaultCloseOperation(DISPOSE_ON_CLOSE); KeyListener keyListener = new KeyAdapter() { public void keyReleased(KeyEvent e) { int c = e.getKeyCode(); if (c == KeyEvent.VK_ESCAPE) dispose(); } }; m_textPane.addKeyListener(keyListener); CaretListener caretListener = new CaretListener() { public void caretUpdate(CaretEvent event) { if (m_listener == null) return; int start = m_textPane.getSelectionStart(); int end = m_textPane.getSelectionEnd(); Document doc = m_textPane.getDocument(); try { if (start == end) { String text = doc.getText(0, doc.getLength()); m_listener.textSelected(text); return; } String text = doc.getText(start, end - start); m_listener.textSelected(text); } catch (BadLocationException e) { assert false; } } }; m_textPane.addCaretListener(caretListener); if (highlight) doSyntaxHighlight(); m_textPane.setCaretPosition(0); m_textPane.setEditable(false); packTextViewer(); } private void packTextViewer() { pack(); // Workaround for problems with oversized windows on some platforms // Also increase width by 10%, because automatic computation of // JTextPane/JTextArea width according to content text does not // work (maybe related to Sun Bug 4829215) Dimension size = getSize(); size.width *= 1.1; Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int maxHeight = (int)(0.9 * screenSize.height); int maxWidth = (int)(0.9 * screenSize.width); if (size.height > maxHeight || size.width > maxWidth) { size.width = Math.min(size.width, maxWidth); size.height = Math.min(size.height, maxHeight); } setMinimumSize(new Dimension(128, 96)); size.height = Math.max(size.height, 96); size.width = Math.max(size.width, 128); setPreferredSize(size); setSize(size); } }