OSDN Git Service

Fix GestureOverlayView handling
authorTor Norbye <tnorbye@google.com>
Fri, 10 Jun 2011 18:29:58 +0000 (11:29 -0700)
committerTor Norbye <tnorbye@google.com>
Fri, 10 Jun 2011 18:46:00 +0000 (11:46 -0700)
This CL fixes a number of problems related to the GestureOverlayView.

The first big problem was that GestureOverlayView lives in the
android.gesture package, which is not one of the special builtin
packages you can omit when specifying the element in layout XML
files. This CL both stores a full path in the descriptor XML name,
which fixes tag-to-descriptor lookup (without this we were showing the
wrong icon and missing vital attributes in completion), and handles
scenarios where the full path has to be used.

The second problem was that the descriptor metadata listed
GestureOverlayView as a "view" rather than a "layout", which meant
that it was missing information about children (which meant you
couldn't drop into it), and it was missing layout params (which meant
children couldn't be assigned attributes like layout_width and
layout_height).

Also tweak selection handling for gesture views.

There are a number of places where we need to go from a class name to
a view descriptor; these are now centralized in a utility method and
sped up with a map lookup.

(Issues fixed: #17541, #17543)

Change-Id: I67c450f28eab07b3575e510420b7faf4410085e3

eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/UiElementPullParser.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/ViewElementDescriptor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/xml/Hyperlinks.java

index 3f48847..9061702 100644 (file)
@@ -37,6 +37,7 @@ public class LayoutConstants {
     public static final String ATTR_ON_CLICK = "onClick";               //$NON-NLS-1$
     public static final String ATTR_TAG = "tag";                        //$NON-NLS-1$
     public static final String ATTR_NUM_COLUMNS = "numColumns";         //$NON-NLS-1$
+    public static final String ATTR_PADDING = "padding";                //$NON-NLS-1$
 
     // Some common layout element names
     public static final String RELATIVE_LAYOUT = "RelativeLayout";      //$NON-NLS-1$
@@ -133,16 +134,19 @@ public class LayoutConstants {
     public static final String ANDROID_URI = SdkConstants.NS_RESOURCES;
 
     /**
-     * The package name where the widgets live (the ones that require no prefix in layout
-     * files)
-     */
-    public static final String ANDROID_WIDGET_PREFIX = "android.widget."; //$NON-NLS-1$
-
-    /**
      * The top level android package as a prefix, "android.".
      */
     public static final String ANDROID_PKG_PREFIX = ANDROID_PKG + '.';
 
+    /** The android.view. package prefix */
+    public static final String ANDROID_VIEW_PKG = ANDROID_PKG_PREFIX + "view."; //$NON-NLS-1$
+
+    /** The android.widget. package prefix */
+    public static final String ANDROID_WIDGET_PREFIX = ANDROID_PKG_PREFIX + "widget."; //$NON-NLS-1$
+
+    /** The android.webkit. package prefix */
+    public static final String ANDROID_WEBKIT_PKG = ANDROID_PKG_PREFIX + "webkit."; //$NON-NLS-1$
+
     /** The fully qualified class name of an EditText view */
     public static final String FQCN_EDIT_TEXT = "android.widget.EditText"; //$NON-NLS-1$
 
index 7da9587..07593cf 100644 (file)
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout;
 
 import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT;
 import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_PADDING;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT;
 import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.ATTR_LAYOUT;
@@ -58,7 +59,6 @@ import java.util.regex.Pattern;
  * This pull parser generates {@link ViewInfo}s which key is a {@link UiElementNode}.
  */
 public class UiElementPullParser extends BasePullParser {
-    private final static String ATTR_PADDING = "padding"; //$NON-NLS-1$
     private final static Pattern FLOAT_PATTERN = Pattern.compile("(-?[0-9]+(?:\\.[0-9]+)?)(.*)"); //$NON-NLS-1$
 
     private final int[] sIntOut = new int[1];
@@ -68,7 +68,7 @@ public class UiElementPullParser extends BasePullParser {
     private final boolean mExplodedRendering;
     private boolean mZeroAttributeIsPadding = false;
     private boolean mIncreaseExistingPadding = false;
-    private List<ViewElementDescriptor> mLayoutDescriptors;
+    private LayoutDescriptors mDescriptors;
     private final Density mDensity;
     private final float mXdpi;
 
@@ -121,8 +121,7 @@ public class UiElementPullParser extends BasePullParser {
             // get the layout descriptor
             IAndroidTarget target = Sdk.getCurrent().getTarget(project);
             AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
-            LayoutDescriptors descriptors = data.getLayoutDescriptors();
-            mLayoutDescriptors = descriptors.getLayoutDescriptors();
+            mDescriptors = data.getLayoutDescriptors();
         }
         push(mRoot);
     }
@@ -162,18 +161,15 @@ public class UiElementPullParser extends BasePullParser {
         if (mExplodedRendering) {
             // first get the node name
             String xml = node.getDescriptor().getXmlLocalName();
-            for (ViewElementDescriptor descriptor : mLayoutDescriptors) {
-                if (xml.equals(descriptor.getXmlLocalName())) {
-                    NamedNodeMap attributes = node.getXmlNode().getAttributes();
-                    Node padding = attributes.getNamedItemNS(SdkConstants.NS_RESOURCES, "padding");
-                    if (padding == null) {
-                        // we'll return an extra padding
-                        mZeroAttributeIsPadding = true;
-                    } else {
-                        mIncreaseExistingPadding = true;
-                    }
-
-                    break;
+            ViewElementDescriptor descriptor = mDescriptors.findDescriptorByTag(xml);
+            if (descriptor != null) {
+                NamedNodeMap attributes = node.getXmlNode().getAttributes();
+                Node padding = attributes.getNamedItemNS(SdkConstants.NS_RESOURCES, ATTR_PADDING);
+                if (padding == null) {
+                    // we'll return an extra padding
+                    mZeroAttributeIsPadding = true;
+                } else {
+                    mIncreaseExistingPadding = true;
                 }
             }
         }
index 75fdf5b..3accaf8 100644 (file)
@@ -205,17 +205,6 @@ public final class CustomViewDescriptorService {
         // check if the type is a built-in View class.
         List<ViewElementDescriptor> builtInList = null;
 
-        Sdk currentSdk = Sdk.getCurrent();
-        if (currentSdk != null) {
-            IAndroidTarget target = currentSdk.getTarget(project);
-            if (target != null) {
-                AndroidTargetData data = currentSdk.getTargetData(target);
-                if (data != null) {
-                    builtInList = data.getLayoutDescriptors().getViewDescriptors();
-                }
-            }
-        }
-
         // give up if there's no type
         if (type == null) {
             return null;
@@ -223,10 +212,18 @@ public final class CustomViewDescriptorService {
 
         String fqcn = type.getFullyQualifiedName();
 
-        if (builtInList != null) {
-            for (ViewElementDescriptor viewDescriptor : builtInList) {
-                if (fqcn.equals(viewDescriptor.getFullClassName())) {
-                    return viewDescriptor;
+        Sdk currentSdk = Sdk.getCurrent();
+        if (currentSdk != null) {
+            IAndroidTarget target = currentSdk.getTarget(project);
+            if (target != null) {
+                AndroidTargetData data = currentSdk.getTargetData(target);
+                if (data != null) {
+                    LayoutDescriptors descriptors = data.getLayoutDescriptors();
+                    ViewElementDescriptor d = descriptors.findDescriptorByClass(fqcn);
+                    if (d != null) {
+                        return d;
+                    }
+                    builtInList = descriptors.getViewDescriptors();
                 }
             }
         }
index 89cfe92..3bfcb5c 100644 (file)
@@ -20,6 +20,7 @@ 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_NAME;
 import static com.android.ide.common.layout.LayoutConstants.ATTR_TAG;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GESTURE_OVERLAY_VIEW;
 
 import com.android.ide.common.api.IAttributeInfo.Format;
 import com.android.ide.common.resources.platform.AttributeInfo;
@@ -37,6 +38,7 @@ import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkConstants;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -116,6 +118,11 @@ public final class LayoutDescriptors implements IDescriptorProvider {
     /** The descriptor matching android.view.View. */
     private ViewElementDescriptor mBaseViewDescriptor;
 
+    /** Map from view full class name to view descriptor */
+    private Map<String, ViewElementDescriptor> mFqcnToDescriptor =
+        // As of 3.1 there are 58 items in this map
+        new HashMap<String, ViewElementDescriptor>(80);
+
     /** Returns the document descriptor. Contains all layouts and views linked together. */
     public DocumentDescriptor getDescriptor() {
         return mRootDescriptor;
@@ -141,16 +148,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      */
     public ViewElementDescriptor getBaseViewDescriptor() {
         if (mBaseViewDescriptor == null) {
-            for (ElementDescriptor desc : mViewDescriptors) {
-                if (desc instanceof ViewElementDescriptor) {
-                    ViewElementDescriptor viewDesc = (ViewElementDescriptor) desc;
-                    if (SdkConstants.CLASS_VIEW.equals(viewDesc.getFullClassName())) {
-                        mBaseViewDescriptor = viewDesc;
-                        break;
-                    }
-                }
-
-            }
+            mBaseViewDescriptor = findDescriptorByClass(SdkConstants.CLASS_VIEW);
         }
         return mBaseViewDescriptor;
     }
@@ -182,6 +180,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
             for (ViewClassInfo info : views) {
                 ViewElementDescriptor desc = convertView(info, infoDescMap);
                 newViews.add(desc);
+                mFqcnToDescriptor.put(desc.getFullClassName(), desc);
             }
         }
 
@@ -194,15 +193,16 @@ public final class LayoutDescriptors implements IDescriptorProvider {
             for (ViewClassInfo info : layouts) {
                 ViewElementDescriptor desc = convertView(info, infoDescMap);
                 newLayouts.add(desc);
+                mFqcnToDescriptor.put(desc.getFullClassName(), desc);
             }
         }
 
         // Find View and inherit all its layout attributes
-        AttributeDescriptor[] viewLayoutAttribs = findViewLayoutAttributes(
-                SdkConstants.CLASS_FRAMELAYOUT, newLayouts);
+        AttributeDescriptor[] frameLayoutAttrs = findViewLayoutAttributes(
+                SdkConstants.CLASS_FRAMELAYOUT);
 
         if (target.getVersion().getApiLevel() >= 4) {
-            ViewElementDescriptor fragmentTag = createFragment(viewLayoutAttribs, styleMap);
+            ViewElementDescriptor fragmentTag = createFragment(frameLayoutAttrs, styleMap);
             newViews.add(fragmentTag);
         }
 
@@ -215,6 +215,15 @@ public final class LayoutDescriptors implements IDescriptorProvider {
             layoutDesc.setChildren(newDescriptors);
         }
 
+        // The gesture overlay descriptor is really a layout but not included in the layouts list
+        // so handle it specially
+        ViewElementDescriptor gestureView = findDescriptorByClass(FQCN_GESTURE_OVERLAY_VIEW);
+        if (gestureView != null) {
+            gestureView.setChildren(newDescriptors);
+            // Inherit layout attributes from FrameLayout
+            gestureView.setLayoutAttributes(frameLayoutAttrs);
+        }
+
         fixSuperClasses(infoDescMap);
 
         ViewElementDescriptor requestFocus = createRequestFocus();
@@ -223,7 +232,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
 
         // The <merge> tag can only be a root tag, so it is added at the end.
         // It gets everything else as children but it is not made a child itself.
-        ViewElementDescriptor mergeTag = createMerge(viewLayoutAttribs);
+        ViewElementDescriptor mergeTag = createMerge(frameLayoutAttrs);
         mergeTag.setChildren(newDescriptors);  // mergeTag makes a copy of the list
         newDescriptors.add(mergeTag);
         newLayouts.add(mergeTag);
@@ -251,7 +260,12 @@ public final class LayoutDescriptors implements IDescriptorProvider {
     private ViewElementDescriptor convertView(
             ViewClassInfo info,
             HashMap<ViewClassInfo, ViewElementDescriptor> infoDescMap) {
-        String xml_name = info.getShortClassName();
+        String xmlName = info.getShortClassName();
+        String uiName = xmlName;
+        String fqcn = info.getFullClassName();
+        if (ViewElementDescriptor.viewNeedsPackage(fqcn)) {
+            xmlName = fqcn;
+        }
         String tooltip = info.getJavaDoc();
 
         ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
@@ -297,13 +311,13 @@ public final class LayoutDescriptors implements IDescriptorProvider {
         LayoutParamsInfo layoutParams = info.getLayoutData();
 
         for(; layoutParams != null; layoutParams = layoutParams.getSuperClass()) {
-            boolean need_separator = true;
-            for (AttributeInfo attr_info : layoutParams.getAttributes()) {
+            boolean needSeparator = true;
+            for (AttributeInfo attrInfo : layoutParams.getAttributes()) {
                 if (DescriptorsUtils.containsAttribute(layoutAttributes,
-                        SdkConstants.NS_RESOURCES, attr_info)) {
+                        SdkConstants.NS_RESOURCES, attrInfo)) {
                     continue;
                 }
-                if (need_separator) {
+                if (needSeparator) {
                     String title;
                     if (layoutParams.getShortClassName().equals(
                             SdkConstants.CLASS_NAME_LAYOUTPARAMS)) {
@@ -315,20 +329,21 @@ public final class LayoutDescriptors implements IDescriptorProvider {
                                 layoutParams.getShortClassName());
                     }
                     layoutAttributes.add(new SeparatorAttributeDescriptor(title));
-                    need_separator = false;
+                    needSeparator = false;
                 }
                 DescriptorsUtils.appendAttribute(layoutAttributes,
                         null, // elementName
                         SdkConstants.NS_RESOURCES,
-                        attr_info,
+                        attrInfo,
                         false, // required
                         null /* overrides */);
             }
         }
 
-        ViewElementDescriptor desc = new ViewElementDescriptor(xml_name,
-                xml_name, // ui_name
-                info.getFullClassName(),
+        ViewElementDescriptor desc = new ViewElementDescriptor(
+                xmlName,
+                uiName,
+                fqcn,
                 tooltip,
                 null, // sdk_url
                 attributes.toArray(new AttributeDescriptor[attributes.size()]),
@@ -346,7 +361,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      *   View descriptor and extract its layout attributes.
      */
     private void insertInclude(List<ViewElementDescriptor> knownViews) {
-        String xml_name = VIEW_INCLUDE;
+        String xmlName = VIEW_INCLUDE;
 
         // Create the include custom attributes
         ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
@@ -372,11 +387,11 @@ public final class LayoutDescriptors implements IDescriptorProvider {
 
         // Find View and inherit all its layout attributes
         AttributeDescriptor[] viewLayoutAttribs = findViewLayoutAttributes(
-                SdkConstants.CLASS_VIEW, knownViews);
+                SdkConstants.CLASS_VIEW);
 
         // Create the include descriptor
-        ViewElementDescriptor desc = new ViewElementDescriptor(xml_name,  // xml_name
-                xml_name, // ui_name
+        ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
+                xmlName, // ui_name
                 VIEW_INCLUDE, // "class name"; the GLE only treats this as an element tag
                 "Lets you statically include XML layouts inside other XML layouts.",  // tooltip
                 null, // sdk_url
@@ -393,11 +408,11 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      * @param viewLayoutAttribs The layout attributes to use for the new descriptor
      */
     private ViewElementDescriptor createMerge(AttributeDescriptor[] viewLayoutAttribs) {
-        String xml_name = VIEW_MERGE;
+        String xmlName = VIEW_MERGE;
 
         // Create the include descriptor
-        ViewElementDescriptor desc = new ViewElementDescriptor(xml_name,  // xml_name
-                xml_name, // ui_name
+        ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
+                xmlName, // ui_name
                 VIEW_MERGE, // "class name"; the GLE only treats this as an element tag
                 "A root tag useful for XML layouts inflated using a ViewStub.",  // tooltip
                 null,  // sdk_url
@@ -416,7 +431,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      */
     private ViewElementDescriptor createFragment(AttributeDescriptor[] viewLayoutAttribs,
             Map<String, DeclareStyleableInfo> styleMap) {
-        String xml_name = VIEW_FRAGMENT;
+        String xmlName = VIEW_FRAGMENT;
         final ViewElementDescriptor descriptor;
 
         // First try to create the descriptor from metadata in attrs.xml:
@@ -457,9 +472,9 @@ public final class LayoutDescriptors implements IDescriptorProvider {
             // The above will only work on API 11 and up. However, fragments are *also* available
             // on older platforms, via the fragment support library, so add in a manual
             // entry if necessary.
-            descriptor = new ViewElementDescriptor(xml_name,  // xml_name
-                xml_name, // ui_name
-                xml_name, // "class name"; the GLE only treats this as an element tag
+            descriptor = new ViewElementDescriptor(xmlName,
+                xmlName, // ui_name
+                xmlName, // "class name"; the GLE only treats this as an element tag
                 fragmentTooltip,
                 sdkUrl,
                 new AttributeDescriptor[] {
@@ -489,13 +504,13 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      * Creates and returns a new {@code <requestFocus>} descriptor.
      */
     private ViewElementDescriptor createRequestFocus() {
-        String xml_name = REQUEST_FOCUS;
+        String xmlName = REQUEST_FOCUS;
 
         // Create the include descriptor
         return new ViewElementDescriptor(
-                xml_name,  // xml_name
-                xml_name, // ui_name
-                xml_name, // "class name"; the GLE only treats this as an element tag
+                xmlName,  // xml_name
+                xmlName, // ui_name
+                xmlName, // "class name"; the GLE only treats this as an element tag
                 "Requests focus for the parent element or one of its descendants", // tooltip
                 null,  // sdk_url
                 null,  // attributes
@@ -508,13 +523,10 @@ public final class LayoutDescriptors implements IDescriptorProvider {
      * Finds the descriptor and retrieves all its layout attributes.
      */
     private AttributeDescriptor[] findViewLayoutAttributes(
-            String viewFqcn,
-            List<ViewElementDescriptor> knownViews) {
-
-        for (ViewElementDescriptor viewDesc : knownViews) {
-            if (viewFqcn.equals(viewDesc.getFullClassName())) {
-                return viewDesc.getLayoutAttributes();
-            }
+            String viewFqcn) {
+        ViewElementDescriptor viewDesc = findDescriptorByClass(viewFqcn);
+        if (viewDesc != null) {
+            return viewDesc.getLayoutAttributes();
         }
 
         return null;
@@ -549,4 +561,45 @@ public final class LayoutDescriptors implements IDescriptorProvider {
             }
         }
     }
+
+    /**
+     * Returns the {@link ViewElementDescriptor} with the given fully qualified class
+     * name, or null if not found. This is a quick map lookup.
+     *
+     * @param fqcn the fully qualified class name
+     * @return the corresponding {@link ViewElementDescriptor} or null
+     */
+    public ViewElementDescriptor findDescriptorByClass(String fqcn) {
+        return mFqcnToDescriptor.get(fqcn);
+    }
+
+    /**
+     * Returns the {@link ViewElementDescriptor} with the given XML tag name,
+     * which usually does not include the package (depending on the
+     * value of {@link ViewElementDescriptor#viewNeedsPackage(String)}).
+     *
+     * @param tag the XML tag name
+     * @return the corresponding {@link ViewElementDescriptor} or null
+     */
+    public ViewElementDescriptor findDescriptorByTag(String tag) {
+        // TODO: Consider whether we need to add a direct map lookup for this as well.
+        // Currently not done since this is not frequently needed (only needed for
+        // exploded rendering which was already performing list iteration.)
+        for (ViewElementDescriptor descriptor : mLayoutDescriptors) {
+            if (tag.equals(descriptor.getXmlLocalName())) {
+                return descriptor;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a collection of all the view class names, including layouts
+     *
+     * @return a collection of all the view class names, never null
+     */
+    public Collection<String> getAllViewClassNames() {
+        return mFqcnToDescriptor.keySet();
+    }
 }
index b45a197..a18b821 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors.layout.descriptors;
 
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_VIEW_PKG;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_WEBKIT_PKG;
+
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
@@ -53,7 +57,7 @@ public class ViewElementDescriptor extends ElementDescriptor {
     private final String mFullClassName;
 
     /** The list of layout attributes. Can be empty but not null. */
-    private final AttributeDescriptor[] mLayoutAttributes;
+    private AttributeDescriptor[] mLayoutAttributes;
 
     /** The super-class descriptor. Can be null. */
     private ViewElementDescriptor mSuperClassDesc;
@@ -117,6 +121,16 @@ public class ViewElementDescriptor extends ElementDescriptor {
     }
 
     /**
+     * Sets the list of layout attribute attributes.
+     *
+     * @param attributes the new layout attributes, not null
+     */
+    public void setLayoutAttributes(AttributeDescriptor[] attributes) {
+        assert attributes != null;
+        mLayoutAttributes = attributes;
+    }
+
+    /**
      * Returns a new {@link UiViewElementNode} linked to this descriptor.
      */
     @Override
@@ -168,4 +182,17 @@ public class ViewElementDescriptor extends ElementDescriptor {
         return icon;
     }
 
+    /**
+     * Returns true if views with the given fully qualified class name need to include
+     * their package in the layout XML tag
+     *
+     * @param fqcn the fully qualified class name, such as android.widget.Button
+     * @return true if the full package path should be included in the layout XML element
+     *         tag
+     */
+    public static boolean viewNeedsPackage(String fqcn) {
+        return !(fqcn.startsWith(ANDROID_WIDGET_PREFIX)
+              || fqcn.startsWith(ANDROID_VIEW_PKG)
+              || fqcn.startsWith(ANDROID_WEBKIT_PKG));
+    }
 }
index 6bd03b2..7471e54 100755 (executable)
@@ -77,7 +77,7 @@ public class CanvasViewInfo implements IPropertySource {
     private final UiViewElementNode mUiViewNode;
     private CanvasViewInfo mParent;
     private ViewInfo mViewInfo;
-    private final ArrayList<CanvasViewInfo> mChildren = new ArrayList<CanvasViewInfo>();
+    private final List<CanvasViewInfo> mChildren = new ArrayList<CanvasViewInfo>();
 
     /**
      * Is this view info an individually exploded view? This is the case for views
@@ -390,7 +390,8 @@ public class CanvasViewInfo implements IPropertySource {
         // etc)
         if (mParent != null
                 && mParent.mName.endsWith(GESTURE_OVERLAY_VIEW)
-                && mParent.isRoot()) {
+                && mParent.isRoot()
+                && mParent.mChildren.size() == 1) {
             return true;
         }
 
index 176b7bd..4923107 100644 (file)
@@ -20,6 +20,7 @@ import static com.android.ide.common.layout.LayoutConstants.ANDROID_STRING_PREFI
 import static com.android.ide.common.layout.LayoutConstants.SCROLL_VIEW;
 import static com.android.ide.common.layout.LayoutConstants.STRING_PREFIX;
 import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor.viewNeedsPackage;
 import static com.android.sdklib.SdkConstants.FD_GEN_SOURCES;
 
 import com.android.ide.common.rendering.LayoutLibrary;
@@ -43,14 +44,13 @@ import com.android.ide.eclipse.adt.internal.editors.IPageImageProvider;
 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor;
+import com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback;
 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ChangeFlags;
 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
-import com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback;
 import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
-import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.IConfigListener;
 import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite.IConfigListener;
 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
 import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
 import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite;
@@ -1661,7 +1661,7 @@ public class GraphicalEditorPart extends EditorPart
                                     // is the same
                                     labelClass),
                                     actual,
-                                    suggested.startsWith(ANDROID_PKG) ? suggestedBase : suggested
+                                    viewNeedsPackage(suggested) ? suggested : suggestedBase
                     );
                     addText(mErrorLabel, ", ");
                 }
@@ -1681,23 +1681,15 @@ public class GraphicalEditorPart extends EditorPart
     }
 
     private static Collection<String> getAndroidViewClassNames(IProject project) {
-        List<String> classNames = new ArrayList<String>(100);
-
         Sdk currentSdk = Sdk.getCurrent();
         IAndroidTarget target = currentSdk.getTarget(project);
         if (target != null) {
             AndroidTargetData targetData = currentSdk.getTargetData(target);
             LayoutDescriptors layoutDescriptors = targetData.getLayoutDescriptors();
-
-            for (ViewElementDescriptor d : layoutDescriptors.getViewDescriptors()) {
-                classNames.add(d.getFullClassName());
-            }
-            for (ViewElementDescriptor d : layoutDescriptors.getLayoutDescriptors()) {
-                classNames.add(d.getFullClassName());
-            }
+            return layoutDescriptors.getAllViewClassNames();
         }
 
-        return classNames;
+        return Collections.emptyList();
     }
 
     /** Add a normal line of text to the styled text widget. */
index 87fdc14..4a92108 100644 (file)
@@ -1230,20 +1230,7 @@ public abstract class VisualRefactoring extends Refactoring {
     protected ViewElementDescriptor getElementDescriptor(String fqcn) {
         AndroidTargetData data = mEditor.getTargetData();
         if (data != null) {
-            List<ViewElementDescriptor> views =
-                data.getLayoutDescriptors().getViewDescriptors();
-            for (ViewElementDescriptor descriptor : views) {
-                if (fqcn.equals(descriptor.getFullClassName())) {
-                    return descriptor;
-                }
-            }
-            List<ViewElementDescriptor> layouts =
-                data.getLayoutDescriptors().getLayoutDescriptors();
-            for (ViewElementDescriptor descriptor : layouts) {
-                if (fqcn.equals(descriptor.getFullClassName())) {
-                    return descriptor;
-                }
-            }
+            return data.getLayoutDescriptors().findDescriptorByClass(fqcn);
         }
 
         return null;
index 60b5662..5bd35a1 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors.layout.uimodel;
 
+import static com.android.ide.common.layout.LayoutConstants.FQCN_FRAME_LAYOUT;
+
 import com.android.ide.common.layout.LayoutConstants;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
@@ -29,8 +32,6 @@ import com.android.sdklib.SdkConstants;
 
 import org.eclipse.core.resources.IProject;
 
-import java.util.List;
-
 /**
  * Specialized version of {@link UiElementNode} for the {@link ViewElementDescriptor}s.
  */
@@ -67,7 +68,6 @@ public class UiViewElementNode extends UiElementNode {
             // owned by a FrameLayout.
             // TODO replace by something user-configurable.
 
-            List<ViewElementDescriptor> layoutDescriptors = null;
             IProject project = getEditor().getProject();
             if (project != null) {
                 Sdk currentSdk = Sdk.getCurrent();
@@ -76,21 +76,17 @@ public class UiViewElementNode extends UiElementNode {
                     if (target != null) {
                         AndroidTargetData data = currentSdk.getTargetData(target);
                         if (data != null) {
-                            layoutDescriptors = data.getLayoutDescriptors().getLayoutDescriptors();
+                            LayoutDescriptors descriptors = data.getLayoutDescriptors();
+                            ViewElementDescriptor desc =
+                                descriptors.findDescriptorByClass(FQCN_FRAME_LAYOUT);
+                            if (desc != null) {
+                                layout_attrs = desc.getLayoutAttributes();
+                                need_xmlns = true;
+                            }
                         }
                     }
                 }
             }
-
-            if (layoutDescriptors != null) {
-                for (ViewElementDescriptor desc : layoutDescriptors) {
-                    if (desc.getXmlName().equals(SdkConstants.CLASS_NAME_FRAMELAYOUT)) {
-                        layout_attrs = desc.getLayoutAttributes();
-                        need_xmlns = true;
-                        break;
-                    }
-                }
-            }
         } else if (ui_parent instanceof UiViewElementNode) {
             layout_attrs =
                 ((ViewElementDescriptor) ui_parent.getDescriptor()).getLayoutAttributes();
index 817fcbe..a9cf902 100644 (file)
@@ -1692,6 +1692,9 @@ public class Hyperlinks {
                         if (region != null
                                 && DOMRegionContext.XML_TAG_NAME.equals(region.getType())) {
                             ITextRegion subRegion = region.getRegionAtCharacterOffset(offset);
+                            if (subRegion == null) {
+                                return null;
+                            }
                             int regionStart = region.getStartOffset();
                             int subregionStart = subRegion.getStart();
                             int relativeOffset = offset - (regionStart + subregionStart);