OSDN Git Service

AI 146335: ADT: Rework the Manifest class browser.
authorRaphael Moll <>
Wed, 15 Apr 2009 18:14:04 +0000 (11:14 -0700)
committerThe Android Open Source Project <initial-contribution@android.com>
Wed, 15 Apr 2009 18:14:04 +0000 (11:14 -0700)
  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.)
  BUG=1603194

Automated import of CL 146335

tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ApplicationAttributeDescriptor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/InstrumentationAttributeDescriptor.java [deleted file]
tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java

index 77c08b5..5d1abab 100644 (file)
@@ -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 */);
index eab7f09..98d0fe8 100644 (file)
@@ -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*/);
     }
 }
index 629b37c..d1a76e0 100644 (file)
@@ -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 (file)
index 6e589f7..0000000
+++ /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);
-    }
-}
-
index e32be86..c872b6f 100644 (file)
@@ -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<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>();
         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;