package eu.jucy.gui; import helpers.GH; import helpers.PreferenceChangedAdapter; import java.io.File; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.LinkedList; import java.util.List; import logger.LoggerFactory; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.spi.LoggingEvent; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.StatusLineManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import uc.DCClient.ILogEventListener; import uc.crypto.IHashEngine.IHashedListener; import uihelpers.SUIJob; import eu.jucy.gui.logeditor.LogEditor; import eu.jucy.gui.logeditor.LogEditorInput; import eu.jucy.gui.logeditor.OpenLogEditorHandler; /** * * A class to manage logging events that go to the gui.. * * * @author Quicksilver */ public class GuiAppender extends AppenderSkeleton implements ILogEventListener,IHashedListener { private static final int KEPT_MESSAGES = 100; private static final int MessagesShownInTooltip = 10; private SimpleDateFormat dateFormat; private boolean timeStamps; private IStatusLineManager statusline; private IWorkbenchWindow window; private SUIJob errorClear = null; private Layout severe = new PatternLayout("%-5p %F Line:%L \t\t %m%n"); //private final Control c; //for the ToolTip private final List<LoggingEvent> lastMessages = new LinkedList<LoggingEvent>(); private static class SingletonHolder { private static final GuiAppender singleton = new GuiAppender(); } public static GuiAppender get() { return SingletonHolder.singleton; } private GuiAppender() { new PreferenceChangedAdapter(GUIPI.get(),GUIPI.timeStampFormat) { @Override public void preferenceChanged(String preference, String oldValue,String newValue) { new SUIJob() { @Override public void run() { refreshSettings(); } }.schedule(); } }; refreshSettings(); } private void refreshSettings() { String format = GUIPI.get(GUIPI.timeStampFormat); if (format == null || GH.isEmpty(format)) { dateFormat = new SimpleDateFormat(); } else { dateFormat = new SimpleDateFormat(format); } timeStamps = GUIPI.getBoolean(GUIPI.timeStamps); } /** * very hacky method to make setting the StatusLineToolTip possible * * c.getChildren()[0] is instanceof CLabel * @param tooltip */ public void setToolTipToStatusLine(String tooltip) { Control c = getToolTipControl() ; if (c != null) { c.setToolTipText(tooltip); } } private Control getToolTipControl() { if (statusline instanceof StatusLineManager) { StatusLineManager slm = (StatusLineManager)statusline; Composite c = (Composite)slm.createControl(null); if (c.getChildren().length > 0) { return c.getChildren()[0]; } } return null; } /** * registers listener so doubleclick will open LogEditor * * @param statusline - the statusline where we can log to */ public void initialize(IStatusLineManager statusline) { this.statusline= statusline; this.window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); Control c = getToolTipControl(); if (c != null) { c.addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { OpenLogEditorHandler.openSystemLogEditor(); } }); } LoggerFactory.addAppender(this); ApplicationWorkbenchWindowAdvisor.get().addLogEventListener(this); } private final Logger logger = LoggerFactory.make(); public static final Level GUI = new Level(Level.INFO.toInt(),"GUI",Level.INFO.getSyslogEquivalent()){ private static final long serialVersionUID = 7946573916583631244L; } ; public void logEvent(String event) { logger.log(GUI, event); } public void hashed(File f, long duration,long remainingSize) { logger.log(GuiAppender.GUI,new TimeToken(duration,f,remainingSize)); } private void appendLE(final LoggingEvent event) { new SUIJob() { public void run() { lastMessages.add(event); while (lastMessages.size() > KEPT_MESSAGES) { lastMessages.remove(0); } if (window == null) { return; } IWorkbenchPage page = window.getActivePage(); if (page == null) { return; } LogEditor le =(LogEditor)page.findEditor(new LogEditorInput()); if (event.getLevel().isGreaterOrEqual(Level.WARN)) { statusline.setErrorMessage(severe.format(event)); //event.getRenderedMessage()); if (le == null) { OpenLogEditorHandler.openSystemLogEditor(); if (event.getLevel().isGreaterOrEqual(Level.ERROR)) { MessageDialog.openError(window.getShell(), event.getLevel().toString(), severe.format(event)); } } if (errorClear != null) { errorClear.cancel(); } errorClear = new SUIJob() { // "clear Error" public void run() { errorClear = null; statusline.setErrorMessage(null); } }; errorClear.schedule(1000 * 60 *5); } else { statusline.setMessage(getMessage(event)); } String tooltip = null; for (int i = Math.max(lastMessages.size()-MessagesShownInTooltip, 0); i < lastMessages.size(); i++) { if (tooltip == null) { tooltip = getMessage(lastMessages.get(i)); } else { tooltip += "\n"+getMessage(lastMessages.get(i)); } } setToolTipToStatusLine(tooltip); if (le != null) { le.append(event); } } }.schedule(); } /** * * when a LoggingEvent is received this will print it to the * StatusLine * * also the event will be redirected to an OpenLoggingEditor * if the event has at least Level Warn the editor will be * opened if it is not already open */ @Override protected void append(final LoggingEvent event) { if (event.getLevel().isGreaterOrEqual(Level.WARN)|| event.getLevel().equals(GUI)) { appendLE(event); } } @Override public void close() {} @Override public boolean requiresLayout() { return false; } /** * @return messages received in the past .. * up to the last 100 messages */ public List<LoggingEvent> getLastMessages() { return Collections.unmodifiableList(lastMessages); } private String getMessage(LoggingEvent event) { return (timeStamps? dateFormat.format(new Date(event.timeStamp)) : "" ) +event.getRenderedMessage(); } }