blob: 846dee2b30cac1a40523b22b6a2a02d9ca0359de [file] [log] [blame]
amywu547e8e12007-03-14 20:16:31 +00001/*******************************************************************************
2 * Copyright (c) 2006, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
nitindd4f81c02005-02-07 23:11:25 +000011package org.eclipse.jst.jsp.ui.internal.hyperlink;
12
13import java.util.ArrayList;
14import java.util.List;
15
16import org.eclipse.core.resources.IFile;
17import org.eclipse.core.resources.ResourcesPlugin;
18import org.eclipse.core.runtime.Path;
19import org.eclipse.jdt.core.IField;
20import org.eclipse.jdt.core.IJavaElement;
21import org.eclipse.jdt.core.ILocalVariable;
22import org.eclipse.jdt.core.IMethod;
23import org.eclipse.jdt.core.ISourceRange;
24import org.eclipse.jdt.core.ISourceReference;
25import org.eclipse.jdt.core.JavaModelException;
26import org.eclipse.jface.text.BadLocationException;
27import org.eclipse.jface.text.IDocument;
28import org.eclipse.jface.text.IRegion;
29import org.eclipse.jface.text.ITextViewer;
30import org.eclipse.jface.text.Region;
amywu547e8e12007-03-14 20:16:31 +000031import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
nitindd4f81c02005-02-07 23:11:25 +000032import org.eclipse.jface.text.hyperlink.IHyperlink;
nitindd4f81c02005-02-07 23:11:25 +000033import org.eclipse.jst.jsp.core.internal.java.IJSPTranslation;
34import org.eclipse.jst.jsp.core.internal.java.JSPTranslation;
35import org.eclipse.jst.jsp.core.internal.java.JSPTranslationAdapter;
36import org.eclipse.jst.jsp.ui.internal.Logger;
david_williamsb5d05632006-02-27 09:24:00 +000037import org.eclipse.wst.sse.core.StructuredModelManager;
david_williams4ad020f2005-04-18 08:00:30 +000038import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
nitindd7870fd2006-09-13 01:57:38 +000039import org.eclipse.wst.sse.core.internal.util.URIResolver;
david_williams4ad020f2005-04-18 08:00:30 +000040import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
41import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
nitindd4f81c02005-02-07 23:11:25 +000042
43/**
44 * Detects hyperlinks in JSP Java content
45 */
amywu547e8e12007-03-14 20:16:31 +000046public class JSPJavaHyperlinkDetector extends AbstractHyperlinkDetector {
nitindd4f81c02005-02-07 23:11:25 +000047
48 private IHyperlink createHyperlink(IJavaElement element, IRegion region, IDocument document) {
49 IHyperlink link = null;
50 if (region != null) {
51 // open local variable in the JSP file...
52 if (element instanceof ISourceReference) {
53 IFile file = null;
54 int jspOffset = 0;
55 IStructuredModel sModel = null;
56
57 // try to locate the file in the workspace
58 try {
59 sModel = StructuredModelManager.getModelManager().getExistingModelForRead(document);
60 if (sModel != null) {
nitindd7870fd2006-09-13 01:57:38 +000061 URIResolver resolver = sModel.getResolver();
amywu547e8e12007-03-14 20:16:31 +000062 if (resolver != null) {
nitindd7870fd2006-09-13 01:57:38 +000063 String uriString = resolver.getFileBaseLocation();
64 file = getFile(uriString);
65 }
nitindd4f81c02005-02-07 23:11:25 +000066 }
67 }
68 finally {
69 if (sModel != null)
70 sModel.releaseFromRead();
71 }
72
73 // get Java range, translate coordinate to JSP
74
75 try {
76 ISourceRange range = null;
77 IJSPTranslation jspTranslation = getJSPTranslation(document);
78 if (jspTranslation != null) {
79 // link to local variable definitions
80 if (element instanceof ILocalVariable) {
81 range = ((ILocalVariable) element).getNameRange();
82 }
83 // linking to fields of the same compilation unit
84 else if (element.getElementType() == IJavaElement.FIELD) {
85 Object cu = ((IField) element).getCompilationUnit();
86 if (cu != null && cu.equals(jspTranslation.getCompilationUnit()))
87 range = ((ISourceReference) element).getSourceRange();
88 }
89 // linking to methods of the same compilation unit
90 else if (element.getElementType() == IJavaElement.METHOD) {
91 Object cu = ((IMethod) element).getCompilationUnit();
92 if (cu != null && cu.equals(jspTranslation.getCompilationUnit()))
93 range = ((ISourceReference) element).getSourceRange();
94 }
95 }
96
amywu65ab20a2006-04-28 21:41:03 +000097 if (range != null && file != null) {
nitindd4f81c02005-02-07 23:11:25 +000098 jspOffset = jspTranslation.getJspOffset(range.getOffset());
99 if (jspOffset >= 0) {
100 link = new WorkspaceFileHyperlink(region, file, new Region(jspOffset, range.getLength()));
101 }
102 }
103 }
104 catch (JavaModelException jme) {
105 Logger.log(Logger.WARNING_DEBUG, jme.getMessage(), jme);
106 }
107 }
108 if (link == null) {
109 link = new JSPJavaHyperlink(region, element);
110 }
111 }
112 return link;
113 }
114
115 /*
116 * (non-Javadoc)
117 *
118 * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer,
119 * org.eclipse.jface.text.IRegion, boolean)
120 */
121 public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
122 List hyperlinks = new ArrayList(0);
123
124 if (region != null && textViewer != null) {
125 IDocument document = textViewer.getDocument();
126
127 // check and make sure this is a valid Java type
128 JSPTranslation jspTranslation = getJSPTranslation(document);
129 if (jspTranslation != null) {
130 // check if we are in JSP Java content
131 int javaOffset = jspTranslation.getJavaOffset(region.getOffset());
132 if (javaOffset > -1) {
133 // check that we are not in indirect Java content (like
134 // included files)
135 if (!jspTranslation.isIndirect(javaOffset)) {
136 // get Java elements
137 IJavaElement[] elements = jspTranslation.getElementsFromJspRange(region.getOffset(), region.getOffset() + region.getLength());
138 if (elements != null && elements.length > 0) {
139 // create a JSPJavaHyperlink for each Java element
140 for (int i = 0; i < elements.length; ++i) {
141 IJavaElement element = elements[i];
142
143 // find hyperlink range for Java element
144 IRegion hyperlinkRegion = selectWord(document, region.getOffset());
145 IHyperlink link = createHyperlink(element, hyperlinkRegion, document);
146 if (link != null) {
147 hyperlinks.add(link);
148 }
149 }
150 }
151 }
152 }
153 }
154 }
155
156 if (hyperlinks.size() == 0)
157 return null;
158 return (IHyperlink[]) hyperlinks.toArray(new IHyperlink[0]);
159 }
160
161 /**
162 * Returns an IFile from the given uri if possible, null if cannot find
163 * file from uri.
164 *
165 * @param fileString
166 * file system path
167 * @return returns IFile if fileString exists in the workspace
168 */
169 private IFile getFile(String fileString) {
170 IFile file = null;
171
172 if (fileString != null) {
nitinda9d7a592007-09-06 11:36:55 +0000173 Path filePath = new Path(fileString);
174 if (filePath.segmentCount() > 1 && ResourcesPlugin.getWorkspace().getRoot().getFile(filePath).exists()) {
175 return ResourcesPlugin.getWorkspace().getRoot().getFile(filePath);
176 }
177 IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(filePath);
nitindd4f81c02005-02-07 23:11:25 +0000178 for (int i = 0; i < files.length && file == null; i++)
179 if (files[i].exists())
180 file = files[i];
181 }
182
183 return file;
184 }
amywu547e8e12007-03-14 20:16:31 +0000185
nitindd4f81c02005-02-07 23:11:25 +0000186 /**
187 * Get JSP translation object
188 *
189 * @return JSPTranslation if one exists, null otherwise
190 */
191 private JSPTranslation getJSPTranslation(IDocument document) {
192 JSPTranslation translation = null;
193
david_williamsc39caaf2005-04-05 06:07:16 +0000194 IDOMModel xmlModel = null;
nitindd4f81c02005-02-07 23:11:25 +0000195 try {
david_williamsc39caaf2005-04-05 06:07:16 +0000196 xmlModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(document);
nitindd4f81c02005-02-07 23:11:25 +0000197 if (xmlModel != null) {
david_williamsc39caaf2005-04-05 06:07:16 +0000198 IDOMDocument xmlDoc = xmlModel.getDocument();
nitindd4f81c02005-02-07 23:11:25 +0000199 JSPTranslationAdapter adapter = (JSPTranslationAdapter) xmlDoc.getAdapterFor(IJSPTranslation.class);
200 if (adapter != null) {
pavery9e8f2402005-11-10 04:42:03 +0000201 translation = adapter.getJSPTranslation();
nitindd4f81c02005-02-07 23:11:25 +0000202 }
203 }
204 }
205 finally {
206 if (xmlModel != null)
207 xmlModel.releaseFromRead();
208 }
209 return translation;
210 }
211
212 /**
213 * Java always selects word when defining region
214 *
215 * @param document
216 * @param anchor
217 * @return IRegion
218 */
219 private IRegion selectWord(IDocument document, int anchor) {
220
221 try {
222 int offset = anchor;
223 char c;
224
225 while (offset >= 0) {
226 c = document.getChar(offset);
227 if (!Character.isJavaIdentifierPart(c))
228 break;
229 --offset;
230 }
231
232 int start = offset;
233
234 offset = anchor;
235 int length = document.getLength();
236
237 while (offset < length) {
238 c = document.getChar(offset);
239 if (!Character.isJavaIdentifierPart(c))
240 break;
241 ++offset;
242 }
243
244 int end = offset;
245
246 if (start == end)
247 return new Region(start, 0);
248
249 return new Region(start + 1, end - start - 1);
250
251 }
252 catch (BadLocationException x) {
253 return null;
254 }
255 }
256}