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: * Portions Copyrighted 2007 Sun Microsystems, Inc.
027: */
028: package org.netbeans.api.java.source.ui;
029:
030: import com.sun.source.tree.ClassTree;
031: import com.sun.source.tree.CompilationUnitTree;
032: import com.sun.source.tree.MethodTree;
033: import com.sun.source.tree.Tree;
034: import com.sun.source.tree.VariableTree;
035: import com.sun.source.util.TreePathScanner;
036: import java.io.IOException;
037: import javax.lang.model.element.Element;
038: import javax.swing.text.StyledDocument;
039: import org.netbeans.api.java.source.ClasspathInfo;
040: import org.netbeans.api.java.source.CompilationController;
041: import org.netbeans.api.java.source.CompilationInfo;
042: import org.netbeans.api.java.source.ElementHandle;
043: import org.netbeans.api.java.source.JavaSource;
044: import org.netbeans.api.java.source.SourceUtils;
045: import org.netbeans.api.java.source.Task;
046: import org.netbeans.modules.java.BinaryElementOpen;
047: import org.openide.ErrorManager;
048: import org.openide.cookies.EditorCookie;
049: import org.openide.cookies.LineCookie;
050: import org.openide.cookies.OpenCookie;
051: import org.openide.filesystems.FileObject;
052: import org.openide.loaders.DataObject;
053: import org.openide.text.Line;
054: import org.openide.text.NbDocument;
055: import org.openide.util.Exceptions;
056: import org.openide.util.Lookup;
057:
058: /** Utility class for opening elements in editor.
059: *
060: * @author Jan Lahoda
061: */
062: public final class ElementOpen {
063:
064: private ElementOpen() {
065: }
066:
067: /**
068: * Opens {@link Element} corresponding to the given {@link ElementHandle}.
069: *
070: * @param cpInfo ClasspathInfo which should be used for the search
071: * @param el declaration to open
072: * @return true if and only if the declaration was correctly opened,
073: * false otherwise
074: * @since 1.5
075: */
076: public static boolean open(final ClasspathInfo cpInfo,
077: final ElementHandle<? extends Element> el) {
078: FileObject fo = SourceUtils.getFile(el, cpInfo);
079: Object[] openInfo = fo != null ? getOpenInfo(fo, el) : null;
080: if (openInfo != null) {
081: assert openInfo[0] instanceof FileObject;
082: assert openInfo[1] instanceof Integer;
083: return doOpen((FileObject) openInfo[0],
084: (Integer) openInfo[1]);
085: }
086:
087: BinaryElementOpen beo = Lookup.getDefault().lookup(
088: BinaryElementOpen.class);
089:
090: if (beo != null) {
091: return beo.open(cpInfo, el);
092: } else {
093: return false;
094: }
095: }
096:
097: /**
098: * Opens given {@link Element}.
099: *
100: * @param cpInfo ClasspathInfo which should be used for the search
101: * @param el declaration to open
102: * @return true if and only if the declaration was correctly opened,
103: * false otherwise
104: */
105: public static boolean open(final ClasspathInfo cpInfo,
106: final Element el) {
107: return open(cpInfo, ElementHandle.create(el));
108: }
109:
110: /**
111: * Opens given {@link Element}.
112: *
113: * @param toSearch fileobject whose {@link ClasspathInfo} will be used
114: * @param toOpen {@link ElementHandle} of the element which should be opened.
115: * @return true if and only if the declaration was correctly opened,
116: * false otherwise
117: */
118: public static boolean open(final FileObject toSearch,
119: final ElementHandle<? extends Element> toOpen) {
120: if (toSearch == null || toOpen == null) {
121: throw new IllegalArgumentException("null not supported");
122: }
123:
124: Object[] openInfo = getOpenInfo(toSearch, toOpen);
125: if (openInfo != null) {
126: assert openInfo[0] instanceof FileObject;
127: assert openInfo[1] instanceof Integer;
128: return doOpen((FileObject) openInfo[0],
129: (Integer) openInfo[1]);
130: }
131:
132: BinaryElementOpen beo = Lookup.getDefault().lookup(
133: BinaryElementOpen.class);
134:
135: if (beo != null) {
136: return beo.open(ClasspathInfo.create(toSearch), toOpen);
137: } else {
138: return false;
139: }
140: }
141:
142: // Private methods ---------------------------------------------------------
143:
144: private static Object[] getOpenInfo(final FileObject fo,
145: final ElementHandle<? extends Element> handle) {
146: assert fo != null;
147:
148: try {
149: int offset = getOffset(fo, handle);
150: return new Object[] { fo, offset };
151: } catch (IOException e) {
152: Exceptions.printStackTrace(e);
153: return null;
154: }
155: }
156:
157: private static boolean doOpen(FileObject fo, int offset) {
158: try {
159: DataObject od = DataObject.find(fo);
160: EditorCookie ec = od
161: .getCookie(org.openide.cookies.EditorCookie.class);
162: LineCookie lc = od
163: .getCookie(org.openide.cookies.LineCookie.class);
164:
165: if (ec != null && lc != null && offset != -1) {
166: StyledDocument doc = ec.openDocument();
167: if (doc != null) {
168: int line = NbDocument.findLineNumber(doc, offset);
169: int lineOffset = NbDocument.findLineOffset(doc,
170: line);
171: int column = offset - lineOffset;
172:
173: if (line != -1) {
174: Line l = lc.getLineSet().getCurrent(line);
175:
176: if (l != null) {
177: l.show(Line.SHOW_GOTO, column);
178: return true;
179: }
180: }
181: }
182: }
183:
184: OpenCookie oc = od
185: .getCookie(org.openide.cookies.OpenCookie.class);
186:
187: if (oc != null) {
188: oc.open();
189: return true;
190: }
191: } catch (IOException e) {
192: Exceptions.printStackTrace(e);
193: }
194:
195: return false;
196: }
197:
198: private static int getOffset(FileObject fo,
199: final ElementHandle<? extends Element> handle)
200: throws IOException {
201: final int[] result = new int[] { -1 };
202:
203: JavaSource js = JavaSource.forFileObject(fo);
204: if (js != null) {
205: js.runUserActionTask(new Task<CompilationController>() {
206: public void run(CompilationController info) {
207: try {
208: info.toPhase(JavaSource.Phase.RESOLVED);
209: } catch (IOException ioe) {
210: Exceptions.printStackTrace(ioe);
211: }
212: Element el = handle.resolve(info);
213: if (el == null) {
214: ErrorManager.getDefault().log(
215: ErrorManager.ERROR,
216: "Cannot resolve " + handle + ". "
217: + info.getClasspathInfo());
218: return;
219: }
220:
221: FindDeclarationVisitor v = new FindDeclarationVisitor(
222: el, info);
223:
224: CompilationUnitTree cu = info.getCompilationUnit();
225:
226: v.scan(cu, null);
227: Tree elTree = v.declTree;
228:
229: if (elTree != null)
230: result[0] = (int) info.getTrees()
231: .getSourcePositions().getStartPosition(
232: cu, elTree);
233: }
234: }, true);
235: }
236: return result[0];
237: }
238:
239: // Private innerclasses ----------------------------------------------------
240:
241: private static class FindDeclarationVisitor extends
242: TreePathScanner<Void, Void> {
243:
244: private Element element;
245: private Tree declTree;
246: private CompilationInfo info;
247:
248: public FindDeclarationVisitor(Element element,
249: CompilationInfo info) {
250: this .element = element;
251: this .info = info;
252: }
253:
254: @Override
255: public Void visitClass(ClassTree tree, Void d) {
256: handleDeclaration();
257: super .visitClass(tree, d);
258: return null;
259: }
260:
261: @Override
262: public Void visitMethod(MethodTree tree, Void d) {
263: handleDeclaration();
264: super .visitMethod(tree, d);
265: return null;
266: }
267:
268: @Override
269: public Void visitVariable(VariableTree tree, Void d) {
270: handleDeclaration();
271: super .visitVariable(tree, d);
272: return null;
273: }
274:
275: public void handleDeclaration() {
276: Element found = info.getTrees()
277: .getElement(getCurrentPath());
278:
279: if (element.equals(found)) {
280: declTree = getCurrentPath().getLeaf();
281: }
282: }
283:
284: }
285:
286: }
|