summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java b/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java
new file mode 100644
index 00000000..058ac207
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/gui/util/LogPane.java
@@ -0,0 +1,251 @@
+package de.lmu.ifi.dbs.elki.gui.util;
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2011
+Ludwig-Maximilians-Universität München
+Lehr- und Forschungseinheit für Datenbanksysteme
+ELKI Development Team
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import java.awt.Color;
+import java.util.logging.ErrorManager;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.SimpleFormatter;
+
+import javax.swing.JTextPane;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+
+import de.lmu.ifi.dbs.elki.logging.LoggingConfiguration;
+import de.lmu.ifi.dbs.elki.logging.MessageFormatter;
+import de.lmu.ifi.dbs.elki.logging.OutputStreamLogger;
+import de.lmu.ifi.dbs.elki.logging.progress.ProgressLogRecord;
+
+/**
+ * A Swing object to receive ELKI logging output. Call
+ * {@link #becomeDefaultLogger()} to register as default logger in ELKI.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.uses LoggingConfiguration
+ * @apiviz.uses de.lmu.ifi.dbs.elki.logging.ELKILogRecord
+ * @apiviz.uses ProgressLogRecord
+ */
+public class LogPane extends JTextPane {
+ /**
+ * Serialization version number
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Base (default) style
+ */
+ protected Style baseStyle;
+
+ /**
+ * Regular message style
+ */
+ protected Style msgStyle;
+
+ /**
+ * Debug message style
+ */
+ protected Style dbgStyle;
+
+ /**
+ * Error message style
+ */
+ protected Style errStyle;
+
+ /**
+ * Formatter for regular messages (informational records)
+ */
+ private Formatter msgformat = new MessageFormatter();
+
+ /**
+ * Formatter for debugging messages
+ */
+ private Formatter debugformat = new SimpleFormatter();
+
+ /**
+ * Formatter for error messages
+ */
+ private Formatter errformat = new SimpleFormatter();
+
+ /**
+ * Last newline position
+ */
+ private int lastNewlinePos = 0;
+
+ /**
+ * Constructor
+ */
+ public LogPane() {
+ super();
+ // setup styles
+ baseStyle = getStyledDocument().addStyle(null, null);
+ msgStyle = getStyledDocument().addStyle("msg", baseStyle);
+ errStyle = getStyledDocument().addStyle("err", baseStyle);
+ errStyle.addAttribute(StyleConstants.Foreground, Color.RED);
+ dbgStyle = getStyledDocument().addStyle("err", baseStyle);
+ dbgStyle.addAttribute(StyleConstants.Foreground, Color.BLUE);
+ }
+
+ /**
+ * Print a message as if it were logged, without going through the full
+ * logger.
+ *
+ * @param message Message text
+ * @param level Message level
+ */
+ public void publish(String message, Level level) {
+ try {
+ publish(new LogRecord(level, message));
+ }
+ catch(Exception e) {
+ throw new RuntimeException("Error writing a log-like message.", e);
+ }
+ }
+
+ /**
+ * Publish a log record to the logging pane.
+ *
+ * @param record Log record
+ * @throws Exception
+ */
+ protected synchronized void publish(LogRecord record) throws Exception {
+ // choose an appropriate formatter
+ final Formatter fmt;
+ final Style style;
+ // always format progress messages using the progress formatter.
+ if(record.getLevel().intValue() >= Level.WARNING.intValue()) {
+ // format errors using the error formatter
+ fmt = errformat;
+ style = errStyle;
+ }
+ else if(record.getLevel().intValue() <= Level.FINE.intValue()) {
+ // format debug statements using the debug formatter.
+ fmt = debugformat;
+ style = dbgStyle;
+ }
+ else {
+ // default to the message formatter.
+ fmt = msgformat;
+ style = msgStyle;
+ }
+ // format
+ final String m;
+ m = fmt.format(record);
+ if(record instanceof ProgressLogRecord) {
+ if(lastNewlinePos < getStyledDocument().getLength()) {
+ getStyledDocument().remove(lastNewlinePos, getStyledDocument().getLength() - lastNewlinePos);
+ }
+ }
+ else {
+ // insert a newline, if we didn't see one yet.
+ if(lastNewlinePos < getStyledDocument().getLength()) {
+ getStyledDocument().insertString(getStyledDocument().getLength(), "\n", style);
+ lastNewlinePos = getStyledDocument().getLength();
+ }
+ }
+ int tail = tailingNonNewline(m, 0, m.length());
+ int headlen = m.length() - tail;
+ if(headlen > 0) {
+ String pre = m.substring(0, headlen);
+ getStyledDocument().insertString(getStyledDocument().getLength(), pre, style);
+ }
+ lastNewlinePos = getStyledDocument().getLength();
+ if(tail > 0) {
+ String post = m.substring(m.length() - tail);
+ getStyledDocument().insertString(lastNewlinePos, post, style);
+ }
+ }
+
+ /**
+ * Count the tailing non-newline characters.
+ *
+ * @param str String
+ * @param off Offset
+ * @param len Range
+ * @return number of tailing non-newline character
+ */
+ private int tailingNonNewline(String str, int off, int len) {
+ for(int cnt = 0; cnt < len; cnt++) {
+ final int pos = off + (len - 1) - cnt;
+ if(str.charAt(pos) == OutputStreamLogger.UNIX_NEWLINE) {
+ return cnt;
+ }
+ // TODO: need to compare to NEWLINE, too?
+ }
+ return len;
+ }
+
+ /**
+ * Clear the current contents.
+ */
+ public void clear() {
+ setText("");
+ lastNewlinePos = 0;
+ }
+
+ /**
+ * Become the default logger.
+ */
+ public void becomeDefaultLogger() {
+ LoggingConfiguration.replaceDefaultHandler(new LogPaneHandler());
+ }
+
+ /**
+ * Internal {@link java.util.logging.Handler}
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ private class LogPaneHandler extends Handler {
+ /**
+ * Constructor.
+ */
+ protected LogPaneHandler() {
+ super();
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ // do nothing
+ }
+
+ @Override
+ public void flush() {
+ // do nothing
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ try {
+ LogPane.this.publish(record);
+ }
+ catch(Exception e) {
+ reportError("Error printing output log message.", e, ErrorManager.GENERIC_FAILURE);
+ }
+ }
+ }
+}