📄 logcanvas.java
字号:
package momelog.listener;import java.util.Vector;import javax.microedition.lcdui.Canvas;import javax.microedition.lcdui.CommandListener;import javax.microedition.lcdui.Displayable;import javax.microedition.lcdui.Font;import javax.microedition.lcdui.Graphics;import javax.microedition.lcdui.game.GameCanvas;import momelog.Configurable;import momelog.Formatter;import momelog.LogEvent;import momelog.LogListener;import momelog.Logger;/** * <p> * {@link LogListener} implementation intended to display formatted logging * events on device's or emulator's screen. {@link LogCanvas} extends * {@link GameCanvas}. It makes use of key events, and, of course, doesn't * suppress them. It's view consists of scrollable text area. It is refreshed on * every logging event's arrival. All formatted logging events are wrapped on * character basis and displayed on text area. Scrollbar is shown only, when * logging information occupies more than one page. Scrollbar's cursor has * different color at the edge positions (top and bottom) from that at the * middle, This indicates first and last (at that moment ;-)) line. See <a * href="../../../logcanvas-screenshots.html">LogCanvas Screen Shots</a>. Users * can scroll one line or page up or down, move to the top or bottom of logging, * toggle {@code fullscreen} mode or reset buffer by pressing only one key. Key * events are processed in separate thread (started when {@link LogCanvas} is * shown and stopped on hide). This eliminates conflicts with callbacks * processing thread and provides for better resources use. All logging events * are converted to strings and appended to the {@link StringBuffer}. Developer * can explore any logging event at any time. * </p> * <p> * {@link LogCanvas} can be used like any other {@link Displayable}. Developers * can (or even should) add/remove commands, set {@link CommandListener} or * title. {@link LogCanvas} is preset with the title of {@code "Logging"}. No * commands are added, and no {@link CommandListener} is set. It is initially * not in {@code fullscreen} mode. {@code fullscreen} mode of {@link LogCanvas} * can be changed at any time and it's view will be adjusted. * </p> * <p> * {@link LogCanvas} can be instantiated using {@code null-arg} constructor * {@link LogCanvas#LogCanvas()}. If {@code MoMELog} logging framework was * configured to use {@link LogCanvas} for processing logging events (see <a * href="../../../momelog-guide.html#config">MoMELog Guide</a>), * {@link LogCanvas} instance can be obtained by calling * {@link Logger#getLogListener()} static method. * </p> * <p> * {@link LogCanvas} is fully customizable. It provides means to completely * configure it's view and partly behavior. {@link LogCanvas} implements * {@link Configurable} interface. It can be configured declaratively from * character sequence and/or programmatically by using setter methods. See <a * href="../../../logcanvas-guide.html#config">LogCanvas Guide</a> for more * details. * </p> * <p> * Font used for rendering text can be set by using * {@link LogCanvas#setFont(Font)} method. Background or foreground colors can * be configured by calling {@link LogCanvas#setBgColor(int)} or * {@link LogCanvas#setFgColor(int)} respective methods. Developers can set * scrollbar, scrollbar's cursor at the middle positions or scrollbar's cursor * at the edge positions colors by invoking * {@link LogCanvas#setScrollbarColor(int)}, * {@link LogCanvas#setScrollbarCursorColor(int)} or * {@link LogCanvas#setScrollbarCursorEdgeColor(int)} respective methods. The * above methods should be called, when {@link LogCanvas} is hidden. In other * case these methods throw {@link IllegalStateException}. * </p> * <p> * As mentioned above, all logging information is saved in {@link StringBuffer}. * When dealing with very detailed logging and running application on device, * that restricts memory very much, there is possibility of memory shortage (I * didn't encounter such situations). In such situations, developers can reset * buffer by invoking {@link #resetBuffer()} method. This method actually * doesn't reset buffer, but frees buffer reference, sets a new one and runs * garbage collector (if property {@code runGCOnReset} is set to {@code true} * (the default)). Property {@code runGCOnReset} can be set or queried by * respective setter or getter methods ({@link #setRunGCOnReset(boolean)}, * {@link #isRunGCOnReset()}). * </p> * <p> * See <a href="../../../logcanvas-guide.html">LogCanvas Guide</a> for more * details about {@link LogCanvas}. * </p> * * @author Sergio Morozov * @version 1.0 */public class LogCanvas extends GameCanvas implements LogListener, Runnable, Configurable{ /** * Default font for rendering text ({@code proportional,plain.small}). * * @since 1.0 */ public static final Font DEFAULT_FONT = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL); /** * Default background color (<em>dark green</em>). * * @since 1.0 */ public static final int DEFAULT_BG_COLOR = 0x002F00; /** * Default foreground color (<em>white</em>). * * @since 1.0 */ public static final int DEFAULT_FG_COLOR = 0xFFFFFF; /** * Default scrollbar color (<em>green</em>). * * @since 1.0 */ public static final int DEFAULT_SCROLLBAR_COLOR = 0x00BF00; /** * Default color of scrollbar's cursor at the middle positions (<em>white</em>). * * @since 1.0 */ public static final int DEFAULT_SCROLLBAR_CURSOR_COLOR = 0xFFFFFF; /** * Default color of scrollbar's cursor at the edge positions (<em>red</em>). * * @since 1.0 */ public static final int DEFAULT_SCROLLBAR_CURSOR_EDGE_COLOR = 0xEF1F00; /** * TOP-LEFT anchor. */ private static final int TOP_LEFT = Graphics.TOP | Graphics.LEFT; private static final int RESET_KEY = Canvas.KEY_STAR; private static final int NEXT_LINE_KEY = Canvas.DOWN; private static final int PREV_LINE_KEY = Canvas.UP; private static final int NEXT_PAGE_KEY = Canvas.RIGHT; private static final int PREV_PAGE_KEY = Canvas.LEFT; private static final int BOTTOM_LINE_KEY = Canvas.KEY_NUM9; private static final int TOP_LINE_KEY = Canvas.KEY_NUM7; private static final int TOGGLE_FULLSCREEN_KEY = Canvas.KEY_NUM0; private static final Object RESET = new Object(); private static final Object NEXT_LINE = new Object(); private static final Object PREV_LINE = new Object(); private static final Object NEXT_PAGE = new Object(); private static final Object PREV_PAGE = new Object(); private static final Object BOTTOM_LINE = new Object(); private static final Object TOP_LINE = new Object(); private static final Object APPEND_LOG = new Object(); private static final Object TOGGLE_FULLSCREEN = new Object(); private boolean runGCOnReset = true; private StringBuffer text = null; private char[][] page = null; private int[] eols = null; private int shift; private int lpp = 0; private int lines = 0; private int vStart = 0; private boolean needScrollBar = false; private Font font = DEFAULT_FONT; private int fontHeight = DEFAULT_FONT.getHeight(); private Vector cmds; private Object executorLock = new Object(); private Thread runner = null; private boolean fullScreen = false; private int bgColor = DEFAULT_BG_COLOR; private int fgColor = DEFAULT_FG_COLOR; private int scrollBarColor = DEFAULT_SCROLLBAR_COLOR; private int scrollBarCursorColor = DEFAULT_SCROLLBAR_CURSOR_COLOR; private int scrollBarCursorEdgeColor = DEFAULT_SCROLLBAR_CURSOR_EDGE_COLOR; private int textWidthView = 0; private int width = 0; private int height = 0; private Graphics graphics = null; /** * Instantiates LogCanvas. Initializes it with title of {@code "Logging"}. */ public LogCanvas() { super(false); setTitle("Logging"); this.graphics = getGraphics(); this.text = new StringBuffer(); this.cmds = new Vector(); this.vStart = 0; sizeChanged(getWidth(), getHeight()); } /** * Returns {@link Graphics} instance associated with graphic buffer. * * @return {@link Graphics} instance associated with graphic buffer. */ protected Graphics graphics() { return this.graphics; } /** * Adjusts view, if the size has changed. * * @see javax.microedition.lcdui.Canvas#sizeChanged(int, int) */ protected void sizeChanged(int width, int height) { super.sizeChanged(width, height); if (this.height != height || this.width != width) { this.width = width; this.height = height; this.lpp = this.height / this.fontHeight; if (this.eols == null || this.eols.length <= this.lpp) { this.page = new char[this.lpp + 1][]; this.eols = new int[this.lpp + 1]; for (int i = this.lpp; i >= 0; i--) { char[] line = new char[32]; line[0] = 30; line[1] = 0; this.page[i] = line; } } initTextView(); } } /** * Resets logging buffer. This method frees reference to {@link StringBuffer} * containing formatted logging information, sets buffer to a newly * constructed {@link StringBuffer} and then, if {@code runGCOnReset} property * is set to {@code true} (default), runs garbage collector. * </p> * <p> * <strong>Note:</strong> All of these operations are performed in a separate * thread. * </p> * <p> * <strong>Note:</strong> These operations are performed only when key events * processing thread is running (i.e. {@link LogCanvas} is shown). If this * method is called, when {@link LogCanvas} is hidden, it queues the * respective command and returns immediately. Buffer reset will occur after * {@link LogCanvas} displaying. * </p> */ public void resetBuffer() { pushCommand(RESET); } /** * Resets logging buffer. freeing memory allocated for it. After that, if * {@code runGCOnReset} property is set to {@code true} (default). runs * garbage collector. */ protected void resetLogging() { this.text = new StringBuffer(); this.vStart = 0; initTextView(); if (this.runGCOnReset) System.gc(); } /** * Toggles {@code fullscreen} mode. */ protected void toggleFullScreenMode() { setFullScreenMode(this.fullScreen = !this.fullScreen); } /* * (non-Javadoc) * * @see javax.microedition.lcdui.Canvas#setFullScreenMode(boolean) */ public void setFullScreenMode(boolean mode) { this.fullScreen = mode; super.setFullScreenMode(mode); } /** * Sets whether garbage collector should be run after buffer reset. This method * can be called at any time even when {@link LogCanvas} is shown. * * @param runGCOnReset * if {@code true} garbage collector should be run after buffer reset, * not otherwise. */ public void setRunGCOnReset(boolean runGCOnReset) { this.runGCOnReset = runGCOnReset; } /** * Tests whether garbage collector is running run after buffer reset. * * @return {@code true} if garbage collector is running after buffer reset, * {@code false} otherwise. */ public boolean isRunGCOnReset() { return this.runGCOnReset; } /** * Sets background color of text. This method must be called, when * {@link LogCanvas} is hidden. * * @param color * color to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setBgColor(int color) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.bgColor = color; } /** * Sets foreground color of text. This method must be called, when * {@link LogCanvas} is hidden. * * @param color * color to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setFgColor(int color) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.fgColor = color; } /** * Sets color of scrollbar. This method must be called, when {@link LogCanvas} * is hidden. * * @param color * color to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setScrollbarColor(int color) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.scrollBarColor = color; } /** * Sets color of scrollbar's cursor at the middle positions. This method must * be called, when {@link LogCanvas} is hidden. * * @param color * color to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setScrollbarCursorColor(int color) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.scrollBarCursorColor = color; } /** * Sets color of scrollbar's cursor at the edge positions. This method must be * called, when {@link LogCanvas} is hidden. * * @param color * color to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setScrollbarCursorEdgeColor(int color) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.scrollBarCursorEdgeColor = color; } /** * Sets font for rendering text. This method must be called, when * {@link LogCanvas} is hidden. * * @param font * font to set. * @throws IllegalStateException * if {@link LogCanvas} is shown. */ public void setFont(Font font) { if (isShown()) throw new IllegalStateException("Attempt to configure shown LogCanvas."); this.font = (font != null ? font : DEFAULT_FONT); this.fontHeight = this.font.getHeight(); this.lpp = this.height / this.fontHeight; initTextView(); } /** * Returns line at specified position. * * @param i * position of line to return. * @return line at {@code i} position. */ private char[] getLine(int i) { return this.page[getLinePos(i)]; } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -