OSDN Git Service

XML code completion improvements
authorTor Norbye <tnorbye@google.com>
Tue, 15 Mar 2011 04:03:56 +0000 (21:03 -0700)
committerTor Norbye <tnorbye@google.com>
Tue, 15 Mar 2011 18:08:23 +0000 (11:08 -0700)
This changeset contains a number of improvements to the code
completion in XML files.

(1) Add suffix completion in attribute values. For dimensional
    attributes, this will add in (or complete prefixes of) units like
    "dp", "sp", etc. For fractional attributes, the % and %p suffixes
    are completed. (In both cases, there is also a tooltip message
    provided shown in the completion documentation popup).  In
    addition, for flag values, when completing at the end of a flag,
    then the separator character (|) along with the other flag values
    (except those already set) are offered.

(2) Handle completion when the caret is not at the end. For example,
    if you have the following source:

        layout_w^idth="wrap_content"    (^ = caret position)

    then if you invoke code completion you will also be offered the
    attribute layout_weight, and selecting it will -replace- the
    layout_width attribute with layout_height, it will not insert
    layout_weight in the middle of layout_width. This handling is done
    not just for attribute names as shown here but for attribute
    values and element tag names as well.

(3) Improve @resource/ completion sorting. When completing resources,
    consider which attribute is being completed, and use that
    information to sort the resources.  For example, if completing a
    "text" attribute then @string/, and @android:string/ resources
    will be listed first.  For attributes like margins @dimen will be
    first, for include layout the @layout attributes will be listed
    first, and so on.  Also, the resources are sorted alphabetically
    as the second sort key.

(4) Hide some builtin Eclipse code completion items. In particular,
    the default code completion provider for Eclipse will always add
    the current attribute value as a completion. This is extremely
    confusing since if you have a typo, code completion will tell you
    that what you have is okay. I personally witnessed this confusing
    a user who had typed something from memory and code completion
    seemed to him to "confirm" that he had it right.

    To fix this, the code which installs completion providers, will
    identify the builting WST completion provider, and when found,
    replace it with a "filtering" wrapper. This completion provider
    delegates all its calls to the WST completion provider, but it
    recognizes a few patterns, in particular the above attribute value
    completion proposal as well as some namespace and schema ones, and
    removes these.

    (The reason we only filter out these items instead of removing it
    completely is that the completion provider also appears to be
    responsible for inserting code templates defined by the user, and
    we don't want to neuter those if defined by the user.)

(5) Fix a bunch of corner cases - flags could only have a single
    separator (|), resource attribute completion items were missing
    icons, and completion in some positions was not working.

(6) Unit tests. There are now comprehensive unit tests for code
    completion. Each unit test points to a particular source file
    and a particular position within the source file, and code completion
    is invoked for that position. A set of unit tests dump out the
    allowed completion items for each such position, and these are
    compared against golden files. A second set of unit tests then
    specify a particular code completion item among the choices to
    be applied, and then applies that completion item to the document.
    This, along with the caret position (indicated as ^) is written
    into a golden file and used for comparisons. To make it easy
    to see what these tests do, the golden file is actually recorded
    as a diff, so in the test you will see something like this:

Code completion in completion1.xml for android:gravity="left|b^ottom"
selecting bottom:
<         android:gravity="left|bottom"
---
>         android:gravity="left|bottom^"

(6) There are some other misc changes. We had some code which used
    "dip" for device indepdendent pixels (such as the AbsoluteLayout
    handler). Since "dp" seems to be preferred, the code will now
    use that instead.

Change-Id: I8bd5c8336d8747dac1f10a9269ea4197f304cb70

60 files changed:
eclipse/dictionary.txt
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java
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/AndroidContentAssist.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidSourceViewerConfig.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/AttributeDescriptor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutContentAssist.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestContentAssist.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiResourceAttributeNode.java
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/AdtProjectTest.java
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringTest.java
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-actual-applyCompletion1.xml [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion1.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion10.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11a.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11b.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion12.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion2.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion3.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion4.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion5.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion6.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7a.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7b.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion8.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion9.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion1.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion10.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion2.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion3.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion4.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion5.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion6.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7a.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7b.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion8.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion9.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1.xml [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13a.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13b.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13c.diff [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13a.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13b.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13c.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2.xml [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion14.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion15.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion16.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion17.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion18.txt [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest.xml [new file with mode: 0644]
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/sample1a-expected-changeLayout1a.xml
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/sample1b-expected-changeLayout1b.xml
eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/sample5-expected-changeLayout5.xml
eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/AbsoluteLayoutRuleTest.java
eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java [deleted file]

index b92ceb2..b9ccb29 100644 (file)
@@ -205,6 +205,7 @@ tooltip
 tooltips
 traceview
 translucency
+typo
 ui
 uncomment
 undescribed
index c8ce3ac..47fcbd7 100644 (file)
@@ -17,7 +17,7 @@
 package com.android.ide.common.layout;
 
 import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
-import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DIP;
+import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP;
 
 import com.android.ide.common.api.DrawingStyle;
 import com.android.ide.common.api.DropFeedback;
@@ -190,9 +190,9 @@ public class AbsoluteLayoutRule extends BaseLayoutRule {
                     }
 
                     newChild.setAttribute(ANDROID_URI, "layout_x", //$NON-NLS-1$
-                            String.format(VALUE_N_DIP, x));
+                            String.format(VALUE_N_DP, x));
                     newChild.setAttribute(ANDROID_URI, "layout_y", //$NON-NLS-1$
-                            String.format(VALUE_N_DIP, y));
+                            String.format(VALUE_N_DP, y));
 
                     addInnerElements(newChild, element, idMap);
                 }
index a148836..092b0a5 100644 (file)
@@ -52,6 +52,7 @@ public class LayoutConstants {
 
     public static final String ATTR_TEXT = "text";                      //$NON-NLS-1$
     public static final String ATTR_ID = "id";                          //$NON-NLS-1$
+    public static final String ATTR_STYLE = "style";                    //$NON-NLS-1$
     public static final String ATTR_HANDLE = "handle";                  //$NON-NLS-1$
     public static final String ATTR_CONTENT = "content";                //$NON-NLS-1$
     public static final String ATTR_CHECKED = "checked";                //$NON-NLS-1$
@@ -98,7 +99,7 @@ public class LayoutConstants {
     public static final String VALUE_FILL_PARENT = "fill_parent";               //$NON-NLS-1$
     public static final String VALUE_TRUE = "true";                             //$NON-NLS-1$
     public static final String VALUE_FALSE= "false";                            //$NON-NLS-1$
-    public static final String VALUE_N_DIP = "%ddip";                           //$NON-NLS-1$
+    public static final String VALUE_N_DP = "%ddp";                             //$NON-NLS-1$
 
     public static final String VALUE_CENTER_VERTICAL = "centerVertical";        //$NON-NLS-1$
     public static final String VALUE_CENTER_IN_PARENT = "centerInParent";       //$NON-NLS-1$
index 9bc09ec..61c34bf 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors;
 
+import static com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor.ATTRIBUTE_ICON_FILENAME;
+
+import com.android.ide.common.api.IAttributeInfo;
+import com.android.ide.common.api.IAttributeInfo.Format;
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
@@ -32,10 +36,12 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiFlagAttributeNode;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiResourceAttributeNode;
 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
 import com.android.sdklib.SdkConstants;
+import com.android.util.Pair;
 
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.TextSelection;
 import org.eclipse.jface.text.contentassist.CompletionProposal;
@@ -50,12 +56,15 @@ import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PlatformUI;
+import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 /**
@@ -148,29 +157,51 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
             return null;
         }
 
+        boolean isNew = true;
+        int replaceLength = 0;
         if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
             parent = currentNode.getNodeName();
 
-            if (wordPrefix.equals(parent)) {
+            // We're not editing the current node name, so we might be editing its
+            // attributes instead...
+            AttribInfo info = parseAttributeInfo(viewer, offset);
+            if (info != null) {
+                isAttribute = true;
+                // We're editing attributes in an element node (either the attributes' names
+                // or their values).
+                choices = getChoicesForAttribute(parent, currentNode, currentUiNode, info);
+
+                if (info.isInValue) {
+                    // Note - this must be done before the prefix correction below since
+                    // otherwise, when the prefix gets cleared out (for a flag list) we
+                    // end up with a wrong count for the prefix length
+                    Element element = (Element) currentNode;
+                    String attribute = element.getAttribute(info.name);
+                    if (attribute != null) { // Eclipse DOM bug
+                        replaceLength = attribute.length() - wordPrefix.length();
+                        if (info.needTag != 0) {
+                            replaceLength += 2;
+                        }
+                    }
+                } else {
+                    replaceLength = info.name.length() - wordPrefix.length();
+                }
+
+                if (info.correctedPrefix != null) {
+                    wordPrefix = info.correctedPrefix;
+                }
+                needTag = info.needTag;
+                isNew = info.name.length() == 0;
+            } else if (parent.startsWith(wordPrefix)) {
                 // We are still editing the element's tag name, not the attributes
                 // (the element's tag name may not even be complete)
                 isElement = true;
                 choices = getChoicesForElement(parent, currentNode);
-            } else {
-                // We're not editing the current node name, so we might be editing its
-                // attributes instead...
-                isAttribute = true;
-                AttribInfo info = parseAttributeInfo(viewer, offset);
-                if (info != null) {
-                    // We're editing attributes in an element node (either the attributes' names
-                    // or their values).
-                    choices = getChoicesForAttribute(parent, currentNode, currentUiNode, info);
-
-                    if (info.correctedPrefix != null) {
-                        wordPrefix = info.correctedPrefix;
-                    }
-                    needTag = info.needTag;
+                replaceLength = parent.length() - wordPrefix.length();
+                if (wordPrefix.length() == 0) {
+                    replaceLength = 0; // Only do this if on <
                 }
+                isNew = replaceLength == 0;
             }
         } else if (currentNode.getNodeType() == Node.TEXT_NODE) {
             isElement = true;
@@ -201,7 +232,7 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
         }
 
         return computeProposals(offset, currentNode, choices, wordPrefix, needTag,
-                isAttribute, selectionLength);
+                isAttribute, isNew, selectionLength + replaceLength);
     }
 
     /**
@@ -345,24 +376,31 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
                         // A "flag" can consist of several values separated by "or" (|).
                         // If the correct prefix contains such a pipe character, we change
                         // it so that only the currently edited value is completed.
-                        pos = value.indexOf('|');
+                        pos = value.lastIndexOf('|');
                         if (pos >= 0) {
                             attrInfo.correctedPrefix = value = value.substring(pos + 1);
                             attrInfo.needTag = 0;
                         }
                     }
-                }
 
-                if (choices == null && value.startsWith("@")) { //$NON-NLS-1$
-                    // Special case: If the attribute value looks like a reference to a
-                    // resource, offer to complete it, since in many cases our metadata
-                    // does not correctly state whether a resource value is allowed. We don't
-                    // offer these for an empty completion context, but if the user has
-                    // actually typed "@", in that case list resource matches.
-                    // For example, for android:minHeight this makes completion on @dimen/
-                    // possible.
-                    choices = UiResourceAttributeNode.computeResourceStringMatches(currentUiNode,
-                            value);
+                    // Should we do suffix completion on dimension units etc?
+                    choices = completeSuffix(choices, value, currAttrNode);
+
+                    // Check to see if the user is attempting resource completion
+                    AttributeDescriptor attributeDescriptor = currAttrNode.getDescriptor();
+                    IAttributeInfo attributeInfo = attributeDescriptor.getAttributeInfo();
+                    if (value.startsWith("@")  //$NON-NLS-1$
+                            && !Format.REFERENCE.in(attributeInfo.getFormats())) {
+                        // Special case: If the attribute value looks like a reference to a
+                        // resource, offer to complete it, since in many cases our metadata
+                        // does not correctly state whether a resource value is allowed. We don't
+                        // offer these for an empty completion context, but if the user has
+                        // actually typed "@", in that case list resource matches.
+                        // For example, for android:minHeight this makes completion on @dimen/
+                        // possible.
+                        choices = UiResourceAttributeNode.computeResourceStringMatches(
+                                currentUiNode, attributeDescriptor, value);
+                    }
                 }
             }
 
@@ -436,14 +474,16 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
      * - AttributeDescriptor: a possible attribute descriptor which XML name should be completed.
      * - String: string values to display as-is to the user. Typically those are possible
      *           values for a given attribute.
+     * - Pair of Strings: the first value is the keyword to insert, and the second value
+     *           is the tooltip/help for the value to be displayed in the documentation popup.
      *
      * @return The ICompletionProposal[] to display to the user.
      */
     private ICompletionProposal[] computeProposals(int offset, Node currentNode,
-            Object[] choices, String wordPrefix, char need_tag,
-            boolean is_attribute, int selectionLength) {
-        ArrayList<CompletionProposal> proposals = new ArrayList<CompletionProposal>();
-        HashMap<String, String> nsUriMap = new HashMap<String, String>();
+            Object[] choices, String wordPrefix, char needTag,
+            boolean isAttribute, boolean isNew, int replaceLength) {
+        List<CompletionProposal> proposals = new ArrayList<CompletionProposal>();
+        Map<String, String> nsUriMap = new HashMap<String, String>();
 
         for (Object choice : choices) {
             String keyword = null;
@@ -481,6 +521,17 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
 
             } else if (choice instanceof String) {
                 keyword = (String) choice;
+                if (isAttribute) {
+                    icon = IconFactory.getInstance().getIcon(ATTRIBUTE_ICON_FILENAME);
+                }
+            } else if (choice instanceof Pair<?, ?>) {
+                @SuppressWarnings("unchecked")
+                Pair<String, String> pair = (Pair<String, String>) choice;
+                keyword = pair.getFirst();
+                tooltip = pair.getSecond();
+                if (isAttribute) {
+                    icon = IconFactory.getInstance().getIcon(ATTRIBUTE_ICON_FILENAME);
+                }
             } else {
                 continue; // discard unknown choice
             }
@@ -493,18 +544,18 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
                 if (nsPrefix != null) {
                     keyword = nsPrefix + keyword;
                 }
-                String end_tag = ""; //$NON-NLS-1$
-                if (need_tag != 0) {
-                    if (need_tag == '"') {
-                        keyword = need_tag + keyword;
-                        end_tag = String.valueOf(need_tag);
-                    } else if (need_tag == '<') {
+                String endTag = ""; //$NON-NLS-1$
+                if (needTag != 0) {
+                    if (needTag == '"') {
+                        keyword = needTag + keyword;
+                        endTag = String.valueOf(needTag);
+                    } else if (needTag == '<') {
                         if (elementCanHaveChildren(choice)) {
-                            end_tag = String.format("></%1$s>", keyword);  //$NON-NLS-1$
-                            keyword = need_tag + keyword;
+                            endTag = String.format("></%1$s>", keyword);  //$NON-NLS-1$
+                            keyword = needTag + keyword;
                         } else {
-                            keyword = need_tag + keyword;
-                            end_tag = "/>";  //$NON-NLS-1$
+                            keyword = needTag + keyword;
+                            endTag = "/>";  //$NON-NLS-1$
                         }
                     }
                 }
@@ -513,13 +564,13 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
 
                 // For attributes, automatically insert ns:attribute="" and place the cursor
                 // inside the quotes.
-                if (choice instanceof AttributeDescriptor) {
+                if (choice instanceof AttributeDescriptor && isNew) {
                     // Special case for attributes: insert ="" stuff and locate caret inside ""
                     String suffix = "=\"\""; //$NON-NLS-1$
                     proposal = new CompletionProposal(
                         keyword + suffix ,                 // String replacementString
                         offset - wordPrefix.length(),       // int replacementOffset
-                        wordPrefix.length() + selectionLength,  // int replacementLength
+                        wordPrefix.length() + replaceLength,  // int replacementLength
                         keyword.length() + suffix.length() - 1, // cursorPosition
                         icon,                               // Image image
                         keyword,                            // displayString - don't include =""
@@ -527,11 +578,16 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
                         tooltip                             // String additionalProposalInfo
                         );
                 } else {
+                    int cursorPosition = keyword.length();
+                    if (choice instanceof ElementDescriptor && isNew) {
+                        endTag = ' ' + endTag;
+                        cursorPosition += 1;
+                    }
                     proposal = new CompletionProposal(
-                        keyword + end_tag,                  // String replacementString
+                        keyword + endTag,                  // String replacementString
                         offset - wordPrefix.length(),           // int replacementOffset
-                        wordPrefix.length() + selectionLength,  // int replacementLength
-                        keyword.length(),                   // int cursorPosition (rel. to rplcmntOffset)
+                        wordPrefix.length() + replaceLength,  // int replacementLength
+                        cursorPosition,                     // int cursorPosition (rel. to rplcmntOffset)
                         icon,                               // Image image
                         null,                               // String displayString
                         null,                               // IContextInformation contextInformation
@@ -579,7 +635,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
      * or if one of the attributes is a TextValueDescriptor.
      *
      * @param descriptor An ElementDescriptor or an AttributeDescriptor
-     * @return True if the descriptor is an ElementDescriptor that can have children or a text value
+     * @return True if the descriptor is an ElementDescriptor that can have children or a text
+     *         value
      */
     private boolean elementCanHaveChildren(Object descriptor) {
         if (descriptor instanceof ElementDescriptor) {
@@ -587,8 +644,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
             if (desc.hasChildren()) {
                 return true;
             }
-            for (AttributeDescriptor attr_desc : desc.getAttributes()) {
-                if (attr_desc instanceof TextValueDescriptor) {
+            for (AttributeDescriptor attrDesc : desc.getAttributes()) {
+                if (attrDesc instanceof TextValueDescriptor) {
                     return true;
                 }
             }
@@ -729,14 +786,22 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
      */
     private AttribInfo parseAttributeInfo(ITextViewer viewer, int offset) {
         AttribInfo info = new AttribInfo();
+        int originalOffset = offset;
 
         IDocument document = viewer.getDocument();
         int n = document.getLength();
         if (offset <= n) {
             try {
+                // Look to the right to make sure we aren't sitting on the boundary of the
+                // beginning of a new element with whitespace before it
+                if (offset < n && document.getChar(offset) == '<') {
+                    return null;
+                }
+
                 n = offset;
                 for (;offset > 0; --offset) {
                     char ch = document.getChar(offset - 1);
+                    if (ch == '>') break;
                     if (ch == '<') break;
                 }
 
@@ -780,6 +845,22 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
                 if (pos_equal == -1) {
                     info.isInValue = false;
                     info.name = text.trim();
+
+                    // info.name is currently just the prefix of the attribute name.
+                    // Look at the text buffer to find the complete name (since we need
+                    // to know its bounds in order to replace it when a different attribute
+                    // that matches this prefix is chosen)
+                    IRegion lineInfo = document.getLineInformationOfOffset(originalOffset);
+                    String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
+                    int nameStart = originalOffset - lineInfo.getOffset();
+                    for (int nameEnd = nameStart; nameEnd < line.length(); nameEnd++) {
+                        char c = line.charAt(nameEnd);
+                        if (!(Character.isLetter(c) || c == ':' || c == '_')) {
+                            String nameSuffix = line.substring(nameStart, nameEnd);
+                            info.name = text.trim() + nameSuffix;
+                            break;
+                        }
+                    }
                 } else {
                     info.isInValue = true;
                     info.name = text.substring(0, pos_equal).trim();
@@ -831,7 +912,8 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
             if (page != null) {
                 IEditorPart editor = page.getActiveEditor();
                 if (editor instanceof AndroidXmlEditor) {
-                    ISourceViewer ssviewer = ((AndroidXmlEditor) editor).getStructuredSourceViewer();
+                    ISourceViewer ssviewer =
+                        ((AndroidXmlEditor) editor).getStructuredSourceViewer();
                     if (ssviewer == viewer) {
                         return (AndroidXmlEditor) editor;
                     }
@@ -842,6 +924,132 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
         return null;
     }
 
+    /**
+     * Fixed list of dimension units, along with user documentation, for use by
+     * {@link #completeSuffix}.
+     */
+    private static final String[] sDimensionUnits = new String[] {
+        "dp", //$NON-NLS-1$
+        "<b>Density-independent Pixels</b> - an abstract unit that is based on the physical "
+                + "density of the screen.",
+
+        "sp", //$NON-NLS-1$
+        "<b>Scale-independent Pixels</b> - this is like the dp unit, but it is also scaled by "
+                + "the user's font size preference.",
+
+        "pt", //$NON-NLS-1$
+        "<b>Points</b> - 1/72 of an inch based on the physical size of the screen.",
+
+        "mm", //$NON-NLS-1$
+        "<b>Millimeters</b> - based on the physical size of the screen.",
+
+        "in", //$NON-NLS-1$
+        "<b>Inches</b> - based on the physical size of the screen.",
+
+        "px", //$NON-NLS-1$
+        "<b>Pixels</b> - corresponds to actual pixels on the screen. Not recommended.",
+    };
+
+    /**
+     * Fixed list of fractional units, along with user documentation, for use by
+     * {@link #completeSuffix}
+     */
+    private static final String[] sFractionUnits = new String[] {
+        "%",  //$NON-NLS-1$
+        "<b>Fraction</b> - a percentage of the base size",
+
+        "%p", //$NON-NLS-1$
+        "<b>Fraction</b> - a percentage relative to parent container",
+    };
 
+    /**
+     * Completes suffixes for applicable types (like dimensions and fractions) such that
+     * after a dimension number you get completion on unit types like "px".
+     */
+    private Object[] completeSuffix(Object[] choices, String value, UiAttributeNode currAttrNode) {
+        IAttributeInfo attributeInfo = currAttrNode.getDescriptor().getAttributeInfo();
+        Format[] formats = attributeInfo.getFormats();
+        List<Object> suffixes = new ArrayList<Object>();
+
+        if (value.length() > 0 && Character.isDigit(value.charAt(0))) {
+            boolean hasDimension = Format.DIMENSION.in(formats);
+            boolean hasFraction = Format.FRACTION.in(formats);
+
+            if (hasDimension || hasFraction) {
+                // Split up the value into a numeric part (the prefix) and the
+                // unit part (the suffix)
+                int suffixBegin = 0;
+                for (; suffixBegin < value.length(); suffixBegin++) {
+                    if (!Character.isDigit(value.charAt(suffixBegin))) {
+                        break;
+                    }
+                }
+                String number = value.substring(0, suffixBegin);
+                String suffix = value.substring(suffixBegin);
+
+                // Add in the matching dimension and/or fraction units, if any
+                if (hasDimension) {
+                    // Each item has two entries in the array of strings: the first odd numbered
+                    // ones are the unit names and the second even numbered ones are the
+                    // corresponding descriptions.
+                    for (int i = 0; i < sDimensionUnits.length; i += 2) {
+                        String unit = sDimensionUnits[i];
+                        if (startsWith(unit, suffix)) {
+                            String description = sDimensionUnits[i + 1];
+                            suffixes.add(Pair.of(number + unit, description));
+                        }
+                    }
 
+                    // Allow "dip" completion but don't offer it ("dp" is preferred)
+                    if (suffix.startsWith("di") || suffix.startsWith("dip")) { //$NON-NLS-1$ //$NON-NLS-2$
+                        suffixes.add(Pair.of(number + "dip", "Alternative name for \"dp\"")); //$NON-NLS-1$
+                    }
+                }
+                if (hasFraction) {
+                    for (int i = 0; i < sFractionUnits.length; i += 2) {
+                        String unit = sFractionUnits[i];
+                        if (startsWith(unit, suffix)) {
+                            String description = sFractionUnits[i + 1];
+                            suffixes.add(Pair.of(number + unit, description));
+                        }
+                    }
+                }
+            }
+        }
+
+        boolean hasFlag = Format.FLAG.in(formats);
+        if (hasFlag) {
+            boolean isDone = false;
+            String[] flagValues = attributeInfo.getFlagValues();
+            for (String flagValue : flagValues) {
+                if (flagValue.equals(value)) {
+                    isDone = true;
+                    break;
+                }
+            }
+            if (isDone) {
+                // Add in all the new values with a separator of |
+                String currentValue = currAttrNode.getCurrentValue();
+                for (String flagValue : flagValues) {
+                    if (currentValue == null || !currentValue.contains(flagValue)) {
+                        suffixes.add(value + '|' + flagValue);
+                    }
+                }
+            }
+        }
+
+        if (suffixes.size() > 0) {
+            // Merge previously added choices (from attribute enums etc) with the new matches
+            List<Object> all = new ArrayList<Object>();
+            if (choices != null) {
+                for (Object s : choices) {
+                    all.add(s);
+                }
+            }
+            all.addAll(suffixes);
+            choices = all.toArray();
+        }
+
+        return choices;
+    }
 }
index 38d8844..258db03 100644 (file)
@@ -18,23 +18,28 @@ package com.android.ide.eclipse.adt.internal.editors;
 
 
 import org.eclipse.jface.text.IAutoEditStrategy;
-import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
 import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
 import org.eclipse.jface.text.formatter.IContentFormatter;
 import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.viewers.IInputProvider;
 import org.eclipse.wst.sse.core.text.IStructuredPartitions;
 import org.eclipse.wst.xml.core.text.IXMLPartitions;
 import org.eclipse.wst.xml.ui.StructuredTextViewerConfigurationXML;
+import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 /**
  * Base Source Viewer Configuration for Android resources.
  */
+@SuppressWarnings("restriction") // XMLContentAssistProcessor
 public class AndroidSourceViewerConfig extends StructuredTextViewerConfigurationXML {
 
     /** Content Assist Processor to use for all handled partitions. */
@@ -67,17 +72,6 @@ public class AndroidSourceViewerConfig extends StructuredTextViewerConfiguration
         if (partitionType == IStructuredPartitions.UNKNOWN_PARTITION ||
             partitionType == IStructuredPartitions.DEFAULT_PARTITION ||
             partitionType == IXMLPartitions.XML_DEFAULT) {
-            if (sourceViewer instanceof IInputProvider) {
-                IInputProvider input = (IInputProvider) sourceViewer;
-                Object a = input.getInput();
-                if (a != null)
-                    a.toString();
-            }
-
-            IDocument doc = sourceViewer.getDocument();
-            if (doc != null)
-                doc.toString();
-
             processors.add(mProcessor);
         }
 
@@ -85,7 +79,13 @@ public class AndroidSourceViewerConfig extends StructuredTextViewerConfiguration
                 partitionType);
         if (others != null && others.length > 0) {
             for (IContentAssistProcessor p : others) {
-                processors.add(p);
+                // Builtin Eclipse WTP code completion assistant? If so,
+                // wrap it with our own filter which hides some unwanted completions.
+                if (p instanceof XMLContentAssistProcessor) {
+                    processors.add(new FilteringContentAssistProcessor(p));
+                } else {
+                    processors.add(p);
+                }
             }
         }
 
@@ -125,4 +125,69 @@ public class AndroidSourceViewerConfig extends StructuredTextViewerConfiguration
         return targets;
     }
 
+    /**
+     * A delegating {@link IContentAssistProcessor} whose purpose is to filter out some
+     * default Eclipse XML completions which are distracting in Android XML files
+     */
+    private class FilteringContentAssistProcessor implements IContentAssistProcessor {
+        private IContentAssistProcessor mDelegate;
+
+        public FilteringContentAssistProcessor(IContentAssistProcessor delegate) {
+            super();
+            mDelegate = delegate;
+        }
+
+        public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+            ICompletionProposal[] result = mDelegate.computeCompletionProposals(viewer, offset);
+            if (result == null) {
+                return null;
+            }
+
+            List<ICompletionProposal> proposals =
+                new ArrayList<ICompletionProposal>(result.length);
+            for (ICompletionProposal proposal : result) {
+                String replacement = proposal.getDisplayString();
+                if (replacement.charAt(0) == '"' &&
+                        replacement.charAt(replacement.length() - 1) == '"') {
+                    // Filter out attribute values. In Android XML files (where there is no DTD
+                    // etc) the default Eclipse XML code completion simply provides the
+                    // existing value as a completion. This is often misleading, since if you
+                    // for example have a typo, completion will show your current (wrong)
+                    // value as a valid completion.
+                } else if (replacement.contains("Namespace")  //$NON-NLS-1$
+                        || replacement.contains("Schema")) {  //$NON-NLS-1$
+                    // Eclipse adds in a number of namespace and schema related completions which
+                    // are not usually applicable in our files.
+                } else {
+                    proposals.add(proposal);
+                }
+            }
+
+            if (proposals.size() == result.length) {
+                return result;
+            } else {
+                return proposals.toArray(new ICompletionProposal[proposals.size()]);
+            }
+        }
+
+        public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
+            return mDelegate.computeContextInformation(viewer, offset);
+        }
+
+        public char[] getCompletionProposalAutoActivationCharacters() {
+            return mDelegate.getCompletionProposalAutoActivationCharacters();
+        }
+
+        public char[] getContextInformationAutoActivationCharacters() {
+            return mDelegate.getContextInformationAutoActivationCharacters();
+        }
+
+        public IContextInformationValidator getContextInformationValidator() {
+            return mDelegate.getContextInformationValidator();
+        }
+
+        public String getErrorMessage() {
+            return mDelegate.getErrorMessage();
+        }
+    }
 }
index 1cf11e4..e6df2ca 100644 (file)
@@ -35,7 +35,7 @@ import org.eclipse.swt.graphics.Image;
  * the correct UiAttributeNode-derived class.
  */
 public abstract class AttributeDescriptor {
-    private static final String ATTRIBUTE_ICON_FILENAME = "attribute"; //$NON-NLS-1$
+    public static final String ATTRIBUTE_ICON_FILENAME = "attribute"; //$NON-NLS-1$
 
     private final String mXmlLocalName;
     private final String mNsUri;
index 4b313f6..d55db31 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors.layout;
 
+import com.android.annotations.VisibleForTesting;
 import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
 
 /**
  * Content Assist Processor for /res/layout XML files
  */
-class LayoutContentAssist extends AndroidContentAssist {
+@VisibleForTesting
+public final class LayoutContentAssist extends AndroidContentAssist {
 
     /**
-     * Constructor for LayoutContentAssist 
+     * Constructor for LayoutContentAssist
      */
     public LayoutContentAssist() {
         super(AndroidTargetData.DESCRIPTOR_LAYOUT);
index 6e85412..193c3c0 100644 (file)
@@ -57,7 +57,7 @@ import static com.android.ide.common.layout.LayoutConstants.LINEAR_LAYOUT;
 import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX;
 import static com.android.ide.common.layout.LayoutConstants.RELATIVE_LAYOUT;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_FALSE;
-import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DIP;
+import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL;
 import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
@@ -911,7 +911,7 @@ class RelativeLayoutConversionHelper {
                             view.addHorizConstraint(attachLeftProperty, attachLeftValue);
                             if (marginLeft > 0) {
                                 view.addHorizConstraint(ATTR_LAYOUT_MARGIN_LEFT,
-                                        String.format(VALUE_N_DIP, marginLeft));
+                                        String.format(VALUE_N_DP, marginLeft));
                                 marginLeft = 0;
                             }
                         } else {
@@ -965,7 +965,7 @@ class RelativeLayoutConversionHelper {
                             view.addVerticalConstraint(attachTopProperty, attachTopValue);
                             if (marginTop > 0) {
                                 view.addVerticalConstraint(ATTR_LAYOUT_MARGIN_TOP,
-                                        String.format(VALUE_N_DIP, marginTop));
+                                        String.format(VALUE_N_DP, marginTop));
                                 marginTop = 0;
                             }
                         } else {
index 349048f..1c92309 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors.manifest;
 
+import com.android.annotations.VisibleForTesting;
 import com.android.ide.eclipse.adt.internal.editors.AndroidContentAssist;
 import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
 
 /**
  * Content Assist Processor for AndroidManifest.xml
  */
-final class ManifestContentAssist extends AndroidContentAssist {
+@VisibleForTesting
+public final class ManifestContentAssist extends AndroidContentAssist {
 
     /**
-     * Constructor for ManifestContentAssist 
+     * Constructor for ManifestContentAssist
      */
     public ManifestContentAssist() {
         super(AndroidTargetData.DESCRIPTOR_MANIFEST);
index 9032b46..c0ca837 100644 (file)
 
 package com.android.ide.eclipse.adt.internal.editors.uimodel;
 
+import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_STYLE;
 import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
 
+import com.android.ide.common.api.IAttributeInfo;
+import com.android.ide.common.api.IAttributeInfo.Format;
 import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
 import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceItem;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
@@ -49,7 +54,10 @@ import org.eclipse.ui.forms.widgets.TableWrapData;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.EnumSet;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -63,6 +71,8 @@ import java.util.regex.Pattern;
  * See {@link UiTextAttributeNode} for more information.
  */
 public class UiResourceAttributeNode extends UiTextAttributeNode {
+    /** The resource prefix @android: */
+    private static final String ANDROID_RESOURCE_PREFIX = '@' + ANDROID_PKG + ':';
 
     private ResourceType mType;
 
@@ -198,10 +208,11 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
      */
     @Override
     public String[] getPossibleValues(String prefix) {
-        return computeResourceStringMatches(getUiParent(), prefix);
+        return computeResourceStringMatches(getUiParent(), getDescriptor(), prefix);
     }
 
-    public static String[] computeResourceStringMatches(UiElementNode uiNode, String prefix) {
+    public static String[] computeResourceStringMatches(UiElementNode uiNode,
+            AttributeDescriptor attributeDescriptor, String prefix) {
         ResourceRepository repository = null;
         boolean isSystem = false;
         AndroidXmlEditor editor = uiNode.getEditor();
@@ -236,7 +247,7 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
         }
 
         // Now collect results
-        ArrayList<String> results = new ArrayList<String>();
+        List<String> results = new ArrayList<String>();
 
         if (typeName == null) {
             // This prefix does not have a / in it, so the resource string is either empty
@@ -245,13 +256,13 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
 
             for (ResourceType resType : resTypes) {
                 if (isSystem) {
-                    results.add("@" + ANDROID_PKG + ':' + resType.getName() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
+                    results.add(ANDROID_RESOURCE_PREFIX + resType.getName() + '/');
                 } else {
-                    results.add("@" + resType.getName() + "/");         //$NON-NLS-1$ //$NON-NLS-2$
+                    results.add('@' + resType.getName() + '/');
                 }
                 if (resType == ResourceType.ID) {
                     // Also offer the + version to create an id from scratch
-                    results.add("@+" + resType.getName() + "/");    //$NON-NLS-1$ //$NON-NLS-2$
+                    results.add("@+" + resType.getName() + '/');    //$NON-NLS-1$
                 }
             }
 
@@ -259,7 +270,7 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
             // "@an" we offer to complete it.
             if (prefix == null ||
                     ANDROID_PKG.regionMatches(0, prefix, 1, prefix.length() - 1)) {
-                results.add('@' + ANDROID_PKG + ':');
+                results.add(ANDROID_RESOURCE_PREFIX);
             }
         } else if (repository != null) {
             // We have a style name and a repository. Find all resources that match this
@@ -286,6 +297,94 @@ public class UiResourceAttributeNode extends UiTextAttributeNode {
             }
         }
 
+        sortAttributeChoices(attributeDescriptor, results);
+
         return results.toArray(new String[results.size()]);
     }
+
+    /**
+     * Attempts to sort the attribute values to bubble up the most likely choices to
+     * the top.
+     * <p>
+     * For example, if you are editing a style attribute, it's likely that among the
+     * resource values you would rather see @style or @android than @string.
+     */
+    private static void sortAttributeChoices(AttributeDescriptor descriptor,
+            List<String> choices) {
+        final IAttributeInfo attributeInfo = descriptor.getAttributeInfo();
+        Collections.sort(choices, new Comparator<String>() {
+            public int compare(String s1, String s2) {
+                int compare = score(attributeInfo, s1) - score(attributeInfo, s2);
+                if (compare == 0) {
+                    // Sort alphabetically as a fallback
+                    compare = s1.compareTo(s2);
+                }
+                return compare;
+            }
+        });
+    }
+
+    /** Compute a suitable sorting score for the given  */
+    private static final int score(IAttributeInfo attributeInfo, String value) {
+        if (value.equals(ANDROID_RESOURCE_PREFIX)) {
+            return -1;
+        }
+
+        for (Format format : attributeInfo.getFormats()) {
+            String type = null;
+            switch (format) {
+                case BOOLEAN:
+                    type = "bool"; //$NON-NLS-1$
+                    break;
+                case COLOR:
+                    type = "color"; //$NON-NLS-1$
+                    break;
+                case DIMENSION:
+                    type = "dimen"; //$NON-NLS-1$
+                    break;
+                case INTEGER:
+                    type = "integer"; //$NON-NLS-1$
+                    break;
+                case STRING:
+                    type = "string"; //$NON-NLS-1$
+                    break;
+                // default: REFERENCE, FLAG, ENUM, etc - don't have type info about individual
+                // elements to help make a decision
+            }
+
+            if (type != null) {
+                if (value.startsWith('@' + type + '/')) {
+                    return -2;
+                }
+
+                if (value.startsWith(ANDROID_RESOURCE_PREFIX + type + '/')) {
+                    return -2;
+                }
+            }
+        }
+
+        // Handle a few more cases not covered by the Format metadata check
+        String type = null;
+
+        String attribute = attributeInfo.getName();
+        if (attribute.equals(ATTR_ID)) {
+            type = "id"; //$NON-NLS-1$
+        } else if (attribute.equals(ATTR_STYLE)) {
+            type = "style"; //$NON-NLS-1$
+        } else if (attribute.equals(LayoutDescriptors.ATTR_LAYOUT)) {
+            type = "layout"; //$NON-NLS-1$
+        }
+
+        if (type != null) {
+            if (value.startsWith('@' + type + '/')) {
+                return -2;
+            }
+
+            if (value.startsWith(ANDROID_RESOURCE_PREFIX + type + '/')) {
+                return -2;
+            }
+        }
+
+        return 0;
+    }
 }
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java
new file mode 100644 (file)
index 0000000..38e3bfd
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2011 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.adt.internal.editors;
+
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.layout.LayoutContentAssist;
+import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestContentAssist;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+
+public class AndroidContentAssistTest extends AdtProjectTest {
+    private static final String CARET = "^"; //$NON-NLS-1$
+
+    public void testStartsWith() {
+        assertTrue(AndroidContentAssist.startsWith("", ""));
+        assertTrue(AndroidContentAssist.startsWith("a", ""));
+        assertTrue(AndroidContentAssist.startsWith("A", ""));
+        assertTrue(AndroidContentAssist.startsWith("A", "a"));
+        assertTrue(AndroidContentAssist.startsWith("A", "A"));
+        assertTrue(AndroidContentAssist.startsWith("Ab", "a"));
+        assertTrue(AndroidContentAssist.startsWith("ab", "A"));
+        assertTrue(AndroidContentAssist.startsWith("ab", "AB"));
+        assertFalse(AndroidContentAssist.startsWith("ab", "ABc"));
+        assertFalse(AndroidContentAssist.startsWith("", "ABc"));
+    }
+
+    public void testCompletion1() throws Exception {
+        // Change attribute name completion
+        checkLayoutCompletion("completion1.xml", "layout_w^idth=\"fill_parent\"");
+    }
+
+    public void testCompletion2() throws Exception {
+        // Check attribute value completion for enum
+        checkLayoutCompletion("completion1.xml", "layout_width=\"^fill_parent\"");
+    }
+
+    public void testCompletion3() throws Exception {
+        // Check attribute value completion for enum with a prefix
+        checkLayoutCompletion("completion1.xml", "layout_width=\"fi^ll_parent\"");
+    }
+
+    public void testCompletion4() throws Exception {
+        // Check attribute value completion on units
+        checkLayoutCompletion("completion1.xml", "marginBottom=\"50^\"");
+    }
+
+    public void testCompletion5() throws Exception {
+        // Check attribute value completion on units with prefix
+        checkLayoutCompletion("completion1.xml", "layout_marginLeft=\"50d^p\"");
+    }
+
+    public void testCompletion6() throws Exception {
+        // Check resource sorting - "style" should bubble to the top for a style attribute
+        checkLayoutCompletion("completion1.xml", "style=\"@android:^style/Widget.Button\"");
+    }
+
+    public void testCompletion7a() throws Exception {
+        // Check flags (multiple values inside a single XML value, separated by | - where
+        // the prefix is reset as soon as you pass each | )
+        checkLayoutCompletion("completion1.xml", "android:gravity=\"l^eft|bottom\"");
+    }
+
+    public void testCompletion7b() throws Exception {
+        checkLayoutCompletion("completion1.xml", "android:gravity=\"left|b^ottom\"");
+    }
+
+    public void testCompletion8() throws Exception {
+        // Test completion right at the "=" sign; this will be taken to be the last
+        // character of the attribute name (the caret is between the last char and before
+        // the = characters), so it should match a single attribute
+        checkLayoutCompletion("completion1.xml", "layout_width^=\"fill_parent\"");
+    }
+
+    public void testCompletion9() throws Exception {
+        // Test completion right after the "=" sign; this will be taken to be the beginning
+        // of the attribute value, but all values will also include a leading quote
+        checkLayoutCompletion("completion1.xml", "layout_width=^\"fill_parent\"");
+    }
+
+    public void testCompletion10() throws Exception {
+        // Test completion of element names
+        checkLayoutCompletion("completion1.xml", "<T^extView");
+    }
+
+    public void testCompletion11() throws Exception {
+        // Test completion of element names at the outside of the <. This should include
+        // all the elements too (along with the leading <).
+        checkLayoutCompletion("completion1.xml", "^<TextView");
+    }
+
+    public void testCompletion12() throws Exception {
+        // Test completion of element names inside a nested XML; ensure that this will
+        // correctly compute element names, not previous attribute
+        checkLayoutCompletion("completion1.xml", "btn_default\">^</FrameLayout>");
+    }
+
+    public void testCompletion13a() throws Exception {
+        checkLayoutCompletion("completion2.xml", "gravity=\"left|bottom|^cen");
+    }
+
+    public void testCompletion13b() throws Exception {
+        checkLayoutCompletion("completion2.xml", "gravity=\"left|bottom|cen^");
+    }
+
+    public void testCompletion13c() throws Exception {
+        checkLayoutCompletion("completion2.xml", "gravity=\"left|bottom^|cen");
+    }
+
+    public void testCompletion14() throws Exception {
+        // Test completion of permissions
+        checkManifestCompletion("manifest.xml", "android.permission.ACC^ESS_NETWORK_STATE");
+    }
+
+    public void testCompletion15() throws Exception {
+        // Test completion of intents
+        checkManifestCompletion("manifest.xml", "android.intent.category.L^AUNCHER");
+    }
+
+    public void testCompletion16() throws Exception {
+        // Test completion of top level elements
+        checkManifestCompletion("manifest.xml", "<^application android:i");
+    }
+
+    public void testCompletion17() throws Exception {
+        // Test completion of attributes on the manifest element
+        checkManifestCompletion("manifest.xml", "^android:versionCode=\"1\"");
+    }
+
+    public void testCompletion18() throws Exception {
+        // Test completion of attributes on the manifest element
+        checkManifestCompletion("manifest.xml",
+                "<activity android:^name=\".TestActivity\"");
+    }
+
+    // ---- Test *applying* code completion ----
+
+    // The following tests check -applying- a specific code completion
+    // match - this verifies that the document is updated correctly, the
+    // caret is moved appropriately, etc.
+
+    public void testApplyCompletion1() throws Exception {
+        // Change attribute name completion
+        checkApplyLayoutCompletion("completion1.xml", "layout_w^idth=\"fill_parent\"",
+                "android:layout_weight");
+    }
+
+    public void testApplyCompletion2() throws Exception {
+        // Check attribute value completion for enum
+        checkApplyLayoutCompletion("completion1.xml", "layout_width=\"^fill_parent\"",
+                "match_parent");
+    }
+
+    public void testApplyCompletion3() throws Exception {
+        // Check attribute value completion for enum with a prefix
+        checkApplyLayoutCompletion("completion1.xml", "layout_width=\"fi^ll_parent\"",
+                "fill_parent");
+    }
+
+    public void testApplyCompletion4() throws Exception {
+        // Check attribute value completion on units
+        checkApplyLayoutCompletion("completion1.xml", "marginBottom=\"50^\"", "50mm");
+    }
+
+    public void testApplyCompletion5() throws Exception {
+        // Check attribute value completion on units with prefix
+        checkApplyLayoutCompletion("completion1.xml", "layout_marginLeft=\"50d^p\"", "50dp");
+    }
+
+    public void testApplyCompletion6() throws Exception {
+        // Check resource sorting - "style" should bubble to the top for a style attribute
+        checkApplyLayoutCompletion("completion1.xml", "style=\"@android:^style/Widget.Button\"",
+                "@android:drawable/");
+    }
+
+    public void testApplyCompletion7a() throws Exception {
+        // Check flags (multiple values inside a single XML value, separated by | - where
+        // the prefix is reset as soon as you pass each | )
+        checkApplyLayoutCompletion("completion1.xml", "android:gravity=\"l^eft|bottom\"",
+                "left");
+        // NOTE - this will replace all flag values with the newly selected value.
+        // That may not be the best behavior - perhaps we should only replace one portion
+        // of the value.
+    }
+
+    public void testApplyCompletion7b() throws Exception {
+        checkApplyLayoutCompletion("completion1.xml", "android:gravity=\"left|b^ottom\"",
+                "bottom");
+        // NOTE - this will replace all flag values with the newly selected value.
+        // That may not be the best behavior - perhaps we should only replace one portion
+        // of the value.
+    }
+
+    public void testApplyCompletion8() throws Exception {
+        // Test completion right at the "=" sign; this will be taken to be the last
+        // character of the attribute name (the caret is between the last char and before
+        // the = characters), so it should match a single attribute
+        checkApplyLayoutCompletion("completion1.xml", "layout_width^=\"fill_parent\"",
+                "android:layout_width");
+    }
+
+    public void testApplyCompletion9() throws Exception {
+        // Test completion right after the "=" sign; this will be taken to be the beginning
+        // of the attribute value, but all values will also include a leading quote
+        checkApplyLayoutCompletion("completion1.xml", "layout_width=^\"fill_parent\"",
+                "\"wrap_content\"");
+    }
+
+    public void testApplyCompletion10() throws Exception {
+        // Test completion of element names
+        checkApplyLayoutCompletion("completion1.xml", "<T^extView", "TableLayout");
+    }
+
+    public void testApplyCompletion11a() throws Exception {
+        // Test completion of element names at the outside of the <. This should include
+        // all the elements too (along with the leading <).
+        checkApplyLayoutCompletion("completion1.xml", "^<TextView", "<RadioGroup ></RadioGroup>");
+    }
+
+    public void testApplyCompletion11b() throws Exception {
+        // Similar to testApplyCompletion11a, but replacing with an element that does not
+        // have children (to test the closing tag insertion code)
+        checkApplyLayoutCompletion("completion1.xml", "^<TextView", "<CheckBox />");
+    }
+
+    public void testApplyCompletion12() throws Exception {
+        // Test completion of element names inside a nested XML; ensure that this will
+        // correctly compute element names, not previous attribute
+        checkApplyLayoutCompletion("completion1.xml", "btn_default\">^</FrameLayout>",
+                "<FrameLayout ></FrameLayout>");
+    }
+
+    public void testApplyCompletion13a() throws Exception {
+        checkApplyLayoutCompletion("completion2.xml", "gravity=\"left|bottom|^cen",
+                "fill_vertical");
+    }
+
+    public void testApplyCompletion13b() throws Exception {
+        checkApplyLayoutCompletion("completion2.xml", "gravity=\"left|bottom|cen^",
+                "center_horizontal");
+    }
+
+    public void testApplyCompletion13c() throws Exception {
+        checkApplyLayoutCompletion("completion2.xml", "gravity=\"left|bottom^|cen",
+                "bottom|fill_horizontal");
+    }
+
+    // --- Code Completion test infrastructure ----
+
+    private void checkLayoutCompletion(String name, String caretLocation) throws Exception {
+        checkCompletion(name, getLayoutFile(getProject(), name), caretLocation,
+                new LayoutContentAssist());
+    }
+
+    private void checkManifestCompletion(String name, String caretLocation) throws Exception {
+        // Manifest files must be named AndroidManifest.xml. Must overwrite to replace
+        // the default manifest created in the test project.
+        IFile file = getTestDataFile(getProject(), name, "AndroidManifest.xml", true);
+
+        checkCompletion(name, file, caretLocation,
+                new ManifestContentAssist());
+    }
+
+    private void checkApplyLayoutCompletion(String name, String caretLocation,
+            String match) throws Exception {
+        checkApplyCompletion(name, getLayoutFile(getProject(), name), caretLocation,
+                new LayoutContentAssist(), match);
+    }
+
+    private ICompletionProposal[] complete(IFile file, String caretLocation,
+            AndroidContentAssist assist) throws Exception {
+
+        // Determine the offset
+        String fileContent = AdtPlugin.readFile(file);
+        int caretDelta = caretLocation.indexOf(CARET);
+        assertTrue(caretLocation, caretDelta != -1);
+        String caretContext = caretLocation.substring(0, caretDelta)
+            + caretLocation.substring(caretDelta + CARET.length());
+        int caretContextIndex = fileContent.indexOf(caretContext);
+        assertTrue("Caret content " + caretContext + " not found in file",
+                caretContextIndex != -1);
+        int offset = caretContextIndex + caretDelta;
+
+        // Open file
+        IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+        assertNotNull(page);
+        IEditorPart editor = IDE.openEditor(page, file);
+        assertTrue(editor instanceof AndroidXmlEditor);
+        AndroidXmlEditor layoutEditor = (AndroidXmlEditor) editor;
+        ISourceViewer viewer = layoutEditor.getStructuredSourceViewer();
+
+        // Run code completion
+        ICompletionProposal[] proposals = assist.computeCompletionProposals(viewer, offset);
+        if (proposals == null) {
+            proposals = new ICompletionProposal[0];
+        }
+
+        return proposals;
+    }
+
+    private void checkApplyCompletion(String basename, IFile file, String caretLocation,
+            AndroidContentAssist assist, String match) throws Exception {
+        ICompletionProposal[] proposals = complete(file, caretLocation, assist);
+        ICompletionProposal chosen = null;
+        for (ICompletionProposal proposal : proposals) {
+            if (proposal.getDisplayString().equals(match)) {
+                chosen = proposal;
+                break;
+            }
+        }
+        assertNotNull(chosen);
+        assert chosen != null; // Eclipse null pointer analysis doesn't believe the JUnit assertion
+
+        String fileContent = AdtPlugin.readFile(file);
+        IDocument document = new Document();
+        document.set(fileContent);
+
+        // Apply code completion
+        chosen.apply(document);
+
+        // Insert caret location as well
+        Point location = chosen.getSelection(document);
+        document.replace(location.x, 0, CARET);
+
+        String actual = document.get();
+
+        String diff = getDiff(fileContent, actual);
+        assertTrue(diff.length() > 0 || fileContent.equals(actual));
+
+        StringBuilder summary = new StringBuilder();
+        summary.append("Code completion in " + basename + " for " + caretLocation + " selecting " + match + ":\n");
+        summary.append(diff);
+
+        //assertEqualsGolden(basename, actual);
+        assertEqualsGolden(basename, summary.toString(), "diff");
+    }
+
+    private void checkCompletion(String basename, IFile file, String caretLocation,
+                AndroidContentAssist assist) throws Exception {
+        ICompletionProposal[] proposals = complete(file, caretLocation, assist);
+        StringBuilder sb = new StringBuilder(1000);
+        sb.append("Code completion in " + basename + " for " + caretLocation + ":\n");
+        for (ICompletionProposal proposal : proposals) {
+            sb.append(proposal.getDisplayString());
+            String help = proposal.getAdditionalProposalInfo();
+            if (help != null && help.trim().length() > 0) {
+                sb.append(" : ");
+                sb.append(help.replace('\n', ' '));
+            }
+            sb.append('\n');
+        }
+        assertEqualsGolden(basename, sb.toString(), "txt");
+    }
+}
index b18afa1..4281077 100644 (file)
@@ -15,6 +15,9 @@
  */
 package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
 
+import static com.android.AndroidConstants.FD_RES_LAYOUT;
+import static com.android.sdklib.SdkConstants.FD_RES;
+
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
@@ -27,13 +30,16 @@ import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizard;
 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewTestProjectCreationPage;
 import com.android.ide.eclipse.tests.SdkTestCase;
 import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
 
+import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.wizard.IWizardContainer;
 import org.eclipse.jface.wizard.IWizardPage;
@@ -82,28 +88,53 @@ public class AdtProjectTest extends SdkTestCase {
         return getTestDataFile(project, name, name);
     }
 
+    protected IFile getLayoutFile(IProject project, String name) throws Exception {
+        return getTestDataFile(project, name, FD_RES + "/" + FD_RES_LAYOUT + "/" + name);
+    }
+
     protected IFile getTestDataFile(IProject project, String sourceName,
             String destPath) throws Exception {
+        return getTestDataFile(project, sourceName, destPath, false);
+    }
+
+    protected IFile getTestDataFile(IProject project, String sourceName,
+            String destPath, boolean overwrite) throws Exception {
         String[] split = destPath.split("/"); //$NON-NLS-1$
-        assertTrue(split.length > 1);
-        IFolder folder = project.getFolder(split[0]);
-        NullProgressMonitor monitor = new NullProgressMonitor();
-        if (!folder.exists()) {
-            folder.create(true /* force */, true /* local */, monitor);
+        IContainer parent;
+        String name;
+        if (split.length == 1) {
+            parent = project;
+            name = destPath;
+        } else {
+            IFolder folder = project.getFolder(split[0]);
+            NullProgressMonitor monitor = new NullProgressMonitor();
+            if (!folder.exists()) {
+                folder.create(true /* force */, true /* local */, monitor);
+            }
+            for (int i = 1, n = split.length; i < n -1; i++) {
+                IFolder subFolder = folder.getFolder(split[i]);
+                if (!subFolder.exists()) {
+                    subFolder.create(true /* force */, true /* local */, monitor);
+                }
+                folder = subFolder;
+            }
+            name = split[split.length - 1];
+            parent = folder;
         }
-        for (int i = 1, n = split.length; i < n -1; i++) {
-            IFolder subFolder = folder.getFolder(split[i]);
-            if (!subFolder.exists()) {
-                subFolder.create(true /* force */, true /* local */, monitor);
+        IFile file = parent.getFile(new Path(name));
+        if (overwrite && file.exists()) {
+            String currentContents = AdtPlugin.readFile(file);
+            String newContents = readTestFile(sourceName, true);
+            if (currentContents == null || !currentContents.equals(newContents)) {
+                file.delete(true, new NullProgressMonitor());
+            } else {
+                return file;
             }
-            folder = subFolder;
         }
-
-        String name = split[split.length - 1];
-        IFile file = folder.getFile(name);
         if (!file.exists()) {
             String xml = readTestFile(sourceName, true);
             InputStream bstream = new ByteArrayInputStream(xml.getBytes("UTF-8")); //$NON-NLS-1$
+            NullProgressMonitor monitor = new NullProgressMonitor();
             file.create(bstream, false /* force */, monitor);
         }
 
@@ -161,6 +192,52 @@ public class AdtProjectTest extends SdkTestCase {
         return iproject;
     }
 
+    /**
+     * Very primitive line differ, intended for files where there are very minor changes
+     * (such as code completion apply-tests)
+     */
+    protected String getDiff(String before, String after) {
+
+        // Do line by line analysis
+        String[] beforeLines = before.split("\n");
+        String[] afterLines = after.split("\n");
+
+        int firstDelta = 0;
+        for (; firstDelta < Math.min(beforeLines.length, afterLines.length); firstDelta++) {
+            if (!beforeLines[firstDelta].equals(afterLines[firstDelta])) {
+                break;
+            }
+        }
+
+        if (firstDelta == beforeLines.length && firstDelta == afterLines.length) {
+            return "";
+        }
+
+        // Counts from the end of both arrays
+        int lastDelta = 0;
+        for (; lastDelta < Math.min(beforeLines.length, afterLines.length); lastDelta++) {
+            if (!beforeLines[beforeLines.length - 1 - lastDelta].equals(
+                    afterLines[afterLines.length - 1 - lastDelta])) {
+                break;
+            }
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = firstDelta; i < beforeLines.length - lastDelta; i++) {
+            sb.append("< ");
+            sb.append(beforeLines[i]);
+            sb.append('\n');
+        }
+        sb.append("---\n");
+        for (int i = firstDelta; i < afterLines.length - lastDelta; i++) {
+            sb.append("> ");
+            sb.append(afterLines[i]);
+            sb.append('\n');
+        }
+
+        return sb.toString();
+    }
+
     public static ViewElementDescriptor createDesc(String name, String fqn, boolean hasChildren) {
         if (hasChildren) {
             return new ViewElementDescriptor(name, name, fqn, "", "", new AttributeDescriptor[0],
@@ -203,6 +280,55 @@ public class AdtProjectTest extends SdkTestCase {
         return xml;
     }
 
+    protected void assertEqualsGolden(String basename, String actual) {
+        assertEqualsGolden(basename, actual, basename.substring(basename.lastIndexOf('.') + 1));
+    }
+
+    protected void assertEqualsGolden(String basename, String actual, String newExtension) {
+        String testName = getName();
+        if (testName.startsWith("test")) {
+            testName = testName.substring(4);
+            if (Character.isUpperCase(testName.charAt(0))) {
+                testName = Character.toLowerCase(testName.charAt(0)) + testName.substring(1);
+            }
+        }
+        String expectedName;
+        String extension = basename.substring(basename.lastIndexOf('.') + 1);
+        if (newExtension == null) {
+            newExtension = extension;
+        }
+        expectedName = basename.substring(0, basename.indexOf('.'))
+                + "-expected-" + testName + '.' + newExtension;
+        String expected = readTestFile(expectedName, false);
+        if (expected == null) {
+            File expectedPath = new File(getTempDir(), expectedName);
+            AdtPlugin.writeFile(expectedPath, actual);
+            System.out.println("Expected - written to " + expectedPath + ":\n");
+            System.out.println(actual);
+            fail("Did not find golden file (" + expectedName + "): Wrote contents as "
+                    + expectedPath);
+        } else {
+            if (!expected.equals(actual)) {
+                File expectedPath = new File(getTempDir(), expectedName);
+                File actualPath = new File(getTempDir(),
+                        expectedName.replace("expected", "actual"));
+               AdtPlugin.writeFile(expectedPath, expected);
+                AdtPlugin.writeFile(actualPath, actual);
+                System.out.println("The files differ - see " + expectedPath + " versus "
+                        + actualPath);
+                assertEquals("The files differ - see " + expectedPath + " versus " + actualPath,
+                        expected, actual);
+            }
+        }
+    }
+
+    protected File getTempDir() {
+        if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) {
+            return new File("/tmp"); //$NON-NLS-1$
+        }
+        return new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
+    }
+
     /** Special editor context set on the model to be rendered */
     protected static class TestLayoutEditor extends LayoutEditor {
         private final IFile mFile;
index 372026c..947840c 100644 (file)
  */
 package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
 
-import static com.android.AndroidConstants.FD_RES_LAYOUT;
 import static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX;
-import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML;
-import static com.android.sdklib.SdkConstants.FD_RES;
 
 import com.android.ide.common.rendering.api.ViewInfo;
-import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.sdklib.SdkConstants;
 
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.Document;
@@ -46,7 +40,6 @@ import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
 import org.w3c.dom.Element;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -59,10 +52,6 @@ import java.util.regex.Pattern;
 @SuppressWarnings("restriction")
 public class RefactoringTest extends AdtProjectTest {
 
-    protected IFile getLayoutFile(IProject project, String name) throws Exception {
-        return getTestDataFile(project, name, FD_RES + "/" + FD_RES_LAYOUT + "/" + name);
-    }
-
     protected static Element findElementById(Element root, String id) {
         if (id.equals(VisualRefactoring.getId(root))) {
             return root;
@@ -153,44 +142,6 @@ public class RefactoringTest extends AdtProjectTest {
         }
     }
 
-    protected void assertEqualsGolden(String basename, String actual) {
-        String testName = getName();
-        if (testName.startsWith("test")) {
-            testName = testName.substring(4);
-            if (Character.isUpperCase(testName.charAt(0))) {
-                testName = Character.toLowerCase(testName.charAt(0)) + testName.substring(1);
-            }
-        }
-        String expectedName;
-        if (basename.endsWith(DOT_XML)) {
-            expectedName = basename.substring(0, basename.length() - DOT_XML.length())
-                    + "-expected-" + testName + DOT_XML;
-        } else {
-            expectedName = basename + ".expected";
-        }
-        String expected = readTestFile(expectedName, false);
-        if (expected == null) {
-            File expectedPath = new File(getTempDir(), expectedName);
-            AdtPlugin.writeFile(expectedPath, actual);
-            System.out.println("Expected - written to " + expectedPath + ":\n");
-            System.out.println(actual);
-            fail("Did not find golden file (" + expectedName + "): Wrote contents as "
-                    + expectedPath);
-        } else {
-            if (!expected.equals(actual)) {
-                File expectedPath = new File(getTempDir(), expectedName);
-                File actualPath = new File(getTempDir(),
-                        expectedName.replace("expected", "actual"));
-               AdtPlugin.writeFile(expectedPath, expected);
-                AdtPlugin.writeFile(actualPath, actual);
-                System.out.println("The files differ - see " + expectedPath + " versus "
-                        + actualPath);
-                assertEquals("The files differ - see " + expectedPath + " versus " + actualPath,
-                        expected, actual);
-            }
-        }
-    }
-
     protected UiViewElementNode createModel(UiViewElementNode parent, Element element) {
         List<Element> children = DomUtilities.getChildren(element);
         String fqcn = ANDROID_WIDGET_PREFIX + element.getTagName();
@@ -260,13 +211,6 @@ public class RefactoringTest extends AdtProjectTest {
         return view;
     }
 
-    protected File getTempDir() {
-        if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) {
-            return new File("/tmp"); //$NON-NLS-1$
-        }
-        return new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
-    }
-
     protected TestContext setupTestContext(IFile file, String relativePath) throws Exception {
         IStructuredModel structuredModel = null;
         org.w3c.dom.Document domDocument = null;
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-actual-applyCompletion1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-actual-applyCompletion1.xml
new file mode 100644 (file)
index 0000000..2413658
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
+<!--  
+  This file deliberately contains errors - it represents partial keyboard
+  typing for interactive code completion
+-->
+    <TextView
+        android:layout_weight^="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@android:dimen/app_icon_size"
+        android:layout_marginLeft="50dp"
+        android:layout_marginBottom="50"
+        android:textColor="#000000"
+        style="@android:style/Widget.Button"
+        android:gravity="left|bottom"
+        android:text="@string/hello"
+        android:hint="hint" />
+    <FrameLayout android:foreground="@android:drawable/btn_default"></FrameLayout> 
+</LinearLayout>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion1.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion1.diff
new file mode 100644 (file)
index 0000000..08ba349
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_w^idth="fill_parent" selecting android:layout_weight:
+<         android:layout_width="fill_parent"
+---
+>         android:layout_weight^="fill_parent"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion10.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion10.diff
new file mode 100644 (file)
index 0000000..4cde056
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for <T^extView selecting TableLayout:
+<     <TextView
+---
+>     <TableLayout^
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11a.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11a.diff
new file mode 100644 (file)
index 0000000..7d1fd13
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for ^<TextView selecting <RadioGroup ></RadioGroup>:
+<     <TextView
+---
+>     <RadioGroup ^></RadioGroup><TextView
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11b.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion11b.diff
new file mode 100644 (file)
index 0000000..62bf772
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for ^<TextView selecting <CheckBox />:
+<     <TextView
+---
+>     <CheckBox ^/><TextView
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion12.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion12.diff
new file mode 100644 (file)
index 0000000..2d767a9
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for btn_default">^</FrameLayout> selecting <FrameLayout ></FrameLayout>:
+<     <FrameLayout android:foreground="@android:drawable/btn_default"></FrameLayout> 
+---
+>     <FrameLayout android:foreground="@android:drawable/btn_default"><FrameLayout ^></FrameLayout></FrameLayout> 
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion2.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion2.diff
new file mode 100644 (file)
index 0000000..8e0b3e4
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width="^fill_parent" selecting match_parent:
+<         android:layout_width="fill_parent"
+---
+>         android:layout_width="match_parent^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion3.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion3.diff
new file mode 100644 (file)
index 0000000..5b956a5
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width="fi^ll_parent" selecting fill_parent:
+<         android:layout_width="fill_parent"
+---
+>         android:layout_width="fill_parent^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion4.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion4.diff
new file mode 100644 (file)
index 0000000..818b1fa
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for marginBottom="50^" selecting 50mm:
+<         android:layout_marginBottom="50"
+---
+>         android:layout_marginBottom="50mm^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion5.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion5.diff
new file mode 100644 (file)
index 0000000..5571fd7
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_marginLeft="50d^p" selecting 50dp:
+<         android:layout_marginLeft="50dp"
+---
+>         android:layout_marginLeft="50dp^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion6.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion6.diff
new file mode 100644 (file)
index 0000000..404b2a9
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for style="@android:^style/Widget.Button" selecting @android:drawable/:
+<         style="@android:style/Widget.Button"
+---
+>         style="@android:drawable/^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7a.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7a.diff
new file mode 100644 (file)
index 0000000..e1d019a
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for android:gravity="l^eft|bottom" selecting left:
+<         android:gravity="left|bottom"
+---
+>         android:gravity="left^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7b.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion7b.diff
new file mode 100644 (file)
index 0000000..2fbd2e5
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for android:gravity="left|b^ottom" selecting bottom:
+<         android:gravity="left|bottom"
+---
+>         android:gravity="left|bottom^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion8.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion8.diff
new file mode 100644 (file)
index 0000000..dafdeff
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width^="fill_parent" selecting android:layout_width:
+<         android:layout_width="fill_parent"
+---
+>         android:layout_width^="fill_parent"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion9.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-applyCompletion9.diff
new file mode 100644 (file)
index 0000000..be0c226
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width=^"fill_parent" selecting "wrap_content":
+<         android:layout_width="fill_parent"
+---
+>         android:layout_width="wrap_content^"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion1.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion1.txt
new file mode 100644 (file)
index 0000000..949067a
--- /dev/null
@@ -0,0 +1,3 @@
+Code completion in completion1.xml for layout_w^idth="fill_parent":
+android:layout_width : Specifies the basic width of the view.  [dimension, enum] 
+android:layout_weight : [float] 
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion10.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion10.txt
new file mode 100644 (file)
index 0000000..68efdfb
--- /dev/null
@@ -0,0 +1,10 @@
+Code completion in completion1.xml for <T^extView:
+TabHost
+TabWidget
+TableLayout
+TableRow
+TextSwitcher
+TextView
+TimePicker
+ToggleButton
+TwoLineListItem
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion11.txt
new file mode 100644 (file)
index 0000000..670b03e
--- /dev/null
@@ -0,0 +1,60 @@
+Code completion in completion1.xml for ^<TextView:
+<AbsoluteLayout ></AbsoluteLayout>
+<AdapterViewFlipper ></AdapterViewFlipper>
+<DialerFilter ></DialerFilter>
+<ExpandableListView ></ExpandableListView>
+<FrameLayout ></FrameLayout>
+<GridView ></GridView>
+<HorizontalScrollView ></HorizontalScrollView>
+<ImageSwitcher ></ImageSwitcher>
+<LinearLayout ></LinearLayout>
+<ListView ></ListView>
+<MediaController ></MediaController>
+<RadioGroup ></RadioGroup>
+<RelativeLayout ></RelativeLayout>
+<ScrollView ></ScrollView>
+<SearchView ></SearchView>
+<SlidingDrawer ></SlidingDrawer> : SlidingDrawer specific attributes.
+<StackView ></StackView>
+<TabHost ></TabHost>
+<TabWidget ></TabWidget>
+<TableLayout ></TableLayout>
+<TableRow ></TableRow>
+<TextSwitcher ></TextSwitcher>
+<ViewAnimator ></ViewAnimator>
+<ViewFlipper ></ViewFlipper>
+<ViewSwitcher ></ViewSwitcher>
+<GestureOverlayView /> : GestureOverlayView specific attributes.
+<SurfaceView />
+<View /> : Attributes that can be used with android.view.View or any of its subclasses.
+<ViewStub /> : A android.view.ViewStub lets you lazily include other XML layouts inside your application  at runtime.
+<WebView />
+<AnalogClock />
+<AutoCompleteTextView />
+<Button />
+<CalendarView />
+<CheckBox />
+<CheckedTextView />
+<Chronometer />
+<DatePicker />
+<DigitalClock />
+<EditText />
+<Gallery />
+<ImageButton />
+<ImageView />
+<MultiAutoCompleteTextView />
+<NumberPicker />
+<ProgressBar />
+<QuickContactBadge />
+<RadioButton />
+<RatingBar />
+<SeekBar />
+<Spinner />
+<TextView />
+<TimePicker />
+<ToggleButton />
+<TwoLineListItem />
+<VideoView />
+<ZoomButton />
+<ZoomControls />
+<include /> : Lets you statically include XML layouts inside other XML layouts.
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion12.txt
new file mode 100644 (file)
index 0000000..4af986b
--- /dev/null
@@ -0,0 +1,60 @@
+Code completion in completion1.xml for btn_default">^</FrameLayout>:
+<AbsoluteLayout ></AbsoluteLayout>
+<AdapterViewFlipper ></AdapterViewFlipper>
+<DialerFilter ></DialerFilter>
+<ExpandableListView ></ExpandableListView>
+<FrameLayout ></FrameLayout>
+<GridView ></GridView>
+<HorizontalScrollView ></HorizontalScrollView>
+<ImageSwitcher ></ImageSwitcher>
+<LinearLayout ></LinearLayout>
+<ListView ></ListView>
+<MediaController ></MediaController>
+<RadioGroup ></RadioGroup>
+<RelativeLayout ></RelativeLayout>
+<ScrollView ></ScrollView>
+<SearchView ></SearchView>
+<SlidingDrawer ></SlidingDrawer> : SlidingDrawer specific attributes.
+<StackView ></StackView>
+<TabHost ></TabHost>
+<TabWidget ></TabWidget>
+<TableLayout ></TableLayout>
+<TableRow ></TableRow>
+<TextSwitcher ></TextSwitcher>
+<ViewAnimator ></ViewAnimator>
+<ViewFlipper ></ViewFlipper>
+<ViewSwitcher ></ViewSwitcher>
+<GestureOverlayView /> : GestureOverlayView specific attributes.
+<SurfaceView />
+<View /> : Attributes that can be used with android.view.View or any of its subclasses.
+<ViewStub /> : A android.view.ViewStub lets you lazily include other XML layouts inside your application  at runtime.
+<WebView />
+<AnalogClock />
+<AutoCompleteTextView />
+<Button />
+<CalendarView />
+<CheckBox />
+<CheckedTextView />
+<Chronometer />
+<DatePicker />
+<DigitalClock />
+<EditText />
+<Gallery />
+<ImageButton />
+<ImageView />
+<MultiAutoCompleteTextView />
+<NumberPicker />
+<ProgressBar />
+<QuickContactBadge />
+<RadioButton />
+<RatingBar />
+<SeekBar />
+<Spinner />
+<TextView />
+<TimePicker />
+<ToggleButton />
+<TwoLineListItem />
+<VideoView />
+<ZoomButton />
+<ZoomControls />
+<include /> : Lets you statically include XML layouts inside other XML layouts.
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion2.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion2.txt
new file mode 100644 (file)
index 0000000..136a6fe
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width="^fill_parent":
+fill_parent
+match_parent
+wrap_content
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion3.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion3.txt
new file mode 100644 (file)
index 0000000..09c27ce
--- /dev/null
@@ -0,0 +1,2 @@
+Code completion in completion1.xml for layout_width="fi^ll_parent":
+fill_parent
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion4.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion4.txt
new file mode 100644 (file)
index 0000000..a9111eb
--- /dev/null
@@ -0,0 +1,7 @@
+Code completion in completion1.xml for marginBottom="50^":
+50dp : <b>Density-independent Pixels</b> - an abstract unit that is based on the physical density of the screen.
+50sp : <b>Scale-independent Pixels</b> - this is like the dp unit, but it is also scaled by the user's font size preference.
+50pt : <b>Points</b> - 1/72 of an inch based on the physical size of the screen.
+50mm : <b>Millimeters</b> - based on the physical size of the screen.
+50in : <b>Inches</b> - based on the physical size of the screen.
+50px : <b>Pixels</b> - corresponds to actual pixels on the screen. Not recommended.
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion5.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion5.txt
new file mode 100644 (file)
index 0000000..6b1c993
--- /dev/null
@@ -0,0 +1,2 @@
+Code completion in completion1.xml for layout_marginLeft="50d^p":
+50dp : <b>Density-independent Pixels</b> - an abstract unit that is based on the physical density of the screen.
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion6.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion6.txt
new file mode 100644 (file)
index 0000000..0853a83
--- /dev/null
@@ -0,0 +1,22 @@
+Code completion in completion1.xml for style="@android:^style/Widget.Button":
+@android:style/
+@android:anim/
+@android:animator/
+@android:array/
+@android:bool/
+@android:color/
+@android:declare-styleable/
+@android:dimen/
+@android:drawable/
+@android:fraction/
+@android:id/
+@android:integer/
+@android:interpolator/
+@android:layout/
+@android:menu/
+@android:mipmap/
+@android:plurals/
+@android:public/
+@android:raw/
+@android:string/
+@android:xml/
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7a.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7a.txt
new file mode 100644 (file)
index 0000000..cf373ad
--- /dev/null
@@ -0,0 +1,2 @@
+Code completion in completion1.xml for android:gravity="l^eft|bottom":
+left
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7b.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion7b.txt
new file mode 100644 (file)
index 0000000..66276d6
--- /dev/null
@@ -0,0 +1,2 @@
+Code completion in completion1.xml for android:gravity="left|b^ottom":
+bottom
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion8.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion8.txt
new file mode 100644 (file)
index 0000000..bee7f93
--- /dev/null
@@ -0,0 +1,2 @@
+Code completion in completion1.xml for layout_width^="fill_parent":
+android:layout_width : Specifies the basic width of the view.  [dimension, enum] 
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion9.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1-expected-completion9.txt
new file mode 100644 (file)
index 0000000..ab6a0d2
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion1.xml for layout_width=^"fill_parent":
+"fill_parent"
+"match_parent"
+"wrap_content"
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion1.xml
new file mode 100644 (file)
index 0000000..d523eeb
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
+<!--  
+  This file deliberately contains errors - it represents partial keyboard
+  typing for interactive code completion
+-->
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@android:dimen/app_icon_size"
+        android:layout_marginLeft="50dp"
+        android:layout_marginBottom="50"
+        android:textColor="#000000"
+        style="@android:style/Widget.Button"
+        android:gravity="left|bottom"
+        android:text="@string/hello"
+        android:hint="hint" />
+    <FrameLayout android:foreground="@android:drawable/btn_default"></FrameLayout> 
+</LinearLayout>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13a.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13a.diff
new file mode 100644 (file)
index 0000000..e19874b
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion2.xml for gravity="left|bottom|^cen selecting fill_vertical:
+<     <TextView android:gravity="left|bottom|cen"></TextView>
+---
+>     <TextView android:gravity="left|bottom|fill_vertical^"></TextView>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13b.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13b.diff
new file mode 100644 (file)
index 0000000..ddea7f1
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion2.xml for gravity="left|bottom|cen^ selecting center_horizontal:
+<     <TextView android:gravity="left|bottom|cen"></TextView>
+---
+>     <TextView android:gravity="left|bottom|center_horizontal^"></TextView>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13c.diff b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-applyCompletion13c.diff
new file mode 100644 (file)
index 0000000..dec1691
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion2.xml for gravity="left|bottom^|cen selecting bottom|fill_horizontal:
+<     <TextView android:gravity="left|bottom|cen"></TextView>
+---
+>     <TextView android:gravity="left|bottom|fill_horizontal^"></TextView>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13a.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13a.txt
new file mode 100644 (file)
index 0000000..323bb78
--- /dev/null
@@ -0,0 +1,13 @@
+Code completion in completion2.xml for gravity="left|bottom|^cen:
+top
+bottom
+left
+right
+center_vertical
+fill_vertical
+center_horizontal
+fill_horizontal
+center
+fill
+clip_vertical
+clip_horizontal
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13b.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13b.txt
new file mode 100644 (file)
index 0000000..8e6d4d8
--- /dev/null
@@ -0,0 +1,4 @@
+Code completion in completion2.xml for gravity="left|bottom|cen^:
+center_vertical
+center_horizontal
+center
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13c.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2-expected-completion13c.txt
new file mode 100644 (file)
index 0000000..3e292ce
--- /dev/null
@@ -0,0 +1,12 @@
+Code completion in completion2.xml for gravity="left|bottom^|cen:
+bottom
+bottom|top
+bottom|right
+bottom|center_vertical
+bottom|fill_vertical
+bottom|center_horizontal
+bottom|fill_horizontal
+bottom|center
+bottom|fill
+bottom|clip_vertical
+bottom|clip_horizontal
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/completion2.xml
new file mode 100644 (file)
index 0000000..0921674
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Test multiple pipes in the flag value -->
+    <TextView android:gravity="left|bottom|cen"></TextView>
+</LinearLayout>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion14.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion14.txt
new file mode 100644 (file)
index 0000000..478e435
--- /dev/null
@@ -0,0 +1,10 @@
+Code completion in manifest.xml for android.permission.ACC^ESS_NETWORK_STATE:
+android.permission.ACCESS_CHECKIN_PROPERTIES
+android.permission.ACCESS_COARSE_LOCATION
+android.permission.ACCESS_FINE_LOCATION
+android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
+android.permission.ACCESS_MOCK_LOCATION
+android.permission.ACCESS_NETWORK_STATE
+android.permission.ACCESS_SURFACE_FLINGER
+android.permission.ACCESS_WIFI_STATE
+android.permission.ACCOUNT_MANAGER
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion15.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion15.txt
new file mode 100644 (file)
index 0000000..c6b3538
--- /dev/null
@@ -0,0 +1,3 @@
+Code completion in manifest.xml for android.intent.category.L^AUNCHER:
+android.intent.category.LAUNCHER
+android.intent.category.LE_DESK_DOCK
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion16.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion16.txt
new file mode 100644 (file)
index 0000000..b69522c
--- /dev/null
@@ -0,0 +1,14 @@
+Code completion in manifest.xml for <^application android:i:
+application  : The "application" tag describes application-level components contained  in the package, as well as general application attributes.
+instrumentation  : Attributes that can be supplied in an AndroidManifest.xml "instrumentation"  tag, a child of the root manifest tag.
+uses-feature  : The "uses-feature" tag specifies a specific feature used by the  application.
+permission-group  : The "permission-group" tag declares a logical grouping of related  permissions.
+supports-screens  : The "supports-screens" specifies the screen dimensions an application  supports.
+protected-broadcast  : Private tag to declare system protected broadcast actions.
+uses-configuration  : The "uses-configuration" tag specifies a specific hardware configuration  value used by the application.
+compatible-screens 
+permission  : The "permission" tag declares a security permission that can be  used to control access from other packages to specific components  or features in your package (or other packages).
+uses-sdk  : The "uses-sdk" tag describes the SDK features that the containing  package must be running on to operate correctly.
+permission-tree  : The "permission-tree" tag declares the base of a tree of permission  values: it declares that this package has ownership of the given  permission name, as well as all names underneath it (separated  by '.').
+uses-permission  : The "uses-permission" tag requests a "permission" that the containing  package must be granted in order for it to operate correctly.
+original-package  : Private tag to declare the original package name that this package  is based on.
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion17.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion17.txt
new file mode 100644 (file)
index 0000000..6d966da
--- /dev/null
@@ -0,0 +1,7 @@
+Code completion in manifest.xml for ^android:versionCode="1":
+package : This attribute gives a unique name for the package, using a Java-style naming convention to avoid name collisions. For example, applications published by Google could have names of the form com.google.app.appname
+android:versionCode : Internal version code.  [integer] 
+android:versionName : The text shown to the user to indicate the version they have.  [string] 
+android:sharedUserId : Specify the name of a user ID that will be shared between multiple  packages.  [string] 
+android:sharedUserLabel : Specify a label for the shared user UID of this package.  [reference] 
+android:installLocation : The default install location defined by an application.  [enum] 
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion18.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest-expected-completion18.txt
new file mode 100644 (file)
index 0000000..6fd1096
--- /dev/null
@@ -0,0 +1,27 @@
+Code completion in manifest.xml for <activity android:^name=".TestActivity":
+android:name : Required name of the class implementing the activity, deriving  from android.app.Activity.  [string] 
+android:theme : The overall theme to use for an activity.  [reference] 
+android:label : A user-legible name for the given item.  [string, reference] 
+android:description : Descriptive text for the associated data.  [reference] 
+android:icon : A Drawable resource providing a graphical representation of its  associated item.  [reference] 
+android:logo : A Drawable resource providing an extended graphical logo for  its associated item.  [reference] 
+android:launchMode : Specify how an activity should be launched.  [enum] 
+android:screenOrientation : Specify the orientation an activity should be run in.  [enum] 
+android:configChanges : Specify one or more configuration changes that the activity will  handle itself.  [flag] 
+android:permission : Specify a permission that a client is required to have in order  to use the associated object.  [string] 
+android:multiprocess : Specify whether a component is allowed to have multiple instances  of itself running in different processes.  [boolean] 
+android:process : Specify a specific process that the associated code is to run  in.  [string] 
+android:taskAffinity : Specify a task name that activities have an "affinity" to.  [string] 
+android:allowTaskReparenting : Specify that an activity can be moved out of a task it is in  to the task it has an affinity for when appropriate.  [boolean] 
+android:finishOnTaskLaunch : Specify whether an activity should be finished when its task  is brought to the foreground by relaunching from the home screen.  [boolean] 
+android:finishOnCloseSystemDialogs : Specify whether an activity should be finished when a "close  system windows" request has been made.  [boolean] 
+android:clearTaskOnLaunch : Specify whether an activity's task should be cleared when it  is re-launched from the home screen.  [boolean] 
+android:noHistory : Specify whether an activity should be kept in its history stack.  [boolean] 
+android:alwaysRetainTaskState : Specify whether an acitivty's task state should always be maintained  by the system, or if it is allowed to reset the task to its initial  state in certain situations.  [boolean] 
+android:stateNotNeeded : Indicates that an Activity does not need to have its freeze state  (as returned by onSaveInstanceState retained in order to be restarted.  [boolean] 
+android:excludeFromRecents : Indicates that an Activity should be excluded from the list of  recently launched activities.  [boolean] 
+android:enabled : Specify whether the activity is enabled or not (that is, can  be instantiated by the system).  [boolean] 
+android:exported : Flag indicating whether the given application component is available  to other applications.  [boolean] 
+android:windowSoftInputMode : Specify the default soft-input mode for the main window of this  activity.  [flag] 
+android:immersive : Flag declaring this activity to be 'immersive'; immersive activities  should not be interrupted with other activities or notifications.  [boolean] 
+android:hardwareAccelerated : <p>Flag indicating whether the application's rendering should  be hardware accelerated if possible.  [boolean] 
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/manifest.xml
new file mode 100644 (file)
index 0000000..2c0024f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="foo.bar"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <uses-sdk android:minSdkVersion="11" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:name=".TestActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
index 98e0a8f..772f82a 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout android:id="@+id/RelativeLayout1" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
     <Button android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:text="FirstButton" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
-    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button2" android:layout_below="@+id/button1" android:layout_marginTop="2dip" android:text="SecondButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2"></Button>
+    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button2" android:layout_below="@+id/button1" android:layout_marginTop="2dp" android:text="SecondButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2"></Button>
     <Button android:layout_toRightOf="@+id/button2" android:layout_alignBaseline="@+id/button2" android:layout_alignTop="@+id/button2" android:text="ThirdButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button3"></Button>
     <CheckBox android:layout_toRightOf="@+id/button3" android:layout_alignBaseline="@+id/button2" android:layout_below="@+id/button1" android:id="@+id/checkBox1" android:text="CheckBox" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
     <Button android:layout_alignParentLeft="true" android:layout_below="@+id/checkBox1" android:layout_height="wrap_content" android:text="FourthButton" android:id="@+id/button4" android:layout_width="match_parent"></Button>
index 737e72d..f47e9be 100644 (file)
@@ -10,7 +10,7 @@
         android:id="@+id/button1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"></Button>
-    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button2" android:layout_below="@+id/button1" android:layout_marginTop="2dip"
+    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button2" android:layout_below="@+id/button1" android:layout_marginTop="2dp"
     android:text="SecondButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
index fba3049..225476c 100644 (file)
@@ -3,7 +3,7 @@
     <Button android:layout_centerHorizontal="true" android:layout_alignParentTop="true" android:text="Button" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"></Button>
     <Button android:layout_centerHorizontal="true" android:layout_below="@+id/button1" android:text="Button" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"></Button>
     <Button android:layout_alignParentRight="true" android:layout_below="@+id/button2" android:text="Button" android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right"></Button>
-    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button4" android:layout_below="@+id/button3" android:layout_marginTop="70dip" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Button" android:id="@+id/button4" android:layout_width="wrap_content"></Button>
+    <Button android:layout_alignParentLeft="true" android:layout_alignBaseline="@+id/button4" android:layout_below="@+id/button3" android:layout_marginTop="70dp" android:layout_height="wrap_content" android:layout_gravity="center" android:text="Button" android:id="@+id/button4" android:layout_width="wrap_content"></Button>
     <Button android:layout_toRightOf="@+id/button4" android:layout_alignBaseline="@+id/button4" android:layout_alignTop="@+id/button4" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:text="Button" android:id="@+id/button5" android:layout_width="wrap_content"></Button>
     <Button android:layout_toRightOf="@+id/button5" android:layout_alignParentBottom="true" android:layout_height="wrap_content" android:text="Button" android:id="@+id/button6" android:layout_width="wrap_content" android:layout_gravity="bottom"></Button>
 </RelativeLayout>
index f4092eb..62725b8 100644 (file)
@@ -60,8 +60,8 @@ public class AbsoluteLayoutRuleTest extends LayoutTestBase {
                 // Drop preview
                 "useStyle(DROP_PREVIEW), drawRect(Rect[30,-10,105,80])");
 
-        assertEquals("30dip", inserted.getStringAttr(ANDROID_URI, "layout_x"));
-        assertEquals("-10dip", inserted.getStringAttr(ANDROID_URI, "layout_y"));
+        assertEquals("30dp", inserted.getStringAttr(ANDROID_URI, "layout_x"));
+        assertEquals("-10dp", inserted.getStringAttr(ANDROID_URI, "layout_y"));
 
         // Without drag bounds we should just draw guide lines instead
         inserted = dragInto(new Rect(0, 0, 0, 0), new Point(30, -10), 4, -1,
@@ -70,8 +70,8 @@ public class AbsoluteLayoutRuleTest extends LayoutTestBase {
                 "useStyle(GUIDELINE), drawLine(30,0,30,480), drawLine(0,-10,240,-10)",
                 // Drop preview
                 "useStyle(DROP_PREVIEW), drawLine(30,-10,240,-10), drawLine(30,-10,30,480)");
-        assertEquals("30dip", inserted.getStringAttr(ANDROID_URI, "layout_x"));
-        assertEquals("-10dip", inserted.getStringAttr(ANDROID_URI, "layout_y"));
+        assertEquals("30dp", inserted.getStringAttr(ANDROID_URI, "layout_x"));
+        assertEquals("-10dp", inserted.getStringAttr(ANDROID_URI, "layout_y"));
     }
 
 }
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssistTest.java
deleted file mode 100644 (file)
index 8151f3a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 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.adt.internal.editors;
-
-import junit.framework.TestCase;
-
-public class AndroidContentAssistTest extends TestCase {
-    public void testStartsWith() {
-        assertTrue(AndroidContentAssist.startsWith("", ""));
-        assertTrue(AndroidContentAssist.startsWith("a", ""));
-        assertTrue(AndroidContentAssist.startsWith("A", ""));
-        assertTrue(AndroidContentAssist.startsWith("A", "a"));
-        assertTrue(AndroidContentAssist.startsWith("A", "A"));
-        assertTrue(AndroidContentAssist.startsWith("Ab", "a"));
-        assertTrue(AndroidContentAssist.startsWith("ab", "A"));
-        assertTrue(AndroidContentAssist.startsWith("ab", "AB"));
-        assertFalse(AndroidContentAssist.startsWith("ab", "ABc"));
-        assertFalse(AndroidContentAssist.startsWith("", "ABc"));
-    }
-}