Home | History | Annotate | Download | only in newproject
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.ide.eclipse.adt.internal.wizards.newproject;
     17 
     18 import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE;
     19 import static com.android.SdkConstants.OS_SDK_TOOLS_LIB_FOLDER;
     20 import static com.android.ide.eclipse.adt.AdtUtils.capitalize;
     21 import static com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage.ACTIVITY_NAME_SUFFIX;
     22 import static com.android.utils.SdkUtils.stripWhitespace;
     23 
     24 import com.android.SdkConstants;
     25 import com.android.ide.common.xml.ManifestData;
     26 import com.android.ide.common.xml.ManifestData.Activity;
     27 import com.android.ide.eclipse.adt.AdtPlugin;
     28 import com.android.ide.eclipse.adt.internal.VersionCheck;
     29 import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
     30 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode;
     31 
     32 import org.eclipse.core.filesystem.URIUtil;
     33 import org.eclipse.core.resources.IProject;
     34 import org.eclipse.core.resources.IResource;
     35 import org.eclipse.core.resources.IWorkspace;
     36 import org.eclipse.core.resources.ResourcesPlugin;
     37 import org.eclipse.core.runtime.IStatus;
     38 import org.eclipse.core.runtime.Path;
     39 import org.eclipse.core.runtime.Platform;
     40 import org.eclipse.core.runtime.Status;
     41 import org.eclipse.jface.dialogs.IMessageProvider;
     42 import org.eclipse.jface.viewers.IStructuredSelection;
     43 import org.eclipse.jface.wizard.IWizardPage;
     44 import org.eclipse.jface.wizard.WizardPage;
     45 import org.eclipse.osgi.util.TextProcessor;
     46 import org.eclipse.swt.SWT;
     47 import org.eclipse.swt.events.ModifyEvent;
     48 import org.eclipse.swt.events.ModifyListener;
     49 import org.eclipse.swt.events.SelectionEvent;
     50 import org.eclipse.swt.events.SelectionListener;
     51 import org.eclipse.swt.layout.GridData;
     52 import org.eclipse.swt.layout.GridLayout;
     53 import org.eclipse.swt.widgets.Button;
     54 import org.eclipse.swt.widgets.Composite;
     55 import org.eclipse.swt.widgets.DirectoryDialog;
     56 import org.eclipse.swt.widgets.Label;
     57 import org.eclipse.swt.widgets.Text;
     58 import org.eclipse.ui.IWorkbenchPart;
     59 import org.eclipse.ui.IWorkingSet;
     60 
     61 import java.io.File;
     62 import java.net.URI;
     63 import java.util.Locale;
     64 
     65 /**
     66  * Initial page shown when creating projects which asks for the project name,
     67  * the the location of the project, working sets, etc.
     68  */
     69 public class ProjectNamePage extends WizardPage implements SelectionListener, ModifyListener {
     70     private final NewProjectWizardState mValues;
     71     /** Flag used when setting button/text state manually to ignore listener updates */
     72     private boolean mIgnore;
     73     /** Last user-browsed location, static so that it be remembered for the whole session */
     74     private static String sCustomLocationOsPath = "";  //$NON-NLS-1$
     75     private static boolean sAutoComputeCustomLocation = true;
     76 
     77     private Text mProjectNameText;
     78     private Text mLocationText;
     79     private Button mCreateSampleRadioButton;
     80     private Button mCreateNewButton;
     81     private Button mUseDefaultCheckBox;
     82     private Button mBrowseButton;
     83     private Label mLocationLabel;
     84     private WorkingSetGroup mWorkingSetGroup;
     85     /**
     86      * Whether we've made sure the Tools are up to date (enough that all the
     87      * resources required by the New Project wizard are present -- we don't
     88      * necessarily check for newer versions than that here; that's done by
     89      * {@link VersionCheck}, though that check doesn't <b>enforce</b> an update
     90      * since it needs to allow the user to proceed to access the SDK manager
     91      * etc.)
     92      */
     93     private boolean mCheckedSdkUptodate;
     94 
     95     /**
     96      * Create the wizard.
     97      * @param values current wizard state
     98      */
     99     ProjectNamePage(NewProjectWizardState values) {
    100         super("projectNamePage"); //$NON-NLS-1$
    101         mValues = values;
    102 
    103         setTitle("Create Android Project");
    104         setDescription("Select project name and type of project");
    105         mWorkingSetGroup = new WorkingSetGroup();
    106         setWorkingSets(new IWorkingSet[0]);
    107     }
    108 
    109     void init(IStructuredSelection selection, IWorkbenchPart activePart) {
    110         setWorkingSets(WorkingSetHelper.getSelectedWorkingSet(selection, activePart));
    111     }
    112 
    113     /**
    114      * Create contents of the wizard.
    115      * @param parent the parent to add the page to
    116      */
    117     @Override
    118     public void createControl(Composite parent) {
    119         Composite container = new Composite(parent, SWT.NULL);
    120         container.setLayout(new GridLayout(3, false));
    121 
    122         Label nameLabel = new Label(container, SWT.NONE);
    123         nameLabel.setText("Project Name:");
    124 
    125         mProjectNameText = new Text(container, SWT.BORDER);
    126         mProjectNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
    127         mProjectNameText.addModifyListener(this);
    128 
    129         if (mValues.mode != Mode.TEST) {
    130             mCreateNewButton = new Button(container, SWT.RADIO);
    131             mCreateNewButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
    132             mCreateNewButton.setText("Create new project in workspace");
    133             mCreateNewButton.addSelectionListener(this);
    134 
    135             // TBD: Should we hide this completely, and make samples something you only invoke
    136             // from the "New Sample Project" wizard?
    137             mCreateSampleRadioButton = new Button(container, SWT.RADIO);
    138             mCreateSampleRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
    139                     3, 1));
    140             mCreateSampleRadioButton.setText("Create project from existing sample");
    141             mCreateSampleRadioButton.addSelectionListener(this);
    142         }
    143 
    144         Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
    145         separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
    146 
    147         mUseDefaultCheckBox = new Button(container, SWT.CHECK);
    148         mUseDefaultCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
    149         mUseDefaultCheckBox.setText("Use default location");
    150         mUseDefaultCheckBox.addSelectionListener(this);
    151 
    152         mLocationLabel = new Label(container, SWT.NONE);
    153         mLocationLabel.setText("Location:");
    154 
    155         mLocationText = new Text(container, SWT.BORDER);
    156         mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
    157         mLocationText.addModifyListener(this);
    158 
    159         mBrowseButton = new Button(container, SWT.NONE);
    160         mBrowseButton.setText("Browse...");
    161         mBrowseButton.addSelectionListener(this);
    162 
    163         Composite group = mWorkingSetGroup.createControl(container);
    164         group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1));
    165 
    166         setControl(container);
    167     }
    168 
    169     @Override
    170     public void setVisible(boolean visible) {
    171         super.setVisible(visible);
    172 
    173         if (visible) {
    174             try {
    175                 mIgnore = true;
    176                 if (mValues.projectName != null) {
    177                         mProjectNameText.setText(mValues.projectName);
    178                     mProjectNameText.setFocus();
    179                 }
    180                 if (mValues.mode == Mode.ANY || mValues.mode == Mode.TEST) {
    181                     if (mValues.useExisting) {
    182                         assert false; // This is now handled by the separate import wizard
    183                     } else if (mCreateNewButton != null) {
    184                         mCreateNewButton.setSelection(true);
    185                     }
    186                 } else if (mValues.mode == Mode.SAMPLE) {
    187                     mCreateSampleRadioButton.setSelection(true);
    188                 }
    189                 if (mValues.projectLocation != null) {
    190                     mLocationText.setText(mValues.projectLocation.getPath());
    191                 }
    192                 mUseDefaultCheckBox.setSelection(mValues.useDefaultLocation);
    193                 updateLocationState();
    194             } finally {
    195                 mIgnore = false;
    196             }
    197         }
    198 
    199         validatePage();
    200     }
    201 
    202     @Override
    203     public void modifyText(ModifyEvent e) {
    204         if (mIgnore) {
    205             return;
    206         }
    207 
    208         Object source = e.getSource();
    209 
    210         if (source == mProjectNameText) {
    211             onProjectFieldModified();
    212             if (!mValues.useDefaultLocation && !mValues.projectLocationModifiedByUser) {
    213                 updateLocationPathField(null);
    214             }
    215         } else if (source == mLocationText) {
    216             mValues.projectLocationModifiedByUser = true;
    217             if (!mValues.useDefaultLocation) {
    218                 File f = new File(mLocationText.getText().trim());
    219                 mValues.projectLocation = f;
    220                 if (f.exists() && f.isDirectory() && !f.equals(mValues.projectLocation)) {
    221                     updateLocationPathField(mValues.projectLocation.getPath());
    222                 }
    223             }
    224         }
    225 
    226         validatePage();
    227     }
    228 
    229     private void onProjectFieldModified() {
    230         mValues.projectName = mProjectNameText.getText().trim();
    231         mValues.projectNameModifiedByUser = true;
    232 
    233         if (!mValues.applicationNameModifiedByUser) {
    234             mValues.applicationName = capitalize(mValues.projectName);
    235             if (!mValues.testApplicationNameModified) {
    236                 mValues.testApplicationName =
    237                         ApplicationInfoPage.suggestTestApplicationName(mValues.applicationName);
    238             }
    239         }
    240         if (!mValues.activityNameModifiedByUser) {
    241             String name = capitalize(mValues.projectName);
    242             mValues.activityName = stripWhitespace(name) + ACTIVITY_NAME_SUFFIX;
    243         }
    244         if (!mValues.testProjectModified) {
    245             mValues.testProjectName =
    246                     ApplicationInfoPage.suggestTestProjectName(mValues.projectName);
    247         }
    248         if (!mValues.projectLocationModifiedByUser) {
    249             updateLocationPathField(null);
    250         }
    251     }
    252 
    253     @Override
    254     public void widgetSelected(SelectionEvent e) {
    255         if (mIgnore) {
    256             return;
    257         }
    258 
    259         Object source = e.getSource();
    260 
    261         if (source == mCreateNewButton && mCreateNewButton != null
    262                 && mCreateNewButton.getSelection()) {
    263             mValues.useExisting = false;
    264             if (mValues.mode == Mode.SAMPLE) {
    265                 // Only reset the mode if we're toggling from sample back to create new
    266                 // or create existing. We can only come to the sample state when we're in
    267                 // ANY mode. (In particular, we don't want to switch to ANY if you're
    268                 // in test mode.
    269                 mValues.mode = Mode.ANY;
    270             }
    271             updateLocationState();
    272         } else if (source == mCreateSampleRadioButton && mCreateSampleRadioButton.getSelection()) {
    273             mValues.useExisting = true;
    274             mValues.useDefaultLocation = true;
    275             if (!mUseDefaultCheckBox.getSelection()) {
    276                 try {
    277                     mIgnore = true;
    278                     mUseDefaultCheckBox.setSelection(true);
    279                 } finally {
    280                     mIgnore = false;
    281                 }
    282             }
    283             mValues.mode = Mode.SAMPLE;
    284             updateLocationState();
    285         } else if (source == mUseDefaultCheckBox) {
    286             mValues.useDefaultLocation = mUseDefaultCheckBox.getSelection();
    287             updateLocationState();
    288         } else if (source == mBrowseButton) {
    289             onOpenDirectoryBrowser();
    290         }
    291 
    292         validatePage();
    293     }
    294 
    295    /**
    296     * Enables or disable the location widgets depending on the user selection:
    297     * the location path is enabled when using the "existing source" mode (i.e. not new project)
    298     * or in new project mode with the "use default location" turned off.
    299     */
    300    private void updateLocationState() {
    301        boolean isNewProject = !mValues.useExisting;
    302        boolean isCreateFromSample = mValues.mode == Mode.SAMPLE;
    303        boolean useDefault = mValues.useDefaultLocation && !isCreateFromSample;
    304        boolean locationEnabled = (!isNewProject || !useDefault) && !isCreateFromSample;
    305 
    306        mUseDefaultCheckBox.setEnabled(isNewProject);
    307        mLocationLabel.setEnabled(locationEnabled);
    308        mLocationText.setEnabled(locationEnabled);
    309        mBrowseButton.setEnabled(locationEnabled);
    310 
    311        updateLocationPathField(null);
    312    }
    313 
    314     /**
    315      * Display a directory browser and update the location path field with the selected path
    316      */
    317     private void onOpenDirectoryBrowser() {
    318 
    319         String existingDir = mLocationText.getText().trim();
    320 
    321         // Disable the path if it doesn't exist
    322         if (existingDir.length() == 0) {
    323             existingDir = null;
    324         } else {
    325             File f = new File(existingDir);
    326             if (!f.exists()) {
    327                 existingDir = null;
    328             }
    329         }
    330 
    331         DirectoryDialog directoryDialog = new DirectoryDialog(mLocationText.getShell());
    332         directoryDialog.setMessage("Browse for folder");
    333         directoryDialog.setFilterPath(existingDir);
    334         String dir = directoryDialog.open();
    335 
    336         if (dir != null) {
    337             updateLocationPathField(dir);
    338             validatePage();
    339         }
    340     }
    341 
    342     @Override
    343     public void widgetDefaultSelected(SelectionEvent e) {
    344     }
    345 
    346     /**
    347      * Returns the working sets to which the new project should be added.
    348      *
    349      * @return the selected working sets to which the new project should be added
    350      */
    351     private IWorkingSet[] getWorkingSets() {
    352         return mWorkingSetGroup.getSelectedWorkingSets();
    353     }
    354 
    355     /**
    356      * Sets the working sets to which the new project should be added.
    357      *
    358      * @param workingSets the initial selected working sets
    359      */
    360     private void setWorkingSets(IWorkingSet[] workingSets) {
    361         assert workingSets != null;
    362         mWorkingSetGroup.setWorkingSets(workingSets);
    363     }
    364 
    365     /**
    366      * Updates the location directory path field.
    367      * <br/>
    368      * When custom user selection is enabled, use the absDir argument if not null and also
    369      * save it internally. If absDir is null, restore the last saved absDir. This allows the
    370      * user selection to be remembered when the user switches from default to custom.
    371      * <br/>
    372      * When custom user selection is disabled, use the workspace default location with the
    373      * current project name. This does not change the internally cached absDir.
    374      *
    375      * @param absDir A new absolute directory path or null to use the default.
    376      */
    377     private void updateLocationPathField(String absDir) {
    378         boolean isNewProject = !mValues.useExisting || mValues.mode == Mode.SAMPLE;
    379         boolean useDefault = mValues.useDefaultLocation;
    380         boolean customLocation = !isNewProject || !useDefault;
    381 
    382         if (!mIgnore) {
    383             try {
    384                 mIgnore = true;
    385                 if (customLocation) {
    386                     if (absDir != null) {
    387                         // We get here if the user selected a directory with the "Browse" button.
    388                         // Disable auto-compute of the custom location unless the user selected
    389                         // the exact same path.
    390                         sAutoComputeCustomLocation = sAutoComputeCustomLocation &&
    391                                                      absDir.equals(sCustomLocationOsPath);
    392                         sCustomLocationOsPath = TextProcessor.process(absDir);
    393                     } else  if (sAutoComputeCustomLocation ||
    394                                 (!isNewProject && !new File(sCustomLocationOsPath).isDirectory())) {
    395                         // As a default import location, just suggest the home directory; the user
    396                         // needs to point to a project to import.
    397                         // TODO: Open file chooser automatically?
    398                         sCustomLocationOsPath = System.getProperty("user.home"); //$NON-NLS-1$
    399                     }
    400                     if (!mLocationText.getText().equals(sCustomLocationOsPath)) {
    401                         mLocationText.setText(sCustomLocationOsPath);
    402                         mValues.projectLocation = new File(sCustomLocationOsPath);
    403                     }
    404                 } else {
    405                     String value = Platform.getLocation().append(mValues.projectName).toString();
    406                     value = TextProcessor.process(value);
    407                     if (!mLocationText.getText().equals(value)) {
    408                         mLocationText.setText(value);
    409                         mValues.projectLocation = new File(value);
    410                     }
    411                 }
    412             } finally {
    413                 mIgnore = false;
    414             }
    415         }
    416 
    417         if (mValues.useExisting && mValues.projectLocation != null
    418                 && mValues.projectLocation.exists() && mValues.mode != Mode.SAMPLE) {
    419             mValues.extractFromAndroidManifest(new Path(mValues.projectLocation.getPath()));
    420             if (!mValues.projectNameModifiedByUser && mValues.projectName != null) {
    421                 try {
    422                     mIgnore = true;
    423                     mProjectNameText.setText(mValues.projectName);
    424                 } finally {
    425                     mIgnore = false;
    426                 }
    427             }
    428         }
    429     }
    430 
    431     private void validatePage() {
    432         IStatus status = null;
    433 
    434         // Validate project name -- unless we're creating a sample, in which case
    435         // the user will get a chance to pick the name on the Sample page
    436         if (mValues.mode != Mode.SAMPLE) {
    437             status = validateProjectName(mValues.projectName);
    438         }
    439 
    440         if (status == null || status.getSeverity() != IStatus.ERROR) {
    441             IStatus validLocation = validateLocation();
    442             if (validLocation != null) {
    443                 status = validLocation;
    444             }
    445         }
    446 
    447         if (!mCheckedSdkUptodate) {
    448             // Ensure that we have a recent enough version of the Tools that the right templates
    449             // are available
    450             File file = new File(AdtPlugin.getOsSdkFolder(), OS_SDK_TOOLS_LIB_FOLDER
    451                     + File.separator + FN_PROJECT_PROGUARD_FILE);
    452             if (!file.exists()) {
    453                 status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    454                         String.format("You do not have the latest version of the "
    455                         + "SDK Tools installed: Please update. (Missing %1$s)", file.getPath()));
    456             } else {
    457                 mCheckedSdkUptodate = true;
    458             }
    459         }
    460 
    461         // -- update UI & enable finish if there's no error
    462         setPageComplete(status == null || status.getSeverity() != IStatus.ERROR);
    463         if (status != null) {
    464             setMessage(status.getMessage(),
    465                     status.getSeverity() == IStatus.ERROR
    466                         ? IMessageProvider.ERROR : IMessageProvider.WARNING);
    467         } else {
    468             setErrorMessage(null);
    469             setMessage(null);
    470         }
    471     }
    472 
    473     private IStatus validateLocation() {
    474         if (mValues.mode == Mode.SAMPLE) {
    475             // Samples are always created in the default directory
    476             return null;
    477         }
    478 
    479         // Validate location
    480         Path path = new Path(mValues.projectLocation.getPath());
    481         if (!mValues.useExisting) {
    482             if (!mValues.useDefaultLocation) {
    483                 // If not using the default value validate the location.
    484                 URI uri = URIUtil.toURI(path.toOSString());
    485                 IWorkspace workspace = ResourcesPlugin.getWorkspace();
    486                 IProject handle = workspace.getRoot().getProject(mValues.projectName);
    487                 IStatus locationStatus = workspace.validateProjectLocationURI(handle, uri);
    488                 if (!locationStatus.isOK()) {
    489                     return locationStatus;
    490                 }
    491                 // The location is valid as far as Eclipse is concerned (i.e. mostly not
    492                 // an existing workspace project.) Check it either doesn't exist or is
    493                 // a directory that is empty.
    494                 File f = path.toFile();
    495                 if (f.exists() && !f.isDirectory()) {
    496                     return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    497                             "A directory name must be specified.");
    498                 } else if (f.isDirectory()) {
    499                     // However if the directory exists, we should put a
    500                     // warning if it is not empty. We don't put an error
    501                     // (we'll ask the user again for confirmation before
    502                     // using the directory.)
    503                     String[] l = f.list();
    504                     if (l != null && l.length != 0) {
    505                         return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID,
    506                                 "The selected output directory is not empty.");
    507                     }
    508                 }
    509             } else {
    510                 // Otherwise validate the path string is not empty
    511                 if (mValues.projectLocation.getPath().length() == 0) {
    512                     return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    513                             "A directory name must be specified.");
    514                 }
    515                 File dest = path.toFile();
    516                 if (dest.exists()) {
    517                     return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    518                             String.format(
    519                                     "There is already a file or directory named \"%1$s\" in the selected location.",
    520                             mValues.projectName));
    521                 }
    522             }
    523         } else {
    524             // Must be an existing directory
    525             File f = path.toFile();
    526             if (!f.isDirectory()) {
    527                 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    528                         "An existing directory name must be specified.");
    529             }
    530 
    531             // Check there's an android manifest in the directory
    532             String osPath = path.append(SdkConstants.FN_ANDROID_MANIFEST_XML).toOSString();
    533             File manifestFile = new File(osPath);
    534             if (!manifestFile.isFile()) {
    535                 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    536                         String.format(
    537                                 "Choose a valid Android code directory\n" +
    538                                 "(%1$s not found in %2$s.)",
    539                                 SdkConstants.FN_ANDROID_MANIFEST_XML, f.getName()));
    540             }
    541 
    542             // Parse it and check the important fields.
    543             ManifestData manifestData = AndroidManifestHelper.parseForData(osPath);
    544             if (manifestData == null) {
    545                 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    546                         String.format("File %1$s could not be parsed.", osPath));
    547             }
    548             String packageName = manifestData.getPackage();
    549             if (packageName == null || packageName.length() == 0) {
    550                 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    551                         String.format("No package name defined in %1$s.", osPath));
    552             }
    553             Activity[] activities = manifestData.getActivities();
    554             if (activities == null || activities.length == 0) {
    555                 // This is acceptable now as long as no activity needs to be
    556                 // created
    557                 if (mValues.createActivity) {
    558                     return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    559                             String.format("No activity name defined in %1$s.", osPath));
    560                 }
    561             }
    562 
    563             // If there's already a .project, tell the user to use import instead.
    564             if (path.append(".project").toFile().exists()) {  //$NON-NLS-1$
    565                 return new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID,
    566                         "An Eclipse project already exists in this directory.\n" +
    567                         "Consider using File > Import > Existing Project instead.");
    568             }
    569         }
    570 
    571         return null;
    572     }
    573 
    574     public static IStatus validateProjectName(String projectName) {
    575         if (projectName == null || projectName.length() == 0) {
    576             return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    577                     "Project name must be specified");
    578         } else {
    579             IWorkspace workspace = ResourcesPlugin.getWorkspace();
    580             IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT);
    581             if (!nameStatus.isOK()) {
    582                 return nameStatus;
    583             } else {
    584                 // Note: the case-sensitiveness of the project name matters and can cause a
    585                 // conflict *later* when creating the project resource, so let's check it now.
    586                 for (IProject existingProj : workspace.getRoot().getProjects()) {
    587                     if (projectName.equalsIgnoreCase(existingProj.getName())) {
    588                         return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
    589                                 "A project with that name already exists in the workspace");
    590                     }
    591                 }
    592             }
    593         }
    594 
    595         return null;
    596     }
    597 
    598     @Override
    599     public IWizardPage getNextPage() {
    600         // Sync working set data to the value object, since the WorkingSetGroup
    601         // doesn't let us add listeners to do this lazily
    602         mValues.workingSets = getWorkingSets();
    603 
    604         return super.getNextPage();
    605     }
    606 }
    607