// Comment.java package net.sf.gogui.gui; import java.awt.AWTKeyStroke; import java.awt.Color; import java.awt.Font; import java.awt.Dimension; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.UIManager; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import net.sf.gogui.util.Platform; /** Scroll pane for displaying a comment to the current game node. */ public class Comment extends JScrollPane implements DocumentListener { /** Callback for events generated by Comment. */ public interface Listener { void changed(String comment); /** Callback if some text is selected. */ void textSelected(String text); } public Comment(Listener listener) { m_listener = listener; m_textPane = new JTextPane(); setFocusTraversalKeys(m_textPane); GuiUtil.addStyle(m_textPane, "marked", Color.white, Color.decode("#38d878"), false); setPreferredSize(); m_textPane.getDocument().addDocumentListener(this); CaretListener caretListener = new CaretListener() { public void caretUpdate(CaretEvent event) { if (m_listener == null) return; m_listener.textSelected(m_textPane.getSelectedText()); } }; m_textPane.addCaretListener(caretListener); setViewportView(m_textPane); setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); if (Platform.isMac()) m_normalFont = new Font("Lucida Grande", Font.PLAIN, 11); else m_normalFont = UIManager.getFont("TextPane.font"); setMonoFont(false); } public void changedUpdate(DocumentEvent e) { fireChangedEvent(); } public boolean getMonoFont() { return m_monoFont; } public boolean getScrollableTracksViewportWidth() { return true; } public String getSelectedText() { return m_textPane.getSelectedText(); } public void insertUpdate(DocumentEvent e) { fireChangedEvent(); } public void markAll(Pattern pattern) { Document doc = m_textPane.getDocument(); try { CharSequence text = doc.getText(0, doc.getLength()); Matcher matcher = pattern.matcher(text); boolean firstMatch = true; while (matcher.find()) { int start = matcher.start(); int end = matcher.end(); if (firstMatch) { GuiUtil.setStyle(m_textPane, 0, doc.getLength(), null); m_textPane.setCaretPosition(start); firstMatch = false; } GuiUtil.setStyle(m_textPane, start, end - start, "marked"); } } catch (BadLocationException e) { assert false; } } public void removeUpdate(DocumentEvent e) { fireChangedEvent(); } /** Enable/disable fixed size font. */ public final void setMonoFont(boolean enable) { if (enable) GuiUtil.setMonospacedFont(m_textPane); else m_textPane.setFont(m_normalFont); m_monoFont = enable; m_textPane.repaint(); } public void setComment(String comment) { if (comment == null) comment = ""; if (comment.equals(m_textPane.getText())) return; // setText() generates a remove and insert event, and // we don't want to notify the listener about that yet m_duringSetText = true; m_textPane.setText(comment); m_textPane.setCaretPosition(0); m_duringSetText = false; } public final void setPreferredSize() { int fontSize = GuiUtil.getDefaultMonoFontSize(); setPreferredSize(new Dimension(15 * fontSize, 5 * fontSize)); } private boolean m_monoFont; private boolean m_duringSetText; private final JTextPane m_textPane; private final Listener m_listener; private final Font m_normalFont; private void fireChangedEvent() { if (m_duringSetText) return; String comment = m_textPane.getText(); m_listener.changed(comment); } private static void setFocusTraversalKeys(JTextPane textPane) { int id = KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS; Set<AWTKeyStroke> keystrokes = new HashSet<AWTKeyStroke>(); keystrokes.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0)); textPane.setFocusTraversalKeys(id, keystrokes); } }