001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.gsfret.editor.semantic;
042:
043: import java.awt.Color;
044: import java.io.IOException;
045: import java.util.Collection;
046: import java.util.Collections;
047: import java.util.HashSet;
048: import java.util.List;
049: import java.util.Map;
050: import java.util.Set;
051: import java.util.logging.Level;
052: import java.util.logging.Logger;
053: import javax.swing.text.Document;
054: import org.netbeans.editor.BaseDocument;
055: import org.netbeans.modules.gsf.api.OffsetRange;
056: import org.netbeans.modules.gsf.api.CancellableTask;
057: import org.netbeans.modules.gsf.api.ColoringAttributes;
058: import org.netbeans.modules.gsf.api.OccurrencesFinder;
059: import org.netbeans.napi.gsfret.source.CompilationInfo;
060: import org.netbeans.modules.editor.highlights.spi.Highlight;
061: import org.netbeans.modules.editor.highlights.spi.Highlighter;
062: import org.netbeans.modules.gsf.Language;
063: import org.netbeans.modules.gsf.LanguageRegistry;
064: import org.openide.ErrorManager;
065: import org.openide.cookies.EditorCookie;
066: import org.openide.filesystems.FileObject;
067: import org.openide.filesystems.FileUtil;
068: import org.openide.loaders.DataObject;
069:
070: /**
071: * This file is originally from Retouche, the Java Support
072: * infrastructure in NetBeans. I have modified the file as little
073: * as possible to make merging Retouche fixes back as simple as
074: * possible.
075: *
076: *
077: * @author Jan Lahoda
078: */
079: public class MarkOccurencesHighlighter implements
080: CancellableTask<CompilationInfo> {
081:
082: private FileObject file;
083:
084: /** Creates a new instance of SemanticHighlighter */
085: MarkOccurencesHighlighter(FileObject file) {
086: this .file = file;
087: }
088:
089: public static final Color ES_COLOR = new Color(175, 172, 102); // new Color(244, 164, 113);
090:
091: public Document getDocument() {
092: try {
093: DataObject d = DataObject.find(file);
094: EditorCookie ec = (EditorCookie) d
095: .getCookie(EditorCookie.class);
096:
097: if (ec == null)
098: return null;
099:
100: return ec.getDocument();
101: } catch (IOException e) {
102: Logger.global.log(Level.INFO,
103: "SemanticHighlighter: Cannot find DataObject for file: "
104: + FileUtil.getFileDisplayName(file), e);
105: return null;
106: }
107: }
108:
109: public void run(CompilationInfo info) {
110: resume();
111:
112: Document doc = getDocument();
113:
114: if (doc == null) {
115: Logger.global.log(Level.INFO,
116: "MarkOccurencesHighlighter: Cannot get document!");
117: return;
118: }
119:
120: long start = System.currentTimeMillis();
121:
122: int caretPosition = MarkOccurrencesHighlighterFactory
123: .getLastPosition(file);
124:
125: if (isCancelled())
126: return;
127:
128: Set<Highlight> highlights = processImpl(info, doc,
129: caretPosition);
130:
131: if (isCancelled())
132: return;
133:
134: //TimesCollector.getDefault().reportTime(((DataObject) doc.getProperty(Document.StreamDescriptionProperty)).getPrimaryFile(), "occurrences", "Occurrences", (System.currentTimeMillis() - start));
135:
136: Highlighter.getDefault().setHighlights(file, "occurrences",
137: highlights);
138: OccurrencesMarkProvider.get(doc).setOccurrences(highlights);
139: }
140:
141: // private boolean isIn(CompilationUnitTree cu, SourcePositions sp, Tree tree, int position) {
142: // return sp.getStartPosition(cu, tree) <= position && position <= sp.getEndPosition(cu, tree);
143: // }
144: //
145: private boolean isIn(int caretPosition, int[] span) {
146: return span[0] <= caretPosition && caretPosition <= span[1];
147: }
148:
149: Set<Highlight> processImpl(CompilationInfo info, Document doc,
150: int caretPosition) {
151: Set<Highlight> localUsages = null;
152:
153: List<Language> list = LanguageRegistry
154: .getInstance()
155: .getEmbeddedLanguages((BaseDocument) doc, caretPosition);
156: Language language = null;
157: for (Language l : list) {
158: if (l.getOccurrencesFinder() != null) {
159: language = l;
160: break;
161: }
162: }
163:
164: if (language != null) {
165: OccurrencesFinder finder = language.getOccurrencesFinder();
166: assert finder != null;
167:
168: finder.setCaretPosition(caretPosition);
169: OccurrencesFinder task = finder;
170: if (task != null) {
171: try {
172: task.run(info);
173: } catch (Exception ex) {
174: ErrorManager.getDefault().notify(ex);
175: }
176:
177: if (isCancelled()) {
178: task.cancel();
179: }
180:
181: Map<OffsetRange, ColoringAttributes> highlights = task
182: .getOccurrences();
183: if (highlights != null) {
184: for (OffsetRange range : highlights.keySet()) {
185: if (isCancelled())
186: return Collections.EMPTY_SET;
187:
188: ColoringAttributes colors = highlights
189: .get(range);
190: //Collection<ColoringAttributes> c = EnumSet.copyOf(set);
191: Collection<ColoringAttributes> c = Collections
192: .singletonList(colors);
193: Highlight h = Utilities.createHighlight(
194: language, doc, range.getStart(), range
195: .getEnd(), c, null);
196:
197: if (h != null) {
198: if (localUsages == null) {
199: localUsages = new HashSet<Highlight>();
200: }
201: localUsages.add(h);
202: }
203: }
204: }
205: }
206: }
207:
208: // CompilationUnitTree cu = info.getCompilationUnit();
209: // Tree lastTree = null;
210: // TreePath tp = info.getTreeUtilities().pathFor(caretPosition);
211: // while(tp != null) {
212: // if (isCancelled())
213: // return Collections.emptySet();
214: //
215: // Tree tree = tp.getLeaf();
216: // //detect caret inside the return type or throws clause:
217: // if (tree instanceof MethodTree && (lastTree instanceof IdentifierTree
218: // || lastTree instanceof PrimitiveTypeTree
219: // || lastTree instanceof MemberSelectTree)) {
220: // //hopefully found something, check:
221: // MethodTree decl = (MethodTree) tree;
222: // Tree type = decl.getReturnType();
223: //
224: // if (isIn(cu, info.getTrees().getSourcePositions(), type, caretPosition)) {
225: // MethodExitDetector med = new MethodExitDetector();
226: //
227: // setExitDetector(med);
228: //
229: // try {
230: // return med.process(info, doc, decl, null);
231: // } finally {
232: // setExitDetector(null);
233: // }
234: // }
235: //
236: // for (Tree exc : decl.getThrows()) {
237: // if (isIn(cu, info.getTrees().getSourcePositions(), exc, caretPosition)) {
238: // MethodExitDetector med = new MethodExitDetector();
239: //
240: // setExitDetector(med);
241: //
242: // try {
243: // return med.process(info, doc, decl, Collections.singletonList(exc));
244: // } finally {
245: // setExitDetector(null);
246: // }
247: // }
248: // }
249: // }
250: //
251: // if (localUsages != null)
252: // return localUsages;
253: //
254: // //variable declaration:
255: // Element el = info.getTrees().getElement(tp);
256: // if ( el != null
257: // && (!(tree instanceof ClassTree) || isIn(caretPosition, Utilities.findIdentifierSpan(tp, cu, info.getTrees().getSourcePositions(), doc)))
258: // && !Utilities.isKeyword(tree)
259: // && (!(tree instanceof MethodTree) || lastTree == null)) {
260: // FindLocalUsagesQuery fluq = new FindLocalUsagesQuery();
261: //
262: // setLocalUsages(fluq);
263: //
264: // try {
265: // localUsages = fluq.findUsages(el, info, doc);
266: // } finally {
267: // setLocalUsages(null);
268: // }
269: // }
270: // lastTree = tree;
271: // tp = tp.getParentPath();
272: // }
273: //
274: if (localUsages != null)
275: return localUsages;
276:
277: return Collections.emptySet();
278: }
279:
280: private boolean canceled;
281: private MethodExitDetector exitDetector;
282:
283: // private FindLocalUsagesQuery localUsages;
284: //
285: // private final synchronized void setExitDetector(MethodExitDetector detector) {
286: // this.exitDetector = detector;
287: // }
288:
289: public final synchronized void cancel() {
290: canceled = true;
291:
292: if (exitDetector != null) {
293: // exitDetector.cancel();
294: }
295: // if (localUsages != null) {
296: // localUsages.cancel();
297: // }
298: }
299:
300: protected final synchronized boolean isCancelled() {
301: return canceled;
302: }
303:
304: protected final synchronized void resume() {
305: canceled = false;
306: }
307:
308: }
|