diff options
author | Tor Norbye <tnorbye@google.com> | 2011-02-04 11:59:23 -0800 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2011-02-04 11:59:23 -0800 |
commit | 294a06e3c2b1e3f88eb220b5992977432de39f9b (patch) | |
tree | d3afd408078aa8581513e868da951f3ca8dfc738 /eclipse | |
parent | 1d2909b8ff75a392af9231fe848674378b234bb9 (diff) | |
parent | 918af5b309f888804ba6152537a4b5a72a6b5b16 (diff) | |
download | sdk-294a06e3c2b1e3f88eb220b5992977432de39f9b.zip sdk-294a06e3c2b1e3f88eb220b5992977432de39f9b.tar.gz sdk-294a06e3c2b1e3f88eb220b5992977432de39f9b.tar.bz2 |
Merge "Support onClick method handlers in Hyperlink navigation"
Diffstat (limited to 'eclipse')
2 files changed, 103 insertions, 1 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java index 2a87441..9342f3c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java @@ -32,6 +32,7 @@ public class LayoutConstants { /** The attribute name in a <code><view class="..."></code> element. */ public static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + public static final String ATTR_ON_CLICK = "onClick"; //$NON-NLS-1$ // Some common layout element names public static final String RELATIVE_LAYOUT = "RelativeLayout"; //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java index 54567f3..1765112 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.xml; import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS; +import static com.android.ide.common.layout.LayoutConstants.ATTR_ON_CLICK; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.VIEW; import static com.android.ide.eclipse.adt.AndroidConstants.ANDROID_PKG; @@ -49,6 +50,7 @@ import com.android.ide.eclipse.adt.io.IFileWrapper; import com.android.ide.eclipse.adt.io.IFolderWrapper; import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.SdkConstants; import com.android.sdklib.io.FileWrapper; import com.android.sdklib.io.IAbstractFile; import com.android.sdklib.io.IAbstractFolder; @@ -72,12 +74,23 @@ import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICodeAssist; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; import org.eclipse.jdt.internal.ui.text.JavaWordFinder; @@ -129,6 +142,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; /** @@ -172,7 +186,8 @@ public class Hyperlinks { return false; } - if (isClassAttribute(context) || isActivity(context) || isService(context)) { + if (isClassAttribute(context) || isOnClickAttribute(context) || isActivity(context) + || isService(context)) { return true; } @@ -231,6 +246,15 @@ public class Hyperlinks { return ATTR_CLASS.equals(attribute.getLocalName()) && VIEW.equals(tag); } + /** Returns true if this represents an onClick attribute specifying a method handler */ + private static boolean isOnClickAttribute(XmlContext context) { + Attr attribute = context.getAttribute(); + if (attribute == null) { + return false; + } + return ATTR_ON_CLICK.equals(attribute.getLocalName()) && attribute.getValue().length() > 0; + } + /** Returns true if this represents a {@code <foo.bar.Baz>} custom view class element */ private static boolean isClassElement(XmlContext context) { if (context.getAttribute() != null) { @@ -331,6 +355,8 @@ public class Hyperlinks { return openJavaClass(project, fqcn); } else if (isClassElement(context) || isClassAttribute(context)) { return openJavaClass(project, getClassFqcn(context)); + } else if (isOnClickAttribute(context)) { + return openOnClickMethod(project, context.getAttribute().getValue()); } else { return false; } @@ -443,6 +469,81 @@ public class Hyperlinks { } /** + * Opens a Java method referenced by the given on click attribute method name + * + * @param project the project containing the click handler + * @param method the method name of the on click handler + * @return true if the method was opened, false otherwise + */ + public static boolean openOnClickMethod(IProject project, String method) { + // Search for the method in the Java index, filtering by the required click handler + // method signature (public and has a single View parameter), and narrowing the scope + // first to Activity classes, then to the whole workspace. + final AtomicBoolean success = new AtomicBoolean(false); + SearchRequestor requestor = new SearchRequestor() { + @Override + public void acceptSearchMatch(SearchMatch match) throws CoreException { + Object element = match.getElement(); + if (element instanceof IMethod) { + IMethod methodElement = (IMethod) element; + String[] parameterTypes = methodElement.getParameterTypes(); + if (parameterTypes != null + && parameterTypes.length == 1 + && ("Qandroid.view.View;".equals(parameterTypes[0]) //$NON-NLS-1$ + || "QView;".equals(parameterTypes[0]))) { //$NON-NLS-1$ + // Check that it's public + if (Flags.isPublic(methodElement.getFlags())) { + JavaUI.openInEditor(methodElement); + success.getAndSet(true); + } + } + } + } + }; + try { + IJavaSearchScope scope = null; + IType activityType = null; + IJavaProject javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID); + if (javaProject != null) { + activityType = javaProject.findType(SdkConstants.CLASS_ACTIVITY); + if (activityType != null) { + scope = SearchEngine.createHierarchyScope(activityType); + } + } + if (scope == null) { + scope = SearchEngine.createWorkspaceScope(); + } + + SearchParticipant[] participants = new SearchParticipant[] { + SearchEngine.getDefaultSearchParticipant() + }; + int matchRule = SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE; + SearchPattern pattern = SearchPattern.createPattern("*." + method, + IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, matchRule); + SearchEngine engine = new SearchEngine(); + engine.search(pattern, participants, scope, requestor, new NullProgressMonitor()); + + boolean ok = success.get(); + if (!ok && activityType != null) { + // TODO: Create a project+dependencies scope and search only that scope + + // Try searching again with a complete workspace scope this time + scope = SearchEngine.createWorkspaceScope(); + engine.search(pattern, participants, scope, requestor, new NullProgressMonitor()); + + // TODO: There could be more than one match; add code to consider them all + // and pick the most likely candidate and open only that one. + + ok = success.get(); + } + return ok; + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + return false; + } + + /** * Returns the current configuration, if the associated UI editor has been initialized * and has an associated configuration * |