/* This file is part of jpcsp. Jpcsp 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. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jpcsp.log; import java.awt.Color; import java.awt.Image; import java.awt.Toolkit; import java.io.StringWriter; import java.net.URL; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import javax.swing.ImageIcon; import javax.swing.JTextPane; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.MutableAttributeSet; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import jpcsp.Emulator; import jpcsp.settings.Settings; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.spi.LoggingEvent; /** * <b>Experimental</b> TextPaneAppender. <br> * * * Created: Sat Feb 26 18:50:27 2000 <br> * * @author Sven Reimers */ public class TextPaneAppender extends AppenderSkeleton { JTextPane textpane; StyledDocument doc; StringWriter sw; ConcurrentHashMap<Level, MutableAttributeSet> attributes; ConcurrentHashMap<Level, ImageIcon> icons; private String label; private boolean fancy; final String LABEL_OPTION = "Label"; final String COLOR_OPTION_FATAL = "Color.Emerg"; final String COLOR_OPTION_ERROR = "Color.Error"; final String COLOR_OPTION_WARN = "Color.Warn"; final String COLOR_OPTION_INFO = "Color.Info"; final String COLOR_OPTION_DEBUG = "Color.Debug"; final String COLOR_OPTION_BACKGROUND = "Color.Background"; final String FANCY_OPTION = "Fancy"; final String FONT_NAME_OPTION = "Font.Name"; final String FONT_SIZE_OPTION = "Font.Size"; static final Level levels[] = {Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG, Level.TRACE}; public static Image loadIcon(String path) { Image img = null; try { URL url = ClassLoader.getSystemResource(path); img = (Toolkit.getDefaultToolkit()).getImage(url); } catch (Exception e) { Emulator.log.error("Exception occured: " + e.getMessage(), e); } return (img); } public TextPaneAppender(Layout layout, String name) { this(); this.layout = layout; this.name = name; setTextPane(new JTextPane()); createAttributes(); createIcons(); } public TextPaneAppender() { super(); setTextPane(new JTextPane()); createAttributes(); createIcons(); label = ""; sw = new StringWriter(); fancy = false; } @Override public void close() { } private void createAttributes() { attributes = new ConcurrentHashMap<Level, MutableAttributeSet>(); for (int i = 0; i < levels.length; i++) { MutableAttributeSet att = new SimpleAttributeSet(); attributes.put(levels[i], att); StyleConstants.setFontSize(att, Settings.getInstance().getFont().getSize()); StyleConstants.setFontFamily(att, Settings.getInstance().getFont().getFamily()); } StyleConstants.setForeground(attributes.get(Level.FATAL), Color.red); StyleConstants.setForeground(attributes.get(Level.ERROR), Color.red); StyleConstants.setForeground(attributes.get(Level.WARN), Color.orange); StyleConstants.setForeground(attributes.get(Level.INFO), Color.black); StyleConstants.setForeground(attributes.get(Level.DEBUG), Color.gray); StyleConstants.setForeground(attributes.get(Level.TRACE), Color.gray); } private void createIcons() { icons = new ConcurrentHashMap<Level, ImageIcon>(); } @Override public void append(LoggingEvent event) { String text = layout.format(event); String trace = ""; String keyword = Settings.getInstance().readString("log.keyword"); if (event.getThrowableInformation() != null) { String[] ts = event.getThrowableStrRep(); for (String s : ts) { sw.write(s); } for (int i = 0; i < sw.getBuffer().length(); i++) { if (sw.getBuffer().charAt(i) == '\t') { sw.getBuffer().replace(i, i + 1, " "); } } trace = sw.toString(); sw.getBuffer().delete(0, sw.getBuffer().length()); } try { synchronized (textpane) { if (fancy) { textpane.setEditable(true); textpane.insertIcon(icons.get(event.getLevel())); textpane.setEditable(false); } // Log everything if there's no keyword, or just log messages with the // specified keyword when it exists. if (keyword.equals("LOG_ALL") || (!keyword.equals("LOG_ALL") && text.contains(keyword))) { doc.insertString(doc.getLength(), text + trace, attributes.get(event.getLevel())); } int l = doc.getLength(); if (l > 30000) { doc.remove(0, l - 30000); } } } catch (BadLocationException badex) { System.err.println(badex); } textpane.setCaretPosition(doc.getLength()); } public JTextPane getTextPane() { return textpane; } private static Color parseColor(String v) { StringTokenizer st = new StringTokenizer(v, ","); int val[] = {255, 255, 255, 255}; int i = 0; while (st.hasMoreTokens()) { val[i] = Integer.parseInt(st.nextToken()); i++; } return new Color(val[0], val[1], val[2], val[3]); } private static String colorToString(Color c) { // alpha component emitted only if not default (255) String res = "" + c.getRed() + "," + c.getGreen() + "," + c.getBlue(); return c.getAlpha() >= 255 ? res : res + "," + c.getAlpha(); } @Override public void setLayout(Layout layout) { this.layout = layout; } @Override public void setName(String name) { this.name = name; } public void setTextPane(JTextPane textpane) { this.textpane = textpane; textpane.setEditable(false); doc = textpane.getStyledDocument(); } private void setColor(Level p, String v) { StyleConstants.setForeground(attributes.get(p), parseColor(v)); } private String getColor(Level p) { Color c = StyleConstants.getForeground(attributes.get(p)); return c == null ? null : colorToString(c); } public void setLabel(String label) { this.label = label; } public String getLabel() { return label; } public void setColorEmerg(String color) { setColor(Level.FATAL, color); } public String getColorEmerg() { return getColor(Level.FATAL); } public void setColorError(String color) { setColor(Level.ERROR, color); } public String getColorError() { return getColor(Level.ERROR); } public void setColorWarn(String color) { setColor(Level.WARN, color); } public String getColorWarn() { return getColor(Level.WARN); } public void setColorInfo(String color) { setColor(Level.INFO, color); } public String getColorInfo() { return getColor(Level.INFO); } public void setColorDebug(String color) { setColor(Level.DEBUG, color); } public String getColorDebug() { return getColor(Level.DEBUG); } public void setColorBackground(String color) { textpane.setBackground(parseColor(color)); } public String getColorBackground() { return colorToString(textpane.getBackground()); } public void setFancy(boolean fancy) { this.fancy = fancy; } public boolean getFancy() { return fancy; } public void setFontSize(int size) { Enumeration<MutableAttributeSet> e = attributes.elements(); while (e.hasMoreElements()) { StyleConstants.setFontSize(e.nextElement(), size); } } public int getFontSize() { AttributeSet attrSet = attributes.get(Level.INFO); return StyleConstants.getFontSize(attrSet); } public void setFontName(String name) { Enumeration<MutableAttributeSet> e = attributes.elements(); while (e.hasMoreElements()) { StyleConstants.setFontFamily(e.nextElement(), name); } } public String getFontName() { AttributeSet attrSet = attributes.get(Level.INFO); return StyleConstants.getFontFamily(attrSet); } @Override public boolean requiresLayout() { return true; } }