Java tutorial
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.text.MessageFormat; import java.util.Hashtable; import java.util.ResourceBundle; import java.util.Vector; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.LineStyleEvent; import org.eclipse.swt.custom.LineStyleListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; /** */ public class JavaViewer { Shell shell; StyledText text; JavaLineStyler lineStyler = new JavaLineStyler(); FileDialog fileDialog; Menu createFileMenu() { Menu bar = shell.getMenuBar(); Menu menu = new Menu(bar); MenuItem item; // Open item = new MenuItem(menu, SWT.CASCADE); item.setText("Open"); item.setAccelerator(SWT.MOD1 + 'O'); item.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { openFile(); } }); // Exit item = new MenuItem(menu, SWT.PUSH); item.setText("Exit"); item.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { menuFileExit(); } }); return menu; } void createMenuBar() { Menu bar = new Menu(shell, SWT.BAR); shell.setMenuBar(bar); MenuItem fileItem = new MenuItem(bar, SWT.CASCADE); fileItem.setText("File"); fileItem.setMenu(createFileMenu()); } void createShell(Display display) { shell = new Shell(display); shell.setText("Window"); GridLayout layout = new GridLayout(); layout.numColumns = 1; shell.setLayout(layout); shell.addShellListener(new ShellAdapter() { public void shellClosed(ShellEvent e) { lineStyler.disposeColors(); text.removeLineStyleListener(lineStyler); } }); } void createStyledText() { text = new StyledText(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL); GridData spec = new GridData(); spec.horizontalAlignment = GridData.FILL; spec.grabExcessHorizontalSpace = true; spec.verticalAlignment = GridData.FILL; spec.grabExcessVerticalSpace = true; text.setLayoutData(spec); text.addLineStyleListener(lineStyler); text.setEditable(false); Color bg = Display.getDefault().getSystemColor(SWT.COLOR_GRAY); text.setBackground(bg); } void displayError(String msg) { MessageBox box = new MessageBox(shell, SWT.ICON_ERROR); box.setMessage(msg); box.open(); } public static void main(String[] args) { Display display = new Display(); JavaViewer example = new JavaViewer(); Shell shell = example.open(display); while (!shell.isDisposed()) if (!display.readAndDispatch()) display.sleep(); display.dispose(); } public Shell open(Display display) { createShell(display); createMenuBar(); createStyledText(); shell.setSize(500, 400); shell.open(); return shell; } void openFile() { if (fileDialog == null) { fileDialog = new FileDialog(shell, SWT.OPEN); } fileDialog.setFilterExtensions(new String[] { "*.java", "*.*" }); String name = fileDialog.open(); open(name); } void open(String name) { final String textString; if ((name == null) || (name.length() == 0)) return; File file = new File(name); if (!file.exists()) { String message = "Err file no exist"; displayError(message); return; } try { FileInputStream stream = new FileInputStream(file.getPath()); try { Reader in = new BufferedReader(new InputStreamReader(stream)); char[] readBuffer = new char[2048]; StringBuffer buffer = new StringBuffer((int) file.length()); int n; while ((n = in.read(readBuffer)) > 0) { buffer.append(readBuffer, 0, n); } textString = buffer.toString(); stream.close(); } catch (IOException e) { // Err_file_io String message = "Err_file_io"; displayError(message); return; } } catch (FileNotFoundException e) { String message = "Err_not_found"; displayError(message); return; } // Guard against superfluous mouse move events -- defer action until // later Display display = text.getDisplay(); display.asyncExec(new Runnable() { public void run() { text.setText(textString); } }); // parse the block comments up front since block comments can go across // lines - inefficient way of doing this lineStyler.parseBlockComments(textString); } void menuFileExit() { shell.close(); } } /******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: IBM Corporation - initial API and implementation ******************************************************************************/ class JavaLineStyler implements LineStyleListener { JavaScanner scanner = new JavaScanner(); int[] tokenColors; Color[] colors; Vector blockComments = new Vector(); public static final int EOF = -1; public static final int EOL = 10; public static final int WORD = 0; public static final int WHITE = 1; public static final int KEY = 2; public static final int COMMENT = 3; public static final int STRING = 5; public static final int OTHER = 6; public static final int NUMBER = 7; public static final int MAXIMUM_TOKEN = 8; public JavaLineStyler() { initializeColors(); scanner = new JavaScanner(); } Color getColor(int type) { if (type < 0 || type >= tokenColors.length) { return null; } return colors[tokenColors[type]]; } boolean inBlockComment(int start, int end) { for (int i = 0; i < blockComments.size(); i++) { int[] offsets = (int[]) blockComments.elementAt(i); // start of comment in the line if ((offsets[0] >= start) && (offsets[0] <= end)) return true; // end of comment in the line if ((offsets[1] >= start) && (offsets[1] <= end)) return true; if ((offsets[0] <= start) && (offsets[1] >= end)) return true; } return false; } void initializeColors() { Display display = Display.getDefault(); colors = new Color[] { new Color(display, new RGB(0, 0, 0)), // black new Color(display, new RGB(255, 0, 0)), // red new Color(display, new RGB(0, 255, 0)), // green new Color(display, new RGB(0, 0, 255)) // blue }; tokenColors = new int[MAXIMUM_TOKEN]; tokenColors[WORD] = 0; tokenColors[WHITE] = 0; tokenColors[KEY] = 3; tokenColors[COMMENT] = 1; tokenColors[STRING] = 2; tokenColors[OTHER] = 0; tokenColors[NUMBER] = 0; } void disposeColors() { for (int i = 0; i < colors.length; i++) { colors[i].dispose(); } } /** * Event.detail line start offset (input) Event.text line text (input) * LineStyleEvent.styles Enumeration of StyleRanges, need to be in order. * (output) LineStyleEvent.background line background color (output) */ public void lineGetStyle(LineStyleEvent event) { Vector styles = new Vector(); int token; StyleRange lastStyle; // If the line is part of a block comment, create one style for the // entire line. if (inBlockComment(event.lineOffset, event.lineOffset + event.lineText.length())) { styles.addElement(new StyleRange(event.lineOffset, event.lineText.length(), getColor(COMMENT), null)); event.styles = new StyleRange[styles.size()]; styles.copyInto(event.styles); return; } Color defaultFgColor = ((Control) event.widget).getForeground(); scanner.setRange(event.lineText); token = scanner.nextToken(); while (token != EOF) { if (token == OTHER) { // do nothing for non-colored tokens } else if (token != WHITE) { Color color = getColor(token); // Only create a style if the token color is different than the // widget's default foreground color and the token's style is // not // bold. Keywords are bolded. if ((!color.equals(defaultFgColor)) || (token == KEY)) { StyleRange style = new StyleRange(scanner.getStartOffset() + event.lineOffset, scanner.getLength(), color, null); if (token == KEY) { style.fontStyle = SWT.BOLD; } if (styles.isEmpty()) { styles.addElement(style); } else { // Merge similar styles. Doing so will improve // performance. lastStyle = (StyleRange) styles.lastElement(); if (lastStyle.similarTo(style) && (lastStyle.start + lastStyle.length == style.start)) { lastStyle.length += style.length; } else { styles.addElement(style); } } } } else if ((!styles.isEmpty()) && ((lastStyle = (StyleRange) styles.lastElement()).fontStyle == SWT.BOLD)) { int start = scanner.getStartOffset() + event.lineOffset; lastStyle = (StyleRange) styles.lastElement(); // A font style of SWT.BOLD implies that the last style // represents a java keyword. if (lastStyle.start + lastStyle.length == start) { // Have the white space take on the style before it to // minimize the number of style ranges created and the // number of font style changes during rendering. lastStyle.length += scanner.getLength(); } } token = scanner.nextToken(); } event.styles = new StyleRange[styles.size()]; styles.copyInto(event.styles); } public void parseBlockComments(String text) { blockComments = new Vector(); StringReader buffer = new StringReader(text); int ch; boolean blkComment = false; int cnt = 0; int[] offsets = new int[2]; boolean done = false; try { while (!done) { switch (ch = buffer.read()) { case -1: { if (blkComment) { offsets[1] = cnt; blockComments.addElement(offsets); } done = true; break; } case '/': { ch = buffer.read(); if ((ch == '*') && (!blkComment)) { offsets = new int[2]; offsets[0] = cnt; blkComment = true; cnt++; } else { cnt++; } cnt++; break; } case '*': { if (blkComment) { ch = buffer.read(); cnt++; if (ch == '/') { blkComment = false; offsets[1] = cnt; blockComments.addElement(offsets); } } cnt++; break; } default: { cnt++; break; } } } } catch (IOException e) { // ignore errors } } /** * A simple fuzzy scanner for Java */ public class JavaScanner { protected Hashtable fgKeys = null; protected StringBuffer fBuffer = new StringBuffer(); protected String fDoc; protected int fPos; protected int fEnd; protected int fStartToken; protected boolean fEofSeen = false; private String[] fgKeywords = { "abstract", "boolean", "break", "byte", "case", "catch", "char", "class", "continue", "default", "do", "double", "else", "extends", "false", "final", "finally", "float", "for", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void", "volatile", "while" }; public JavaScanner() { initialize(); } /** * Returns the ending location of the current token in the document. */ public final int getLength() { return fPos - fStartToken; } /** * Initialize the lookup table. */ void initialize() { fgKeys = new Hashtable(); Integer k = new Integer(KEY); for (int i = 0; i < fgKeywords.length; i++) fgKeys.put(fgKeywords[i], k); } /** * Returns the starting location of the current token in the document. */ public final int getStartOffset() { return fStartToken; } /** * Returns the next lexical token in the document. */ public int nextToken() { int c; fStartToken = fPos; while (true) { switch (c = read()) { case EOF: return EOF; case '/': // comment c = read(); if (c == '/') { while (true) { c = read(); if ((c == EOF) || (c == EOL)) { unread(c); return COMMENT; } } } else { unread(c); } return OTHER; case '\'': // char const character: for (;;) { c = read(); switch (c) { case '\'': return STRING; case EOF: unread(c); return STRING; case '\\': c = read(); break; } } case '"': // string string: for (;;) { c = read(); switch (c) { case '"': return STRING; case EOF: unread(c); return STRING; case '\\': c = read(); break; } } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': do { c = read(); } while (Character.isDigit((char) c)); unread(c); return NUMBER; default: if (Character.isWhitespace((char) c)) { do { c = read(); } while (Character.isWhitespace((char) c)); unread(c); return WHITE; } if (Character.isJavaIdentifierStart((char) c)) { fBuffer.setLength(0); do { fBuffer.append((char) c); c = read(); } while (Character.isJavaIdentifierPart((char) c)); unread(c); Integer i = (Integer) fgKeys.get(fBuffer.toString()); if (i != null) return i.intValue(); return WORD; } return OTHER; } } } /** * Returns next character. */ protected int read() { if (fPos <= fEnd) { return fDoc.charAt(fPos++); } return EOF; } public void setRange(String text) { fDoc = text; fPos = 0; fEnd = fDoc.length() - 1; } protected void unread(int c) { if (c != EOF) fPos--; } } }