From 6ba21b98a1c295ac3c62386b2250f25f5eaed310 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Wed, 15 Apr 2009 11:15:19 -0700 Subject: [PATCH] AI 146336: am: CL 146335 ADT: Rework the Manifest class browser. For ADT #1603194, it is desirable to select the Instrumentation Runner class from the android.jar. The class browser was filtering it out. The class browser has been changed like this: - include all source & jar package roots - a checkbox let the user toggle between searching only sources (of the project) or anything in the classpath (thus include jars.) The default is to include everything for the instrumentation and only the source for other browsers. Also improved a bit the filter by not iterating over the hierarchy and filtering out abstract classes (which was not needed before.) Original author: raphael Merged from: //branches/cupcake/... Automated import of CL 146336 --- .../AndroidManifestDescriptors.java | 28 ++++- .../ApplicationAttributeDescriptor.java | 3 +- .../descriptors/ClassAttributeDescriptor.java | 23 +++- .../InstrumentationAttributeDescriptor.java | 46 -------- .../manifest/model/UiClassAttributeNode.java | 107 ++++++++++++++---- 5 files changed, 128 insertions(+), 79 deletions(-) delete mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java index 77c08b526..5d1ababc2 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java @@ -205,6 +205,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider { overrideClassName(overrides, "receiver", AndroidConstants.CLASS_BROADCASTRECEIVER); //$NON-NLS-1$ overrideClassName(overrides, "service", AndroidConstants.CLASS_SERVICE); //$NON-NLS-1$ overrideClassName(overrides, "provider", AndroidConstants.CLASS_CONTENTPROVIDER); //$NON-NLS-1$ + overrideClassName(overrides, "instrumentation", AndroidConstants.CLASS_INSTRUMENTATION); //$NON-NLS-1$ // -- list element nodes already created -- // These elements are referenced by already opened editors, so we want to update them @@ -244,27 +245,42 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider { new DescriptorsUtils.ITextAttributeCreator() { public TextAttributeDescriptor create(String xmlName, String uiName, String nsUri, String tooltip) { + uiName += "*"; //$NON-NLS-1$ if (AndroidConstants.CLASS_ACTIVITY.equals(className)) { return new ClassAttributeDescriptor( className, PostActivityCreationAction.getAction(), - xmlName, uiName + "*", //$NON-NLS-1$ + xmlName, + uiName, nsUri, tooltip, - true /*mandatory */); + true /*mandatory */, + true /*defaultToProjectOnly*/); } else if (AndroidConstants.CLASS_BROADCASTRECEIVER.equals(className)) { return new ClassAttributeDescriptor( className, PostReceiverCreationAction.getAction(), - xmlName, uiName + "*", //$NON-NLS-1$ + xmlName, + uiName, nsUri, tooltip, - true /*mandatory */); - + true /*mandatory */, + true /*defaultToProjectOnly*/); + } else if (AndroidConstants.CLASS_INSTRUMENTATION.equals(className)) { + return new ClassAttributeDescriptor( + className, + null, // no post action + xmlName, + uiName, + nsUri, + tooltip, + true /*mandatory */, + false /*defaultToProjectOnly*/); } else { return new ClassAttributeDescriptor( className, - xmlName, uiName + "*", //$NON-NLS-1$ + xmlName, + uiName, nsUri, tooltip, true /*mandatory */); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java index eab7f091b..98d0fe895 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java @@ -39,6 +39,7 @@ public class ApplicationAttributeDescriptor extends TextAttributeDescriptor { @Override public UiAttributeNode createUiNode(UiElementNode uiParent) { return new UiClassAttributeNode("android.app.Application", //$NON-NLS-1$ - null /* postCreationAction */, false /* mandatory */, this, uiParent); + null /* postCreationAction */, false /* mandatory */, this, uiParent, + true /*defaultToProjectOnly*/); } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java index 629b37c76..d1a76e078 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java @@ -36,6 +36,8 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { /** indicates if the class parameter is mandatory */ boolean mMandatory; + + private final boolean mDefaultToProjectOnly; /** * Creates a new {@link ClassAttributeDescriptor} @@ -49,10 +51,14 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { * @param mandatory indicates if the class attribute is mandatory. */ public ClassAttributeDescriptor(String superClassName, - String xmlLocalName, String uiName, String nsUri, - String tooltip, boolean mandatory) { + String xmlLocalName, + String uiName, + String nsUri, + String tooltip, + boolean mandatory) { super(xmlLocalName, uiName, nsUri, tooltip); mSuperClassName = superClassName; + mDefaultToProjectOnly = true; } /** @@ -67,14 +73,21 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { * See {@link SdkConstants#NS_RESOURCES} for a common value. * @param tooltip A non-empty tooltip string or null. * @param mandatory indicates if the class attribute is mandatory. + * @param defaultToProjectOnly True if only classes from the sources of this project should + * be shown by default in the class browser. */ public ClassAttributeDescriptor(String superClassName, IPostTypeCreationAction postCreationAction, - String xmlLocalName, String uiName, String nsUri, - String tooltip, boolean mandatory) { + String xmlLocalName, + String uiName, + String nsUri, + String tooltip, + boolean mandatory, + boolean defaultToProjectOnly) { super(xmlLocalName, uiName, nsUri, tooltip); mSuperClassName = superClassName; mPostCreationAction = postCreationAction; + mDefaultToProjectOnly = defaultToProjectOnly; } /** @@ -83,6 +96,6 @@ public class ClassAttributeDescriptor extends TextAttributeDescriptor { @Override public UiAttributeNode createUiNode(UiElementNode uiParent) { return new UiClassAttributeNode(mSuperClassName, mPostCreationAction, - mMandatory, this, uiParent); + mMandatory, this, uiParent, mDefaultToProjectOnly); } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java deleted file mode 100644 index 6e589f744..000000000 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ide.eclipse.editors.manifest.descriptors; - -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; -import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiAttributeNode; -import com.android.ide.eclipse.editors.uimodel.UiElementNode; - -/** - * Describes a 'Instrumentation' class XML attribute. It is displayed by a - * {@link UiClassAttributeNode}, that restricts creation and selection to classes inheriting from - * android.app.Instrumentation. - */ -public class InstrumentationAttributeDescriptor extends TextAttributeDescriptor { - - public InstrumentationAttributeDescriptor(String xmlLocalName, String uiName, String nsUri, - String tooltip) { - super(xmlLocalName, uiName, nsUri, tooltip); - } - - /** - * @return A new {@link UiClassAttributeNode} linked to this descriptor. - */ - @Override - public UiAttributeNode createUiNode(UiElementNode uiParent) { - return new UiClassAttributeNode(AndroidConstants.CLASS_INSTRUMENTATION, - null /* postCreationAction */, true /* mandatory */, this, uiParent); - } -} - diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java index e32be86b0..c872b6f31 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.editors.manifest.model; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; import com.android.ide.eclipse.common.project.BaseProjectHelper; @@ -31,6 +32,7 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; @@ -63,6 +65,7 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; @@ -90,20 +93,28 @@ public class UiClassAttributeNode extends UiTextAttributeNode { private String mReferenceClass; private IPostTypeCreationAction mPostCreationAction; private boolean mMandatory; + private final boolean mDefaultToProjectOnly; private class HierarchyTypeSelection extends TypeSelectionExtension { private IJavaProject mJavaProject; + private IType mReferenceType; + private Button mProjectOnly; + private boolean mUseProjectOnly; - public HierarchyTypeSelection(IProject project, String referenceClass) { + public HierarchyTypeSelection(IProject project, String referenceClass) + throws JavaModelException { mJavaProject = JavaCore.create(project); - mReferenceClass = referenceClass; + mReferenceType = mJavaProject.findType(referenceClass); } @Override public ITypeInfoFilterExtension getFilterExtension() { return new ITypeInfoFilterExtension() { public boolean select(ITypeInfoRequestor typeInfoRequestor) { + + boolean projectOnly = mUseProjectOnly; + String packageName = typeInfoRequestor.getPackageName(); String typeName = typeInfoRequestor.getTypeName(); String enclosingType = typeInfoRequestor.getEnclosingName(); @@ -121,19 +132,35 @@ public class UiClassAttributeNode extends UiTextAttributeNode { try { IType type = mJavaProject.findType(className); - if (type != null) { - // get the type hierarchy - ITypeHierarchy hierarchy = type.newSupertypeHierarchy( - new NullProgressMonitor()); - - // if the super class is not the reference class, it may inherit from - // it so we get its supertype. At some point it will be null and we - // will return false; - IType superType = type; - while ((superType = hierarchy.getSuperclass(superType)) != null) { - if (mReferenceClass.equals(superType.getFullyQualifiedName())) { - return true; - } + + if (type == null) { + return false; + } + + // don't display abstract classes + if ((type.getFlags() & Flags.AccAbstract) != 0) { + return false; + } + + // if project-only is selected, make sure the package fragment is + // an actual source (thus "from this project"). + if (projectOnly) { + IPackageFragment frag = type.getPackageFragment(); + if (frag == null || frag.getKind() != IPackageFragmentRoot.K_SOURCE) { + return false; + } + } + + // get the type hierarchy and reference type is one of the super classes. + ITypeHierarchy hierarchy = type.newSupertypeHierarchy( + new NullProgressMonitor()); + + IType[] supertypes = hierarchy.getAllSupertypes(type); + int n = supertypes.length; + for (int i = 0; i < n; i++) { + IType st = supertypes[i]; + if (mReferenceType.equals(st)) { + return true; } } } catch (JavaModelException e) { @@ -143,6 +170,29 @@ public class UiClassAttributeNode extends UiTextAttributeNode { } }; } + + @Override + public Control createContentArea(Composite parent) { + + mProjectOnly = new Button(parent, SWT.CHECK); + mProjectOnly.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mProjectOnly.setText(String.format("Display classes from sources of project '%s' only", + mJavaProject.getProject().getName())); + + mUseProjectOnly = mDefaultToProjectOnly; + mProjectOnly.setSelection(mUseProjectOnly); + + mProjectOnly.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + mUseProjectOnly = mProjectOnly.getSelection(); + getTypeSelectionComponent().triggerSearch(); + } + }); + + return super.createContentArea(parent); + } } /** @@ -165,14 +215,18 @@ public class UiClassAttributeNode extends UiTextAttributeNode { * modification of the class. * @param mandatory indicates if the class value is mandatory * @param attributeDescriptor the {@link AttributeDescriptor} object linked to the Ui Node. + * @param defaultToProjectOnly When true display classes of this project only by default. + * When false any class path will be considered. The user can always toggle this. */ public UiClassAttributeNode(String referenceClass, IPostTypeCreationAction postCreationAction, - boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent) { + boolean mandatory, AttributeDescriptor attributeDescriptor, UiElementNode uiParent, + boolean defaultToProjectOnly) { super(attributeDescriptor, uiParent); mReferenceClass = referenceClass; mPostCreationAction = postCreationAction; mMandatory = mandatory; + mDefaultToProjectOnly = defaultToProjectOnly; } /* (non-java doc) @@ -292,8 +346,11 @@ public class UiClassAttributeNode extends UiTextAttributeNode { // Create a search scope including only the source folder of the current // project. + IPackageFragmentRoot[] packageFragmentRoots = getPackageFragmentRoots(project, + true /*include_containers*/); IJavaSearchScope scope = SearchEngine.createJavaSearchScope( - getPackageFragmentRoots(project), false); + packageFragmentRoots, + false); try { SelectionDialog dlg = JavaUI.createTypeDialog(text.getShell(), @@ -301,7 +358,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode { scope, IJavaElementSearchConstants.CONSIDER_CLASSES, // style false, // no multiple selection - "**", //$NON-NLS-1$ //filter + "**", //$NON-NLS-1$ //filter new HierarchyTypeSelection(project, mReferenceClass)); dlg.setMessage(String.format("Select class name for element %1$s:", getUiParent().getBreadcrumbTrailDescription(false /* include_root */))); @@ -316,6 +373,7 @@ public class UiClassAttributeNode extends UiTextAttributeNode { } } } catch (JavaModelException e1) { + AdtPlugin.log(e1, "UiClassAttributeNode HandleBrowser failed"); } } } @@ -363,7 +421,9 @@ public class UiClassAttributeNode extends UiTextAttributeNode { } } } catch (JavaModelException e) { + AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed"); } catch (PartInitException e) { + AdtPlugin.log(e, "UiClassAttributeNode HandleLabel failed"); } } } @@ -403,16 +463,20 @@ public class UiClassAttributeNode extends UiTextAttributeNode { * Computes and return the {@link IPackageFragmentRoot}s corresponding to the source folders of * the specified project. * @param project the project + * @param b * @return an array of IPackageFragmentRoot. */ - private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project) { + private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project, + boolean include_containers) { ArrayList result = new ArrayList(); try { IJavaProject javaProject = JavaCore.create(project); IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots(); for (int i = 0; i < roots.length; i++) { IClasspathEntry entry = roots[i].getRawClasspathEntry(); - if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE || + (include_containers && + entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)) { result.add(roots[i]); } } @@ -457,7 +521,8 @@ public class UiClassAttributeNode extends UiTextAttributeNode { page.setSuperClass(mReferenceClass, true /* canBeModified */); // get the source folders as java elements. - IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject()); + IPackageFragmentRoot[] roots = getPackageFragmentRoots(getProject(), + true /*include_containers*/); IPackageFragmentRoot currentRoot = null; IPackageFragment currentFragment = null;