001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor.ext.java;
015:
016: import javax.swing.event.DocumentEvent;
017: import javax.swing.event.DocumentListener;
018: import javax.swing.text.BadLocationException;
019:
020: import org.netbeans.editor.Analyzer;
021: import org.netbeans.editor.BaseDocument;
022: import org.netbeans.editor.BaseDocumentEvent;
023: import org.netbeans.editor.Coloring;
024: import org.netbeans.editor.DrawContext;
025: import org.netbeans.editor.DrawLayer;
026: import org.netbeans.editor.FinderFactory;
027: import org.netbeans.editor.MarkFactory;
028: import org.netbeans.editor.TokenContextPath;
029:
030: /**
031: * Various java-layers
032: *
033: * @author Miloslav Metelka
034: * @version 1.00
035: */
036:
037: public class JavaDrawLayerFactory {
038:
039: public static final String JAVA_LAYER_NAME = "java-layer";
040:
041: public static final int JAVA_LAYER_VISIBILITY = 1010;
042:
043: /**
044: * Layer that colors extra java information like the methods or special
045: * characters in the character and string literals.
046: */
047: public static class JavaLayer extends DrawLayer.AbstractLayer {
048:
049: /**
050: * End of the area that is resolved right now. It saves repetitive
051: * searches for '(' for multiple fragments inside one identifier token.
052: */
053: private int resolvedEndOffset;
054:
055: private boolean resolvedValue;
056:
057: private NonWhitespaceFwdFinder nwFinder = new NonWhitespaceFwdFinder();
058:
059: public JavaLayer() {
060: super (JAVA_LAYER_NAME);
061: }
062:
063: public void init(DrawContext ctx) {
064: resolvedEndOffset = 0; // nothing resolved
065: }
066:
067: public boolean isActive(DrawContext ctx,
068: MarkFactory.DrawMark mark) {
069: int nextOffset = ctx.getTokenOffset()
070: + ctx.getTokenLength();
071:
072: setNextActivityChangeOffset(nextOffset);
073: return true;
074: }
075:
076: protected Coloring getMethodColoring(DrawContext ctx) {
077: TokenContextPath path = ctx.getTokenContextPath()
078: .replaceStart(JavaLayerTokenContext.contextPath);
079: return ctx
080: .getEditorUI()
081: .getColoring(
082: path
083: .getFullTokenName(JavaLayerTokenContext.METHOD));
084: }
085:
086: private boolean isMethod(DrawContext ctx) {
087: int idEndOffset = ctx.getTokenOffset()
088: + ctx.getTokenLength();
089: if (idEndOffset > resolvedEndOffset) { // beyond the resolved area
090: resolvedEndOffset = idEndOffset; // will resolve now
091: int endOffset = ctx.getEndOffset();
092: int bufferStartOffset = ctx.getBufferStartOffset();
093: char[] buffer = ctx.getBuffer();
094: int nwOffset = Analyzer.findFirstNonWhite(buffer,
095: idEndOffset - bufferStartOffset, endOffset
096: - idEndOffset);
097: if (nwOffset >= 0) { // found non-white
098: resolvedValue = (buffer[nwOffset] == '(');
099:
100: } else { // must resolve after buffer end
101: try {
102: resolvedValue = (ctx.getEditorUI()
103: .getDocument().find(nwFinder,
104: endOffset, -1) >= 0)
105: && (nwFinder.getFoundChar() == '(');
106: } catch (BadLocationException e) {
107: resolvedValue = false;
108: }
109: }
110: }
111:
112: return resolvedValue;
113: }
114:
115: public void updateContext(DrawContext ctx) {
116: if (ctx.getTokenID() == JavaTokenContext.IDENTIFIER
117: && isMethod(ctx)) {
118: Coloring mc = getMethodColoring(ctx);
119: if (mc != null) {
120: mc.apply(ctx);
121: }
122: }
123: }
124:
125: }
126:
127: /** Find first non-white character forward */
128: static class NonWhitespaceFwdFinder extends
129: FinderFactory.GenericFwdFinder {
130:
131: private char foundChar;
132:
133: public char getFoundChar() {
134: return foundChar;
135: }
136:
137: protected int scan(char ch, boolean lastChar) {
138: if (!Character.isWhitespace(ch)) {
139: found = true;
140: foundChar = ch;
141: return 0;
142: }
143: return 1;
144: }
145: }
146:
147: /** Find first non-white character backward */
148: public static class NonWhitespaceBwdFinder extends
149: FinderFactory.GenericBwdFinder {
150:
151: private char foundChar;
152:
153: public char getFoundChar() {
154: return foundChar;
155: }
156:
157: protected int scan(char ch, boolean lastChar) {
158: if (!Character.isWhitespace(ch)) {
159: found = true;
160: foundChar = ch;
161: return 0;
162: }
163: return -1;
164: }
165: }
166:
167: /**
168: * This class watches whether the '(' character was inserted/removed. It
169: * ensures the appropriate part of the document till the previous
170: * non-whitespace will be repainted.
171: */
172: public static class LParenWatcher implements DocumentListener {
173:
174: NonWhitespaceBwdFinder nwFinder = new NonWhitespaceBwdFinder();
175:
176: private void check(DocumentEvent evt) {
177: if (evt.getDocument() instanceof BaseDocument) {
178: BaseDocument doc = (BaseDocument) evt.getDocument();
179: BaseDocumentEvent bevt = (BaseDocumentEvent) evt;
180: char[] chars = bevt.getChars();
181: if (chars != null) {
182: boolean found = false;
183: for (int i = chars.length - 1; i >= 0; i--) {
184: if (chars[i] == '(') {
185: found = true;
186: break;
187: }
188: }
189:
190: if (found) {
191: int offset = evt.getOffset();
192: // Need to repaint
193: int redrawOffset = 0;
194: if (offset > 0) {
195: try {
196: redrawOffset = doc.find(nwFinder,
197: offset - 1, 0);
198: } catch (BadLocationException e) {
199: }
200:
201: if (redrawOffset < 0) { // not found non-whitespace
202: redrawOffset = 0;
203: }
204: }
205: doc.repaintBlock(redrawOffset, offset);
206: }
207: }
208: }
209: }
210:
211: public void insertUpdate(DocumentEvent evt) {
212: check(evt);
213: }
214:
215: public void removeUpdate(DocumentEvent evt) {
216: check(evt);
217: }
218:
219: public void changedUpdate(DocumentEvent evt) {
220: }
221:
222: }
223:
224: }
|