package me.escapeNT.pail.Util; import java.awt.Color; import java.awt.EventQueue; import java.awt.Font; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.logging.Level; import javax.swing.BoundedRangeModel; import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.ScrollPaneConstants; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultCaret; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; /** * A simple text area contained within a autoscrolling pane. * @author escapeNT */ public class ScrollableTextArea extends JTextPane { private JScrollPane scroller; private boolean textSelected = false; public ScrollableTextArea() { scroller = new JScrollPane(this); scroller.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); scroller.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); setFont(new Font("SansSerif", Font.PLAIN, 12)); setContentType("charset=UTF-8"); setEditable(false); ((DefaultCaret)getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); getDocument().addDocumentListener(new ScrollingDocumentListener(this)); addMouseListener(new ConsoleMouseListener(this)); } /** * Appends the specified text to the pane with the provided color. * @param color The color of the text. * @param text The text to append. */ public void append(Color color, String text) { SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setForeground(sas, color); Document doc = getDocument(); try { doc.insertString(doc.getLength(), text, sas); } catch (BadLocationException ex) { Util.log(Level.SEVERE, ex.toString()); } } /** * Appends the specified text to the pane with the provided color. * @param color The color of the text. * @param bold True if the text will be bold. * @param text The text to append. */ public void append(Color color, boolean bold, String text) { SimpleAttributeSet sas = new SimpleAttributeSet(); StyleConstants.setBold(sas, bold); StyleConstants.setForeground(sas, color); Document doc = getDocument(); try { doc.insertString(doc.getLength(), text, sas); } catch (BadLocationException ex) { Util.log(Level.SEVERE, ex.toString()); } } /** * Returns the text area contained within its scroll pane. * @return the panel with scrollbar */ public JScrollPane getScrollerPanel() { return scroller; } /** * @return the textSelected */ public boolean isTextSelected() { return textSelected; } private class ConsoleMouseListener implements MouseListener { ScrollableTextArea a; public ConsoleMouseListener(ScrollableTextArea a) { this.a = a; } public void mouseReleased(MouseEvent e) { if(a.getSelectedText() != null) { textSelected = true; } else { textSelected = false; } Util.getFileMenu().getSaveSelection().setEnabled(textSelected); } public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } private class ScrollingDocumentListener implements DocumentListener { private ScrollableTextArea textArea; public ScrollingDocumentListener(ScrollableTextArea textArea) { this.textArea = textArea; } public void changedUpdate(DocumentEvent e) { maybeScrollToBottom(); } public void insertUpdate(DocumentEvent e) { maybeScrollToBottom(); } public void removeUpdate(DocumentEvent e) { maybeScrollToBottom(); } private void maybeScrollToBottom() { JScrollBar scrollBar = scroller.getVerticalScrollBar(); boolean scrollBarAtBottom = isScrollBarFullyExtended(scrollBar); if(scrollBarAtBottom) { EventQueue.invokeLater(new Runnable() { public void run() { EventQueue.invokeLater(new Runnable() { public void run() { scrollToBottom(textArea); } }); } }); } } } private static boolean isScrollBarFullyExtended(JScrollBar vScrollBar) { BoundedRangeModel model = vScrollBar.getModel(); return (model.getExtent() + model.getValue()) == model.getMaximum(); } private static void scrollToBottom(JComponent component) { Rectangle visibleRect = component.getVisibleRect(); visibleRect.y = component.getHeight() - visibleRect.height; component.scrollRectToVisible(visibleRect); } }