/* * Copyright (C) 2012 Jason Gedge <http://www.gedge.ca> * * This file is part of the OpGraph project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.gedge.opgraph.app.components; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import javax.swing.JEditorPane; import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; import ca.gedge.opgraph.Processor; /** * A component to show debug information on a node. */ public class ConsolePanel extends JEditorPane { /** Strong reference to processing context's logger */ private static final Logger processingContextLogger = Logger.getLogger(Processor.class.getName()); /** * A writer that outputs data to an HTML document. */ private static class HTMLDocumentWriter extends Writer { /** The HTML document to write to */ private HTMLDocument document; /** The HTML class used for this writer */ private String cssClass; /** The UL element storing lines */ private Element linesElement; /** The string buffer used to store lines */ private StringBuffer buffer; /** * Constructs a writer that writes to a document. * * @param document the document this writer will write to * @param cssClass CSS class to use for this writer */ public HTMLDocumentWriter(HTMLDocument document, String cssClass) { super(); this.buffer = new StringBuffer(); this.document = document; this.cssClass = (cssClass == null ? "" : cssClass); this.linesElement = document.getElement("lines"); } // // Writer // @Override public void close() throws IOException { this.document = null; } @Override public void flush() throws IOException { } @Override public void write(char [] cbuf, int off, int len) throws IOException { if(this.document == null) throw new IOException("Document is null"); buffer.append(cbuf, off, len); // Write at newlines final int pos = buffer.indexOf("\n", buffer.length() - len); if(pos > 0) { final String innerText = buffer.substring(0, pos); // TODO escape html final String itemText = String.format("<li class=\"%s\"><pre>%s</pre></li>", cssClass, innerText); buffer.delete(0, pos + 1); try { document.insertBeforeEnd(linesElement, itemText); } catch(BadLocationException exc) { throw new IOException("Could not write item", exc); } } } } /** Regular output stream */ private PrintWriter out; /** Error output stream */ private PrintWriter err; /** * Default constructor. */ public ConsolePanel() { // Set up editor kit final HTMLEditorKit kit = new HTMLEditorKit(); final StyleSheet style = kit.getStyleSheet(); style.addRule("body { padding: 0; margin: 0; }"); style.addRule("ul { margin: 0; padding: 0; list-style-type: none; }"); style.addRule("li { padding: 2px 5px; }"); style.addRule(".out { font-family: Courier,Courier New,Console,System; white-space: pre; }"); style.addRule(".err { font-family: Courier,Courier New,Console,System; color: #ff0000; background: #ffeeee; white-space: pre; }"); // Initialize setEditorKit(kit); setEditable(false); setText("<html><body><ul id=\"lines\"></ul></body></html>"); // Create streams final HTMLDocument document = (HTMLDocument)getDocument(); this.out = new PrintWriter(new HTMLDocumentWriter(document, "out")); this.err = new PrintWriter(new HTMLDocumentWriter(document, "err")); // processingContextLogger.addHandler(consoleHandler); } /** * Attaches this component to the given logger. * * @param logger the logger to attach to */ public void attachLogger(Logger logger) { logger.addHandler(consoleHandler); } /** * Attaches this component to the given logger. * * @param logger the logger to attach to */ public void detachLogger(Logger logger) { logger.removeHandler(consoleHandler); } // // Logging handler // private final Handler consoleHandler = new Handler() { @Override public void publish(LogRecord record) { if(record.getLevel().intValue() >= Level.SEVERE.intValue()) { err.println(record.getMessage()); } else { out.println(record.getMessage()); } } @Override public void flush() { out.flush(); err.flush(); } @Override public void close() throws SecurityException {} }; // // Overrides // @Override public boolean getScrollableTracksViewportWidth() { return (getUI().getPreferredSize(this).width <= getParent().getSize().width); } }