OSDN Git Service

Misc New Project Wizard fixes
authorTor Norbye <tnorbye@google.com>
Fri, 2 Sep 2011 23:57:35 +0000 (16:57 -0700)
committerTor Norbye <tnorbye@google.com>
Wed, 7 Sep 2011 00:55:49 +0000 (17:55 -0700)
This changeset fixes a couple of bugs in the New Project wizard:

(1) It escapes strings, such as the application name, in the
    strings.xml file.
    http://code.google.com/p/android/issues/detail?id=6725

(2) It fixes package name validation in the activity name
    http://code.google.com/p/android/issues/detail?id=14811

(3) It selects an SDK target by default
    http://code.google.com/p/android/issues/detail?id=17505

Finally it also ensures that the suggested activity name is a valid
Java class name even where the application name is not.

Change-Id: Iba9843dbb2fbb09324122d285e51ad937f6fddfd

eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/refactorings/extractstring/ExtractStringRefactoring.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java
eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/AdtUtilsTest.java

index 38ecbe0..f2ed49a 100644 (file)
@@ -60,6 +60,42 @@ public class AdtUtils {
     }
 
     /**
+     * Creates a Java class name out of the given string, if possible. For
+     * example, "My Project" becomes "MyProject", "hello" becomes "Hello",
+     * "Java's" becomes "Java", and so on.
+     *
+     * @param string the string to be massaged into a Java class
+     * @return the string as a Java class, or null if a class name could not be
+     *         extracted
+     */
+    public static String extractClassName(String string) {
+        StringBuilder sb = new StringBuilder(string.length());
+        int n = string.length();
+
+        int i = 0;
+        for (; i < n; i++) {
+            char c = Character.toUpperCase(string.charAt(i));
+            if (Character.isJavaIdentifierStart(c)) {
+                sb.append(c);
+                i++;
+                break;
+            }
+        }
+        if (sb.length() > 0) {
+            for (; i < n; i++) {
+                char c = string.charAt(i);
+                if (Character.isJavaIdentifierPart(c)) {
+                    sb.append(c);
+                }
+            }
+
+            return sb.toString();
+        }
+
+        return null;
+    }
+
+    /**
      * Strips off the last file extension from the given filename, e.g.
      * "foo.backup.diff" will be turned into "foo.backup".
      * <p>
index a1a490f..d3cb469 100644 (file)
@@ -1459,8 +1459,10 @@ public class ExtractStringRefactoring extends Refactoring {
      * <li>{@code <, >, &} have to be replaced by their predefined xml entity.
      * <li>{@code \n, \t} have to be replaced by a backslash and the appropriate character.
      * </ul>
+     * @param s the string to be escaped
+     * @return the escaped string as it would appear in the XML text in a values file
      */
-    static String escapeString(String s) {
+    public static String escapeString(String s) {
         int n = s.length();
         if (n == 0) {
             return "";
index 182c7b1..df72af6 100644 (file)
@@ -23,6 +23,7 @@
 package com.android.ide.eclipse.adt.internal.wizards.newproject;
 
 import static com.android.ide.eclipse.adt.AdtUtils.capitalize;
+import static com.android.ide.eclipse.adt.AdtUtils.extractClassName;
 import static com.android.ide.eclipse.adt.AdtUtils.stripWhitespace;
 
 import com.android.ide.eclipse.adt.AdtConstants;
@@ -237,7 +238,6 @@ public class NewProjectCreationPage extends WizardPage {
 
     }
 
-
     /**
      * Structure that collects all externally visible information from this page.
      * This is used by the calling wizard to actually do the work or by other pages.
@@ -597,6 +597,22 @@ public class NewProjectCreationPage extends WizardPage {
                 // This will invoke the selection listener on the selector defined above.
                 if (targets != null && targets.length == 1) {
                     mSdkTargetSelector.setSelection(targets[0]);
+                } else if (targets != null) {
+                    // Pick the highest available platform by default (see issue #17505
+                    // for related discussion.)
+                    IAndroidTarget initialTarget = null;
+                    for (IAndroidTarget target : targets) {
+                        if (target.isPlatform()
+                                && !target.getVersion().isPreview()
+                                && (initialTarget == null ||
+                                        target.getVersion().getApiLevel() >
+                                            initialTarget.getVersion().getApiLevel())) {
+                            initialTarget = target;
+                        }
+                    }
+                    if (initialTarget != null) {
+                        mSdkTargetSelector.setSelection(initialTarget);
+                    }
                 }
             }
 
@@ -940,12 +956,14 @@ public class NewProjectCreationPage extends WizardPage {
         if (!mInternalApplicationNameUpdate) {
                mApplicationNameModifiedByUser = true;
                if (!mActivityNameModifiedByUser) {
-                   String name = capitalize(mApplicationNameField.getText());
-                   try {
-                       mInternalActivityNameUpdate = true;
-                       mActivityNameField.setText(stripWhitespace(name) + ACTIVITY_NAME_SUFFIX);
-                   } finally {
-                       mInternalActivityNameUpdate = false;
+                   String name = extractClassName(mApplicationNameField.getText());
+                   if (name != null) {
+                       try {
+                           mInternalActivityNameUpdate = true;
+                           mActivityNameField.setText(stripWhitespace(name) + ACTIVITY_NAME_SUFFIX);
+                       } finally {
+                           mInternalActivityNameUpdate = false;
+                       }
                    }
                }
            }
@@ -1618,6 +1636,10 @@ public class NewProjectCreationPage extends WizardPage {
             return setStatus("Enter a valid activity name", MSG_ERROR);
         }
 
+        if (activityFieldContents.contains("..")) { //$NON-NLS-1$
+            return setStatus("Package segments in activity name cannot be empty (..)", MSG_ERROR);
+        }
+
         // The activity field can actually contain part of a sub-package name
         // or it can start with a dot "." to indicates it comes from the parent package name.
         String packageName = "";  //$NON-NLS-1$
@@ -1634,7 +1656,7 @@ public class NewProjectCreationPage extends WizardPage {
         // the activity field can contain a simple java identifier, or a
         // package name or one that starts with a dot. So if it starts with a dot,
         // ignore this dot -- the rest must look like a package name.
-        if (activityFieldContents.charAt(0) == '.') {
+        if (activityFieldContents.length() > 0 && activityFieldContents.charAt(0) == '.') {
             activityFieldContents = activityFieldContents.substring(1);
         }
 
index 082ab2c..ed5db11 100644 (file)
@@ -26,6 +26,7 @@ import com.android.ide.eclipse.adt.internal.editors.formatting.XmlPrettyPrinter;
 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
 import com.android.ide.eclipse.adt.internal.project.AndroidNature;
 import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
+import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring;
 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreationPage.IMainInfo;
 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewTestProjectCreationPage.TestInfo;
@@ -79,8 +80,8 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 
 /**
  * A "New Android Project" Wizard.
@@ -923,6 +924,9 @@ public class NewProjectWizard extends Wizard implements INewWizard {
                 // get the value from the key
                 String value = strings.get(key);
 
+                // Escape values if necessary
+                value = ExtractStringRefactoring.escapeString(value);
+
                 // place them in the template
                 String stringDef = stringTemplate.replace(PARAM_STRING_NAME, key);
                 stringDef = stringDef.replace(PARAM_STRING_CONTENT, value);
index f4daf59..1d203b0 100644 (file)
@@ -37,6 +37,13 @@ public class AdtUtilsTest extends TestCase {
         assertEquals("foobar", AdtUtils.stripWhitespace("  foo bar  \n\t"));
     }
 
+    public void testExtractClassName() {
+        assertEquals("Foo", AdtUtils.extractClassName("foo"));
+        assertEquals("Foobar", AdtUtils.extractClassName("foo bar"));
+        assertEquals("JavasTypeSystem", AdtUtils.extractClassName("Java's Type System"));
+        assertEquals("Foo", AdtUtils.extractClassName("1foo "));
+    }
+
     public void testStripAllExtensions() {
         assertEquals("", AdtUtils.stripAllExtensions(""));
         assertEquals("foobar", AdtUtils.stripAllExtensions("foobar"));