ADT #1715616: "New Android Test Project" wizard.

Also updates eclipse/changes.txt
This commit is contained in:
Raphael
2009-05-07 19:27:46 -07:00
parent 1f012b193f
commit 0b62151cda
21 changed files with 2282 additions and 451 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
*~ *~
*.pyc *.pyc
Thumbs.db

View File

@@ -1,3 +1,7 @@
0.9.2:
- New wizard to create Android JUnit Test Projects.
0.9.1: 0.9.1:
- Added an AVD creation wizard to ADT. It is automatically displayed during a launch if no compatible AVDs are found. - Added an AVD creation wizard to ADT. It is automatically displayed during a launch if no compatible AVDs are found.
- Fixed issue with libs/ folder where files with no extension would prevent the build from finishing. - Fixed issue with libs/ folder where files with no extension would prevent the build from finishing.

View File

@@ -90,7 +90,7 @@
class="com.android.ide.eclipse.adt.wizards.newproject.NewProjectWizard" class="com.android.ide.eclipse.adt.wizards.newproject.NewProjectWizard"
finalPerspective="org.eclipse.jdt.ui.JavaPerspective" finalPerspective="org.eclipse.jdt.ui.JavaPerspective"
hasPages="true" hasPages="true"
icon="icons/android.png" icon="icons/new_adt_project.png"
id="com.android.ide.eclipse.adt.project.NewProjectWizard" id="com.android.ide.eclipse.adt.project.NewProjectWizard"
name="Android Project" name="Android Project"
preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective" preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective"
@@ -98,10 +98,22 @@
<wizard <wizard
canFinishEarly="false" canFinishEarly="false"
category="com.android.ide.eclipse.wizards.category" category="com.android.ide.eclipse.wizards.category"
class="com.android.ide.eclipse.editors.wizards.NewXmlFileWizard" class="com.android.ide.eclipse.adt.wizards.newproject.NewTestProjectWizard"
finalPerspective="org.eclipse.jdt.ui.JavaPerspective" finalPerspective="org.eclipse.jdt.ui.JavaPerspective"
hasPages="true" hasPages="true"
icon="icons/android.png" icon="icons/androidjunit.png"
id="com.android.ide.eclipse.adt.project.NewTestProjectWizard"
name="Android Test Project"
preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective"
project="true">
</wizard>
<wizard
canFinishEarly="false"
category="com.android.ide.eclipse.wizards.category"
class="com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard"
finalPerspective="org.eclipse.jdt.ui.JavaPerspective"
hasPages="true"
icon="icons/new_xml.png"
id="com.android.ide.eclipse.editors.wizards.NewXmlFileWizard" id="com.android.ide.eclipse.editors.wizards.NewXmlFileWizard"
name="Android XML File" name="Android XML File"
preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective" preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective"
@@ -220,11 +232,22 @@
value="com.android.ide.eclipse.adt.AndroidNature"> value="com.android.ide.eclipse.adt.AndroidNature">
</filter> </filter>
<action <action
class="com.android.ide.eclipse.adt.project.NewXmlFileWizardAction" class="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
enablesFor="1" enablesFor="1"
id="com.android.ide.eclipse.adt.project.NewXmlFileWizardAction" icon="icons/new_xml.png"
id="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
label="New Resource File..." label="New Resource File..."
menubarPath="com.android.ide.eclipse.adt.AndroidTools/group1"> menubarPath="com.android.ide.eclipse.adt.AndroidTools/group1"
tooltip="Opens a wizard to help create a new Android XML Resource file">
</action>
<action
class="com.android.ide.eclipse.adt.wizards.actions.NewTestProjectAction"
enablesFor="1"
icon="icons/androidjunit.png"
id="com.android.ide.eclipse.adt.wizards.actions.NewTestProjectAction"
label="New Test Project..."
menubarPath="com.android.ide.eclipse.adt.AndroidTools/group1"
tooltip="Opens a wizard to help create a new Android Test Project">
</action> </action>
<action <action
class="com.android.ide.eclipse.adt.project.ExportAction" class="com.android.ide.eclipse.adt.project.ExportAction"
@@ -483,6 +506,15 @@
toolbarPath="android_project" toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android XML file"> tooltip="Opens a wizard to help create a new Android XML file">
</action> </action>
<action
class="com.android.ide.eclipse.adt.wizards.actions.NewTestProjectAction"
icon="icons/androidjunit.png"
id="com.android.ide.eclipse.adt.wizards.actions.NewTestProjectAction"
label="New Android Test Project"
style="push"
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android Test Project">
</action>
<action <action
class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction" class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
icon="icons/new_adt_project.png" icon="icons/new_adt_project.png"

View File

@@ -70,6 +70,22 @@ public final class ProjectHelper {
return newEntries; return newEntries;
} }
/**
* Adds the corresponding source folder to the project's class path entries.
*
* @param javaProject The java project of which path entries to update.
* @param new_entry The parent source folder to remove.
* @throws JavaModelException
*/
public static void addEntryToClasspath(
IJavaProject javaProject, IClasspathEntry new_entry)
throws JavaModelException {
IClasspathEntry[] entries = javaProject.getRawClasspath();
entries = addEntryToClasspath(entries, new_entry);
javaProject.setRawClasspath(entries, new NullProgressMonitor());
}
/** /**
* Remove a classpath entry from the array. * Remove a classpath entry from the array.
* @param entries The class path entries to read. A copy will be returned * @param entries The class path entries to read. A copy will be returned
@@ -265,6 +281,8 @@ public final class ProjectHelper {
// If needed, check and fix compiler compliance and source compatibility // If needed, check and fix compiler compliance and source compatibility
ProjectHelper.checkAndFixCompilerCompliance(javaProject); ProjectHelper.checkAndFixCompilerCompliance(javaProject);
} }
/** /**
* Checks the project compiler compliance level is supported. * Checks the project compiler compliance level is supported.
* @param javaProject The project to check * @param javaProject The project to check

View File

@@ -200,7 +200,8 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
label.setText("Configuration:"); label.setText("Configuration:");
mConfigSelector = new ConfigurationSelector(group); mConfigSelector = new ConfigurationSelector(group);
GridData gd = new GridData(2, GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); GridData gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
gd.horizontalSpan = 2;
gd.widthHint = ConfigurationSelector.WIDTH_HINT; gd.widthHint = ConfigurationSelector.WIDTH_HINT;
gd.heightHint = ConfigurationSelector.HEIGHT_HINT; gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
mConfigSelector.setLayoutData(gd); mConfigSelector.setLayoutData(gd);

View File

@@ -23,7 +23,9 @@ import org.eclipse.ui.IWorkbenchWizard;
/** /**
* Delegate for the toolbar action "Android Project". * Delegate for the toolbar action "Android Project".
* It displays the Android New Project wizard. * It displays the Android New Project wizard to create a new Android Project (not a test project).
*
* @see NewTestProjectAction
*/ */
public class NewProjectAction extends OpenWizardAction { public class NewProjectAction extends OpenWizardAction {

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2009 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.wizards.actions;
import com.android.ide.eclipse.adt.wizards.newproject.NewTestProjectWizard;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IWorkbenchWizard;
/**
* Delegate for the toolbar action "Android Test Project".
* It displays the Android New Project wizard to create a new Test Project.
*/
public class NewTestProjectAction extends OpenWizardAction {
@Override
protected IWorkbenchWizard instanciateWizard(IAction action) {
return new NewTestProjectWizard();
}
}

View File

@@ -22,7 +22,9 @@ import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IWorkbenchWizard; import org.eclipse.ui.IWorkbenchWizard;
/** /**
* Delegate for the toolbar action "Android Project". * Delegate for the toolbar action "Android Project" or for the
* project > Android Project context menu.
*
* It displays the Android New XML file wizard. * It displays the Android New XML file wizard.
*/ */
public class NewXmlFileAction extends OpenWizardAction { public class NewXmlFileAction extends OpenWizardAction {

View File

@@ -1,57 +0,0 @@
/*
* Copyright (C) 2008 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.wizards.actions;
import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart;
public class NewXmlFileWizardAction implements IObjectActionDelegate {
private ISelection mSelection;
private IWorkbench mWorkbench;
/**
* @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench();
}
public void run(IAction action) {
if (mSelection instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection)mSelection;
// call the new xml file wizard on the current selection.
NewXmlFileWizard wizard = new NewXmlFileWizard();
wizard.init(mWorkbench, selection);
WizardDialog dialog = new WizardDialog(mWorkbench.getDisplay().getActiveShell(),
wizard);
dialog.open();
}
}
public void selectionChanged(IAction action, ISelection selection) {
this.mSelection = selection;
}
}

View File

@@ -28,6 +28,7 @@ import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindow;
@@ -43,7 +44,8 @@ import org.eclipse.ui.internal.util.Util;
* An abstract action that displays one of our wizards. * An abstract action that displays one of our wizards.
* Derived classes must provide the actual wizard to display. * Derived classes must provide the actual wizard to display.
*/ */
/*package*/ abstract class OpenWizardAction implements IWorkbenchWindowActionDelegate { /*package*/ abstract class OpenWizardAction
implements IWorkbenchWindowActionDelegate, IObjectActionDelegate {
/** /**
* The wizard dialog width, extracted from {@link NewWizardShortcutAction} * The wizard dialog width, extracted from {@link NewWizardShortcutAction}
@@ -60,6 +62,9 @@ import org.eclipse.ui.internal.util.Util;
/** The result from the dialog */ /** The result from the dialog */
private int mDialogResult; private int mDialogResult;
private ISelection mSelection;
private IWorkbench mWorkbench;
/** Returns the wizard that was created by {@link #run(IAction)}. */ /** Returns the wizard that was created by {@link #run(IAction)}. */
public IWorkbenchWizard getWizard() { public IWorkbenchWizard getWizard() {
return mWizard; return mWizard;
@@ -96,12 +101,16 @@ import org.eclipse.ui.internal.util.Util;
public void run(IAction action) { public void run(IAction action) {
// get the workbench and the current window // get the workbench and the current window
IWorkbench workbench = PlatformUI.getWorkbench(); IWorkbench workbench = mWorkbench != null ? mWorkbench : PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
// This code from NewWizardShortcutAction#run() gets the current window selection // This code from NewWizardShortcutAction#run() gets the current window selection
// and converts it to a workbench structured selection for the wizard, if possible. // and converts it to a workbench structured selection for the wizard, if possible.
ISelection selection = window.getSelectionService().getSelection(); ISelection selection = mSelection;
if (selection == null) {
selection = window.getSelectionService().getSelection();
}
IStructuredSelection selectionToPass = StructuredSelection.EMPTY; IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
if (selection instanceof IStructuredSelection) { if (selection instanceof IStructuredSelection) {
selectionToPass = (IStructuredSelection) selection; selectionToPass = (IStructuredSelection) selection;
@@ -157,7 +166,13 @@ import org.eclipse.ui.internal.util.Util;
* @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
*/ */
public void selectionChanged(IAction action, ISelection selection) { public void selectionChanged(IAction action, ISelection selection) {
// pass mSelection = selection;
} }
/* (non-Javadoc)
* @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
mWorkbench = targetPart.getSite().getWorkbenchWindow().getWorkbench();
}
} }

View File

@@ -25,6 +25,7 @@ package com.android.ide.eclipse.adt.wizards.newproject;
import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener; import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.adt.wizards.newproject.NewTestProjectCreationPage.TestInfo;
import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser; import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity; import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity;
@@ -84,6 +85,8 @@ import java.util.regex.Pattern;
public class NewProjectCreationPage extends WizardPage { public class NewProjectCreationPage extends WizardPage {
// constants // constants
private static final String MAIN_PAGE_NAME = "newAndroidProjectPage"; //$NON-NLS-1$
/** Initial value for all name fields (project, activity, application, package). Used /** Initial value for all name fields (project, activity, application, package). Used
* whenever a value is requested before controls are created. */ * whenever a value is requested before controls are created. */
private static final String INITIAL_NAME = ""; //$NON-NLS-1$ private static final String INITIAL_NAME = ""; //$NON-NLS-1$
@@ -107,6 +110,12 @@ public class NewProjectCreationPage extends WizardPage {
private final int MSG_WARNING = 1; private final int MSG_WARNING = 1;
private final int MSG_ERROR = 2; private final int MSG_ERROR = 2;
/** Structure with the externally visible information from this Main Project page. */
private final MainInfo mInfo = new MainInfo();
/** Structure with the externally visible information from the Test Project page.
* This is null if there's no such page, meaning the main project page is standalone. */
private TestInfo mTestInfo;
private String mUserPackageName = ""; //$NON-NLS-1$ private String mUserPackageName = ""; //$NON-NLS-1$
private String mUserActivityName = ""; //$NON-NLS-1$ private String mUserActivityName = ""; //$NON-NLS-1$
private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY; private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY;
@@ -128,28 +137,73 @@ public class NewProjectCreationPage extends WizardPage {
private ITargetChangeListener mSdkTargetChangeListener; private ITargetChangeListener mSdkTargetChangeListener;
private boolean mInternalLocationPathUpdate; private boolean mInternalLocationPathUpdate;
protected boolean mInternalProjectNameUpdate; private boolean mInternalProjectNameUpdate;
protected boolean mInternalApplicationNameUpdate; private boolean mInternalApplicationNameUpdate;
private boolean mInternalCreateActivityUpdate; private boolean mInternalCreateActivityUpdate;
private boolean mInternalActivityNameUpdate; private boolean mInternalActivityNameUpdate;
protected boolean mProjectNameModifiedByUser; private boolean mProjectNameModifiedByUser;
protected boolean mApplicationNameModifiedByUser; private boolean mApplicationNameModifiedByUser;
private boolean mInternalMinSdkVersionUpdate; private boolean mInternalMinSdkVersionUpdate;
private boolean mMinSdkVersionModifiedByUser;
/** /**
* Creates a new project creation wizard page. * Creates a new project creation wizard page.
*
* @param pageName the name of this page
*/ */
public NewProjectCreationPage(String pageName) { public NewProjectCreationPage() {
super(pageName); super(MAIN_PAGE_NAME);
setPageComplete(false); setPageComplete(false);
setTitle("New Android Project");
setDescription("Creates a new Android Project resource.");
} }
// --- Getters used by NewProjectWizard --- // --- Getters used by NewProjectWizard ---
/**
* 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.
* <p/>
* This interface is provided so that the adt-test counterpart can override the returned
* information.
*/
public interface IMainInfo {
public IPath getLocationPath();
/**
* Returns the current project location path as entered by the user, or its
* anticipated initial value. Note that if the default has been returned the
* path in a project description used to create a project should not be set.
*
* @return the project location path or its anticipated initial value.
*/
/** Returns the value of the project name field with leading and trailing spaces removed. */
public String getProjectName();
/** Returns the value of the package name field with spaces trimmed. */
public String getPackageName();
/** Returns the value of the activity name field with spaces trimmed. */
public String getActivityName();
/** Returns the value of the min sdk version field with spaces trimmed. */
public String getMinSdkVersion();
/** Returns the value of the application name field with spaces trimmed. */
public String getApplicationName();
/** Returns the value of the "Create New Project" radio. */
public boolean isNewProject();
/** Returns the value of the "Create Activity" checkbox. */
public boolean isCreateActivity();
/** Returns the value of the Use Default Location field. */
public boolean useDefaultLocation();
/** Returns the internal source folder (for the "existing project" mode) or the default
* "src" constant. */
public String getSourceFolder();
/** Returns the current sdk target or null if none has been selected yet. */
public IAndroidTarget getSdkTarget();
}
/**
* 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.
*/
public class MainInfo implements IMainInfo {
/** /**
* Returns the current project location path as entered by the user, or its * Returns the current project location path as entered by the user, or its
* anticipated initial value. Note that if the default has been returned the * anticipated initial value. Note that if the default has been returned the
@@ -178,7 +232,7 @@ public class NewProjectCreationPage extends WizardPage {
/** Returns the value of the min sdk version field with spaces trimmed. */ /** Returns the value of the min sdk version field with spaces trimmed. */
public String getMinSdkVersion() { public String getMinSdkVersion() {
return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim(); return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim(); //$NON-NLS-1$
} }
/** Returns the value of the application name field with spaces trimmed. */ /** Returns the value of the application name field with spaces trimmed. */
@@ -221,6 +275,23 @@ public class NewProjectCreationPage extends WizardPage {
public IAndroidTarget getSdkTarget() { public IAndroidTarget getSdkTarget() {
return mSdkTargetSelector == null ? null : mSdkTargetSelector.getSelected(); return mSdkTargetSelector == null ? null : mSdkTargetSelector.getSelected();
} }
}
/**
* Returns a {@link MainInfo} structure that collects all externally visible information
* from this page, to be used by the calling wizard or by other pages.
*/
public IMainInfo getMainInfo() {
return mInfo;
}
/**
* Grabs the {@link TestInfo} structure that collects externally visible fields from the
* test project page. This may be null.
*/
public void setTestInfo(TestInfo testInfo) {
mTestInfo = testInfo;
}
/** /**
* Overrides @DialogPage.setVisible(boolean) to put the focus in the project name when * Overrides @DialogPage.setVisible(boolean) to put the focus in the project name when
@@ -231,6 +302,7 @@ public class NewProjectCreationPage extends WizardPage {
super.setVisible(visible); super.setVisible(visible);
if (visible) { if (visible) {
mProjectNameField.setFocus(); mProjectNameField.setFocus();
validatePageComplete();
} }
} }
@@ -265,7 +337,7 @@ public class NewProjectCreationPage extends WizardPage {
setControl(composite); setControl(composite);
// Validate. This will complain about the first empty field. // Validate. This will complain about the first empty field.
setPageComplete(validatePage()); validatePageComplete();
} }
@Override @Override
@@ -328,7 +400,7 @@ public class NewProjectCreationPage extends WizardPage {
Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
// Layout has 4 columns of non-equal size // Layout has 4 columns of non-equal size
group.setLayout(new GridLayout()); group.setLayout(new GridLayout());
group.setLayoutData(new GridData(GridData.FILL_BOTH)); group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
group.setFont(parent.getFont()); group.setFont(parent.getFont());
group.setText("Contents"); group.setText("Contents");
@@ -349,7 +421,7 @@ public class NewProjectCreationPage extends WizardPage {
super.widgetSelected(e); super.widgetSelected(e);
enableLocationWidgets(); enableLocationWidgets();
extractNamesFromAndroidManifest(); extractNamesFromAndroidManifest();
setPageComplete(validatePage()); validatePageComplete();
} }
}; };
@@ -358,9 +430,9 @@ public class NewProjectCreationPage extends WizardPage {
mUseDefaultLocation.addSelectionListener(location_listener); mUseDefaultLocation.addSelectionListener(location_listener);
Composite location_group = new Composite(group, SWT.NONE); Composite location_group = new Composite(group, SWT.NONE);
location_group.setLayout(new GridLayout(4, /* num columns */ location_group.setLayout(new GridLayout(3, /* num columns */
false /* columns of not equal size */)); false /* columns of not equal size */));
location_group.setLayoutData(new GridData(GridData.FILL_BOTH)); location_group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
location_group.setFont(parent.getFont()); location_group.setFont(parent.getFont());
mLocationLabel = new Label(location_group, SWT.NONE); mLocationLabel = new Label(location_group, SWT.NONE);
@@ -371,7 +443,7 @@ public class NewProjectCreationPage extends WizardPage {
GridData.BEGINNING, /* vertical alignment */ GridData.BEGINNING, /* vertical alignment */
true, /* grabExcessHorizontalSpace */ true, /* grabExcessHorizontalSpace */
false, /* grabExcessVerticalSpace */ false, /* grabExcessVerticalSpace */
2, /* horizontalSpan */ 1, /* horizontalSpan */
1); /* verticalSpan */ 1); /* verticalSpan */
mLocationPathField.setLayoutData(data); mLocationPathField.setLayoutData(data);
mLocationPathField.setFont(parent.getFont()); mLocationPathField.setFont(parent.getFont());
@@ -387,7 +459,7 @@ public class NewProjectCreationPage extends WizardPage {
mBrowseButton.addSelectionListener(new SelectionAdapter() { mBrowseButton.addSelectionListener(new SelectionAdapter() {
@Override @Override
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent e) {
openDirectoryBrowser(); onOpenDirectoryBrowser();
} }
}); });
} }
@@ -439,40 +511,11 @@ public class NewProjectCreationPage extends WizardPage {
public void widgetSelected(SelectionEvent e) { public void widgetSelected(SelectionEvent e) {
onSdkTargetModified(); onSdkTargetModified();
updateLocationPathField(null); updateLocationPathField(null);
setPageComplete(validatePage()); validatePageComplete();
} }
}); });
} }
/**
* Display a directory browser and update the location path field with the selected path
*/
private void openDirectoryBrowser() {
String existing_dir = getLocationPathFieldValue();
// Disable the path if it doesn't exist
if (existing_dir.length() == 0) {
existing_dir = null;
} else {
File f = new File(existing_dir);
if (!f.exists()) {
existing_dir = null;
}
}
DirectoryDialog dd = new DirectoryDialog(mLocationPathField.getShell());
dd.setMessage("Browse for folder");
dd.setFilterPath(existing_dir);
String abs_dir = dd.open();
if (abs_dir != null) {
updateLocationPathField(abs_dir);
extractNamesFromAndroidManifest();
setPageComplete(validatePage());
}
}
/** /**
* Creates the group for the project properties: * Creates the group for the project properties:
* - Package name [text field] * - Package name [text field]
@@ -569,7 +612,7 @@ public class NewProjectCreationPage extends WizardPage {
mMinSdkVersionField.addListener(SWT.Modify, new Listener() { mMinSdkVersionField.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event event) { public void handleEvent(Event event) {
onMinSdkVersionFieldModified(); onMinSdkVersionFieldModified();
setPageComplete(validatePage()); validatePageComplete();
} }
}); });
} }
@@ -579,12 +622,12 @@ public class NewProjectCreationPage extends WizardPage {
/** Returns the location path field value with spaces trimmed. */ /** Returns the location path field value with spaces trimmed. */
private String getLocationPathFieldValue() { private String getLocationPathFieldValue() {
return mLocationPathField == null ? "" : mLocationPathField.getText().trim(); return mLocationPathField == null ? "" : mLocationPathField.getText().trim(); //$NON-NLS-1$
} }
/** Returns the current project location, depending on the Use Default Location check box. */ /** Returns the current project location, depending on the Use Default Location check box. */
public String getProjectLocation() { private String getProjectLocation() {
if (isNewProject() && useDefaultLocation()) { if (mInfo.isNewProject() && mInfo.useDefaultLocation()) {
return Platform.getLocation().toString(); return Platform.getLocation().toString();
} else { } else {
return getLocationPathFieldValue(); return getLocationPathFieldValue();
@@ -603,21 +646,50 @@ public class NewProjectCreationPage extends WizardPage {
* @return the new project resource handle * @return the new project resource handle
*/ */
private IProject getProjectHandle() { private IProject getProjectHandle() {
return ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName()); return ResourcesPlugin.getWorkspace().getRoot().getProject(mInfo.getProjectName());
} }
// --- UI Callbacks ---- // --- UI Callbacks ----
/**
* Display a directory browser and update the location path field with the selected path
*/
private void onOpenDirectoryBrowser() {
String existing_dir = getLocationPathFieldValue();
// Disable the path if it doesn't exist
if (existing_dir.length() == 0) {
existing_dir = null;
} else {
File f = new File(existing_dir);
if (!f.exists()) {
existing_dir = null;
}
}
DirectoryDialog dd = new DirectoryDialog(mLocationPathField.getShell());
dd.setMessage("Browse for folder");
dd.setFilterPath(existing_dir);
String abs_dir = dd.open();
if (abs_dir != null) {
updateLocationPathField(abs_dir);
extractNamesFromAndroidManifest();
validatePageComplete();
}
}
/** /**
* Enables or disable the location widgets depending on the user selection: * Enables or disable the location widgets depending on the user selection:
* the location path is enabled when using the "existing source" mode (i.e. not new project) * the location path is enabled when using the "existing source" mode (i.e. not new project)
* or in new project mode with the "use default location" turned off. * or in new project mode with the "use default location" turned off.
*/ */
private void enableLocationWidgets() { private void enableLocationWidgets() {
boolean is_new_project = isNewProject(); boolean is_new_project = mInfo.isNewProject();
boolean use_default = useDefaultLocation(); boolean use_default = mInfo.useDefaultLocation();
boolean location_enabled = !is_new_project || !use_default; boolean location_enabled = !is_new_project || !use_default;
boolean create_activity = isCreateActivity(); boolean create_activity = mInfo.isCreateActivity();
mUseDefaultLocation.setEnabled(is_new_project); mUseDefaultLocation.setEnabled(is_new_project);
@@ -646,8 +718,8 @@ public class NewProjectCreationPage extends WizardPage {
* @param abs_dir A new absolute directory path or null to use the default. * @param abs_dir A new absolute directory path or null to use the default.
*/ */
private void updateLocationPathField(String abs_dir) { private void updateLocationPathField(String abs_dir) {
boolean is_new_project = isNewProject(); boolean is_new_project = mInfo.isNewProject();
boolean use_default = useDefaultLocation(); boolean use_default = mInfo.useDefaultLocation();
boolean custom_location = !is_new_project || !use_default; boolean custom_location = !is_new_project || !use_default;
if (!mInternalLocationPathUpdate) { if (!mInternalLocationPathUpdate) {
@@ -663,7 +735,7 @@ public class NewProjectCreationPage extends WizardPage {
} else if (sAutoComputeCustomLocation || } else if (sAutoComputeCustomLocation ||
(!is_new_project && !new File(sCustomLocationOsPath).isDirectory())) { (!is_new_project && !new File(sCustomLocationOsPath).isDirectory())) {
// By default select the samples directory of the current target // By default select the samples directory of the current target
IAndroidTarget target = getSdkTarget(); IAndroidTarget target = mInfo.getSdkTarget();
if (target != null) { if (target != null) {
sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES); sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES);
} }
@@ -682,13 +754,13 @@ public class NewProjectCreationPage extends WizardPage {
mLocationPathField.setText(sCustomLocationOsPath); mLocationPathField.setText(sCustomLocationOsPath);
} }
} else { } else {
String value = Platform.getLocation().append(getProjectName()).toString(); String value = Platform.getLocation().append(mInfo.getProjectName()).toString();
value = TextProcessor.process(value); value = TextProcessor.process(value);
if (!mLocationPathField.getText().equals(value)) { if (!mLocationPathField.getText().equals(value)) {
mLocationPathField.setText(value); mLocationPathField.setText(value);
} }
} }
setPageComplete(validatePage()); validatePageComplete();
mInternalLocationPathUpdate = false; mInternalLocationPathUpdate = false;
} }
} }
@@ -711,7 +783,7 @@ public class NewProjectCreationPage extends WizardPage {
newPath.equals(sCustomLocationOsPath); newPath.equals(sCustomLocationOsPath);
sCustomLocationOsPath = newPath; sCustomLocationOsPath = newPath;
extractNamesFromAndroidManifest(); extractNamesFromAndroidManifest();
setPageComplete(validatePage()); validatePageComplete();
} }
} }
@@ -723,9 +795,9 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page. * validate the page.
*/ */
private void onPackageNameFieldModified() { private void onPackageNameFieldModified() {
if (isNewProject()) { if (mInfo.isNewProject()) {
mUserPackageName = getPackageName(); mUserPackageName = mInfo.getPackageName();
setPageComplete(validatePage()); validatePageComplete();
} }
} }
@@ -737,10 +809,10 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page. * validate the page.
*/ */
private void onCreateActivityCheckModified() { private void onCreateActivityCheckModified() {
if (isNewProject() && !mInternalCreateActivityUpdate) { if (mInfo.isNewProject() && !mInternalCreateActivityUpdate) {
mUserCreateActivityCheck = isCreateActivity(); mUserCreateActivityCheck = mInfo.isCreateActivity();
} }
setPageComplete(validatePage()); validatePageComplete();
} }
/** /**
@@ -751,9 +823,9 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page. * validate the page.
*/ */
private void onActivityNameFieldModified() { private void onActivityNameFieldModified() {
if (isNewProject() && !mInternalActivityNameUpdate) { if (mInfo.isNewProject() && !mInternalActivityNameUpdate) {
mUserActivityName = getActivityName(); mUserActivityName = mInfo.getActivityName();
setPageComplete(validatePage()); validatePageComplete();
} }
} }
@@ -769,12 +841,12 @@ public class NewProjectCreationPage extends WizardPage {
} }
try { try {
int version = Integer.parseInt(getMinSdkVersion()); int version = Integer.parseInt(mInfo.getMinSdkVersion());
// Before changing, compare with the currently selected one, if any. // Before changing, compare with the currently selected one, if any.
// There can be multiple targets with the same sdk api version, so don't change // There can be multiple targets with the same sdk api version, so don't change
// it if it's already at the right version. // it if it's already at the right version.
IAndroidTarget curr_target = getSdkTarget(); IAndroidTarget curr_target = mInfo.getSdkTarget();
if (curr_target != null && curr_target.getApiVersionNumber() == version) { if (curr_target != null && curr_target.getApiVersionNumber() == version) {
return; return;
} }
@@ -788,20 +860,18 @@ public class NewProjectCreationPage extends WizardPage {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// ignore // ignore
} }
mMinSdkVersionModifiedByUser = true;
} }
/** /**
* Called when an SDK target is modified. * Called when an SDK target is modified.
* *
* If the minSdkVersion field hasn't been modified by the user yet, we change it * Also changes the minSdkVersion field to reflect the sdk api level that has
* to reflect the sdk api level that has just been selected. * just been selected.
*/ */
private void onSdkTargetModified() { private void onSdkTargetModified() {
IAndroidTarget target = getSdkTarget(); IAndroidTarget target = mInfo.getSdkTarget();
if (target != null && !mMinSdkVersionModifiedByUser) { if (target != null) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber())); mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
mInternalMinSdkVersionUpdate = false; mInternalMinSdkVersionUpdate = false;
@@ -814,7 +884,7 @@ public class NewProjectCreationPage extends WizardPage {
* entered before. * entered before.
*/ */
private void updatePackageAndActivityFields() { private void updatePackageAndActivityFields() {
if (isNewProject()) { if (mInfo.isNewProject()) {
if (mUserPackageName.length() > 0 && if (mUserPackageName.length() > 0 &&
!mPackageNameField.getText().equals(mUserPackageName)) { !mPackageNameField.getText().equals(mUserPackageName)) {
mPackageNameField.setText(mUserPackageName); mPackageNameField.setText(mUserPackageName);
@@ -841,7 +911,7 @@ public class NewProjectCreationPage extends WizardPage {
* can actually be found in the custom user directory. * can actually be found in the custom user directory.
*/ */
private void extractNamesFromAndroidManifest() { private void extractNamesFromAndroidManifest() {
if (isNewProject()) { if (mInfo.isNewProject()) {
return; return;
} }
@@ -990,8 +1060,8 @@ public class NewProjectCreationPage extends WizardPage {
if (!foundTarget) { if (!foundTarget) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText( mMinSdkVersionField.setText(
minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" : minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" //$NON-NLS-1$
Integer.toString(minSdkVersion)); //$NON-NLS-1$ : Integer.toString(minSdkVersion));
mInternalMinSdkVersionUpdate = false; mInternalMinSdkVersionUpdate = false;
} }
} }
@@ -1002,7 +1072,7 @@ public class NewProjectCreationPage extends WizardPage {
* @return <code>true</code> if all controls are valid, and * @return <code>true</code> if all controls are valid, and
* <code>false</code> if at least one is invalid * <code>false</code> if at least one is invalid
*/ */
protected boolean validatePage() { private boolean validatePage() {
IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspace workspace = ResourcesPlugin.getWorkspace();
int status = validateProjectField(workspace); int status = validateProjectField(workspace);
@@ -1032,6 +1102,13 @@ public class NewProjectCreationPage extends WizardPage {
return (status & MSG_ERROR) == 0; return (status & MSG_ERROR) == 0;
} }
/**
* Validates the page and updates the Next/Finish buttons
*/
private void validatePageComplete() {
setPageComplete(validatePage());
}
/** /**
* Validates the project name field. * Validates the project name field.
* *
@@ -1039,19 +1116,19 @@ public class NewProjectCreationPage extends WizardPage {
*/ */
private int validateProjectField(IWorkspace workspace) { private int validateProjectField(IWorkspace workspace) {
// Validate project field // Validate project field
String projectFieldContents = getProjectName(); String projectName = mInfo.getProjectName();
if (projectFieldContents.length() == 0) { if (projectName.length() == 0) {
return setStatus("Project name must be specified", MSG_ERROR); return setStatus("Project name must be specified", MSG_ERROR);
} }
// Limit the project name to shell-agnostic characters since it will be used to // Limit the project name to shell-agnostic characters since it will be used to
// generate the final package // generate the final package
if (!sProjectNamePattern.matcher(projectFieldContents).matches()) { if (!sProjectNamePattern.matcher(projectName).matches()) {
return setStatus("The project name must start with an alphanumeric characters, followed by one or more alphanumerics, digits, dots, dashes, underscores or spaces.", return setStatus("The project name must start with an alphanumeric characters, followed by one or more alphanumerics, digits, dots, dashes, underscores or spaces.",
MSG_ERROR); MSG_ERROR);
} }
IStatus nameStatus = workspace.validateName(projectFieldContents, IResource.PROJECT); IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT);
if (!nameStatus.isOK()) { if (!nameStatus.isOK()) {
return setStatus(nameStatus.getMessage(), MSG_ERROR); return setStatus(nameStatus.getMessage(), MSG_ERROR);
} }
@@ -1061,6 +1138,13 @@ public class NewProjectCreationPage extends WizardPage {
MSG_ERROR); MSG_ERROR);
} }
if (mTestInfo != null &&
mTestInfo.getCreateTestProject() &&
projectName.equals(mTestInfo.getProjectName())) {
return setStatus("The main project name and the test project name must be different.",
MSG_WARNING);
}
return MSG_NONE; return MSG_NONE;
} }
@@ -1071,8 +1155,8 @@ public class NewProjectCreationPage extends WizardPage {
*/ */
private int validateLocationPath(IWorkspace workspace) { private int validateLocationPath(IWorkspace workspace) {
Path path = new Path(getProjectLocation()); Path path = new Path(getProjectLocation());
if (isNewProject()) { if (mInfo.isNewProject()) {
if (!useDefaultLocation()) { if (!mInfo.useDefaultLocation()) {
// If not using the default value validate the location. // If not using the default value validate the location.
URI uri = URIUtil.toURI(path.toOSString()); URI uri = URIUtil.toURI(path.toOSString());
IStatus locationStatus = workspace.validateProjectLocationURI(getProjectHandle(), IStatus locationStatus = workspace.validateProjectLocationURI(getProjectHandle(),
@@ -1103,10 +1187,10 @@ public class NewProjectCreationPage extends WizardPage {
return setStatus("A directory name must be specified.", MSG_ERROR); return setStatus("A directory name must be specified.", MSG_ERROR);
} }
File dest = path.append(getProjectName()).toFile(); File dest = path.append(mInfo.getProjectName()).toFile();
if (dest.exists()) { if (dest.exists()) {
return setStatus(String.format("There is already a file or directory named \"%1$s\" in the selected location.", return setStatus(String.format("There is already a file or directory named \"%1$s\" in the selected location.",
getProjectName()), MSG_ERROR); mInfo.getProjectName()), MSG_ERROR);
} }
} }
} else { } else {
@@ -1144,7 +1228,7 @@ public class NewProjectCreationPage extends WizardPage {
Activity[] activities = manifestData.getActivities(); Activity[] activities = manifestData.getActivities();
if (activities == null || activities.length == 0) { if (activities == null || activities.length == 0) {
// This is acceptable now as long as no activity needs to be created // This is acceptable now as long as no activity needs to be created
if (isCreateActivity()) { if (mInfo.isCreateActivity()) {
return setStatus( return setStatus(
String.format("No activity name defined in %1$s.", osPath), String.format("No activity name defined in %1$s.", osPath),
MSG_ERROR); MSG_ERROR);
@@ -1167,7 +1251,7 @@ public class NewProjectCreationPage extends WizardPage {
* @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE.
*/ */
private int validateSdkTarget() { private int validateSdkTarget() {
if (getSdkTarget() == null) { if (mInfo.getSdkTarget() == null) {
return setStatus("An SDK Target must be specified.", MSG_ERROR); return setStatus("An SDK Target must be specified.", MSG_ERROR);
} }
return MSG_NONE; return MSG_NONE;
@@ -1181,14 +1265,14 @@ public class NewProjectCreationPage extends WizardPage {
private int validateMinSdkVersionField() { private int validateMinSdkVersionField() {
// If the min sdk version is empty, it is always accepted. // If the min sdk version is empty, it is always accepted.
if (getMinSdkVersion().length() == 0) { if (mInfo.getMinSdkVersion().length() == 0) {
return MSG_NONE; return MSG_NONE;
} }
int version = AndroidManifestParser.INVALID_MIN_SDK; int version = AndroidManifestParser.INVALID_MIN_SDK;
try { try {
// If not empty, it must be a valid integer > 0 // If not empty, it must be a valid integer > 0
version = Integer.parseInt(getMinSdkVersion()); version = Integer.parseInt(mInfo.getMinSdkVersion());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// ignore // ignore
} }
@@ -1197,7 +1281,7 @@ public class NewProjectCreationPage extends WizardPage {
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR); return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
} }
if (getSdkTarget() != null && getSdkTarget().getApiVersionNumber() != version) { if (mInfo.getSdkTarget() != null && mInfo.getSdkTarget().getApiVersionNumber() != version) {
return setStatus("The API level for the selected SDK target does not match the Min SDK version.", return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
MSG_WARNING); MSG_WARNING);
} }
@@ -1212,19 +1296,19 @@ public class NewProjectCreationPage extends WizardPage {
*/ */
private int validateActivityField() { private int validateActivityField() {
// Disregard if not creating an activity // Disregard if not creating an activity
if (!isCreateActivity()) { if (!mInfo.isCreateActivity()) {
return MSG_NONE; return MSG_NONE;
} }
// Validate activity field // Validate activity field
String activityFieldContents = getActivityName(); String activityFieldContents = mInfo.getActivityName();
if (activityFieldContents.length() == 0) { if (activityFieldContents.length() == 0) {
return setStatus("Activity name must be specified.", MSG_ERROR); return setStatus("Activity name must be specified.", MSG_ERROR);
} }
// The activity field can actually contain part of a sub-package name // 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. // or it can start with a dot "." to indicates it comes from the parent package name.
String packageName = ""; String packageName = ""; //$NON-NLS-1$
int pos = activityFieldContents.lastIndexOf('.'); int pos = activityFieldContents.lastIndexOf('.');
if (pos >= 0) { if (pos >= 0) {
packageName = activityFieldContents.substring(0, pos); packageName = activityFieldContents.substring(0, pos);
@@ -1272,7 +1356,7 @@ public class NewProjectCreationPage extends WizardPage {
*/ */
private int validatePackageField() { private int validatePackageField() {
// Validate package field // Validate package field
String packageFieldContents = getPackageName(); String packageFieldContents = mInfo.getPackageName();
if (packageFieldContents.length() == 0) { if (packageFieldContents.length() == 0) {
return setStatus("Package name must be specified.", MSG_ERROR); return setStatus("Package name must be specified.", MSG_ERROR);
} }
@@ -1312,16 +1396,16 @@ public class NewProjectCreationPage extends WizardPage {
private int validateSourceFolder() { private int validateSourceFolder() {
// This check does nothing when creating a new project. // This check does nothing when creating a new project.
// This check is also useless when no activity is present or created. // This check is also useless when no activity is present or created.
if (isNewProject() || !isCreateActivity()) { if (mInfo.isNewProject() || !mInfo.isCreateActivity()) {
return MSG_NONE; return MSG_NONE;
} }
String osTarget = getActivityName(); String osTarget = mInfo.getActivityName();
if (osTarget.indexOf('.') == -1) { if (osTarget.indexOf('.') == -1) {
osTarget = getPackageName() + File.separator + osTarget; osTarget = mInfo.getPackageName() + File.separator + osTarget;
} else if (osTarget.indexOf('.') == 0) { } else if (osTarget.indexOf('.') == 0) {
osTarget = getPackageName() + osTarget; osTarget = mInfo.getPackageName() + osTarget;
} }
osTarget = osTarget.replace('.', File.separatorChar) + AndroidConstants.DOT_JAVA; osTarget = osTarget.replace('.', File.separatorChar) + AndroidConstants.DOT_JAVA;

View File

@@ -20,6 +20,8 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.AndroidNature; import com.android.ide.eclipse.adt.project.AndroidNature;
import com.android.ide.eclipse.adt.project.ProjectHelper; import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.wizards.newproject.NewProjectCreationPage.IMainInfo;
import com.android.ide.eclipse.adt.wizards.newproject.NewTestProjectCreationPage.TestInfo;
import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.AndroidConstants;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
@@ -39,6 +41,8 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaCore;
@@ -76,6 +80,24 @@ import java.util.Map.Entry;
*/ */
public class NewProjectWizard extends Wizard implements INewWizard { public class NewProjectWizard extends Wizard implements INewWizard {
/**
* Indicates which pages should be available in the New Project Wizard.
*/
protected enum AvailablePages {
/**
* Both the usual "Android Project" and the "Android Test Project" pages will
* be available. The first page displayed will be the former one and it can depend
* on the soon-to-be created normal project.
*/
ANDROID_AND_TEST_PROJECT,
/**
* Only the "Android Test Project" page will be available. User will have to
* select an existing Android Project. If the selection matches such a project,
* it will be used as a default.
*/
TEST_PROJECT_ONLY
}
private static final String PARAM_SDK_TOOLS_DIR = "ANDROID_SDK_TOOLS"; //$NON-NLS-1$ private static final String PARAM_SDK_TOOLS_DIR = "ANDROID_SDK_TOOLS"; //$NON-NLS-1$
private static final String PARAM_ACTIVITY = "ACTIVITY_NAME"; //$NON-NLS-1$ private static final String PARAM_ACTIVITY = "ACTIVITY_NAME"; //$NON-NLS-1$
private static final String PARAM_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$ private static final String PARAM_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$
@@ -87,11 +109,20 @@ public class NewProjectWizard extends Wizard implements INewWizard {
private static final String PARAM_SRC_FOLDER = "SRC_FOLDER"; //$NON-NLS-1$ private static final String PARAM_SRC_FOLDER = "SRC_FOLDER"; //$NON-NLS-1$
private static final String PARAM_SDK_TARGET = "SDK_TARGET"; //$NON-NLS-1$ private static final String PARAM_SDK_TARGET = "SDK_TARGET"; //$NON-NLS-1$
private static final String PARAM_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$ private static final String PARAM_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$
// Warning: The expanded string PARAM_TEST_TARGET_PACKAGE must not contain the
// string "PACKAGE" since it collides with the replacement of PARAM_PACKAGE.
private static final String PARAM_TEST_TARGET_PACKAGE = "TEST_TARGET_PCKG"; //$NON-NLS-1$
private static final String PARAM_TARGET_SELF = "TARGET_SELF"; //$NON-NLS-1$
private static final String PARAM_TARGET_MAIN = "TARGET_MAIN"; //$NON-NLS-1$
private static final String PARAM_TARGET_EXISTING = "TARGET_EXISTING"; //$NON-NLS-1$
private static final String PARAM_REFERENCE_PROJECT = "REFERENCE_PROJECT"; //$NON-NLS-1$
private static final String PH_ACTIVITIES = "ACTIVITIES"; //$NON-NLS-1$ private static final String PH_ACTIVITIES = "ACTIVITIES"; //$NON-NLS-1$
private static final String PH_USES_SDK = "USES-SDK"; //$NON-NLS-1$ private static final String PH_USES_SDK = "USES-SDK"; //$NON-NLS-1$
private static final String PH_INTENT_FILTERS = "INTENT_FILTERS"; //$NON-NLS-1$ private static final String PH_INTENT_FILTERS = "INTENT_FILTERS"; //$NON-NLS-1$
private static final String PH_STRINGS = "STRINGS"; //$NON-NLS-1$ private static final String PH_STRINGS = "STRINGS"; //$NON-NLS-1$
private static final String PH_TEST_USES_LIBRARY = "TEST-USES-LIBRARY"; //$NON-NLS-1$
private static final String PH_TEST_INSTRUMENTATION = "TEST-INSTRUMENTATION"; //$NON-NLS-1$
private static final String BIN_DIRECTORY = private static final String BIN_DIRECTORY =
SdkConstants.FD_OUTPUT + AndroidConstants.WS_SEP; SdkConstants.FD_OUTPUT + AndroidConstants.WS_SEP;
@@ -117,6 +148,12 @@ public class NewProjectWizard extends Wizard implements INewWizard {
+ "uses-sdk.template"; //$NON-NLS-1$ + "uses-sdk.template"; //$NON-NLS-1$
private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY
+ "launcher_intent_filter.template"; //$NON-NLS-1$ + "launcher_intent_filter.template"; //$NON-NLS-1$
private static final String TEMPLATE_TEST_USES_LIBRARY = TEMPLATES_DIRECTORY
+ "test_uses-library.template"; //$NON-NLS-1$
private static final String TEMPLATE_TEST_INSTRUMENTATION = TEMPLATES_DIRECTORY
+ "test_instrumentation.template"; //$NON-NLS-1$
private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY
+ "strings.template"; //$NON-NLS-1$ + "strings.template"; //$NON-NLS-1$
@@ -140,11 +177,19 @@ public class NewProjectWizard extends Wizard implements INewWizard {
private static final String LAYOUT_TEMPLATE = "layout.template"; //$NON-NLS-1$ private static final String LAYOUT_TEMPLATE = "layout.template"; //$NON-NLS-1$
private static final String MAIN_LAYOUT_XML = "main.xml"; //$NON-NLS-1$ private static final String MAIN_LAYOUT_XML = "main.xml"; //$NON-NLS-1$
protected static final String MAIN_PAGE_NAME = "newAndroidProjectPage"; //$NON-NLS-1$
private NewProjectCreationPage mMainPage; private NewProjectCreationPage mMainPage;
private NewTestProjectCreationPage mTestPage;
/** Package name available when the wizard completes. */ /** Package name available when the wizard completes. */
private String mPackageName; private String mPackageName;
private final AvailablePages mAvailablePages;
public NewProjectWizard() {
this(AvailablePages.ANDROID_AND_TEST_PROJECT);
}
protected NewProjectWizard(AvailablePages availablePages) {
mAvailablePages = availablePages;
}
/** /**
* Initializes this creation wizard using the passed workbench and object * Initializes this creation wizard using the passed workbench and object
@@ -155,13 +200,14 @@ public class NewProjectWizard extends Wizard implements INewWizard {
setWindowTitle("New Android Project"); setWindowTitle("New Android Project");
setImageDescriptor(); setImageDescriptor();
if (mAvailablePages == AvailablePages.ANDROID_AND_TEST_PROJECT) {
mMainPage = createMainPage(); mMainPage = createMainPage();
mMainPage.setTitle("New Android Project"); }
mMainPage.setDescription("Creates a new Android Project resource."); mTestPage = createTestPage();
} }
/** /**
* Creates the wizard page. * Creates the main wizard page.
* <p/> * <p/>
* Please do NOT override this method. * Please do NOT override this method.
* <p/> * <p/>
@@ -170,7 +216,20 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* to maintain compatibility between different versions of the plugin. * to maintain compatibility between different versions of the plugin.
*/ */
protected NewProjectCreationPage createMainPage() { protected NewProjectCreationPage createMainPage() {
return new NewProjectCreationPage(MAIN_PAGE_NAME); return new NewProjectCreationPage();
}
/**
* Creates the test wizard page.
* <p/>
* Please do NOT override this method.
* <p/>
* This is protected so that it can be overridden by unit tests.
* However the contract of this class is private and NO ATTEMPT will be made
* to maintain compatibility between different versions of the plugin.
*/
protected NewTestProjectCreationPage createTestPage() {
return new NewTestProjectCreationPage();
} }
// -- Methods inherited from org.eclipse.jface.wizard.Wizard -- // -- Methods inherited from org.eclipse.jface.wizard.Wizard --
@@ -182,8 +241,16 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*/ */
@Override @Override
public void addPages() { public void addPages() {
if (mAvailablePages == AvailablePages.ANDROID_AND_TEST_PROJECT) {
addPage(mMainPage); addPage(mMainPage);
} }
addPage(mTestPage);
if (mMainPage != null && mTestPage != null) {
mTestPage.setMainInfo(mMainPage.getMainInfo());
mMainPage.setTestInfo(mTestPage.getTestInfo());
}
}
/** /**
* Performs any actions appropriate in response to the user having pressed * Performs any actions appropriate in response to the user having pressed
@@ -195,7 +262,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*/ */
@Override @Override
public boolean performFinish() { public boolean performFinish() {
if (!createAndroidProject()) { if (!createAndroidProjects()) {
return false; return false;
} }
@@ -207,7 +274,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// -- Public Fields -- // -- Public Fields --
/** Returns the package name. Only valid once the wizard finishes. */ /** Returns the main project package name. Only valid once the wizard finishes. */
public String getPackageName() { public String getPackageName() {
return mPackageName; return mPackageName;
} }
@@ -234,33 +301,108 @@ public class NewProjectWizard extends Wizard implements INewWizard {
return true; return true;
} }
/**
* Structure that describes all the information needed to create a project.
* This is collected from the pages by {@link NewProjectWizard#createAndroidProjects()}
* and then used by
* {@link NewProjectWizard#createProjectAsync(IProgressMonitor, ProjectInfo, ProjectInfo)}.
*/
private static class ProjectInfo {
private final IProject mProject;
private final IProjectDescription mDescription;
private final Map<String, Object> mParameters;
private final HashMap<String, String> mDictionary;
public ProjectInfo(IProject project,
IProjectDescription description,
Map<String, Object> parameters,
HashMap<String, String> dictionary) {
mProject = project;
mDescription = description;
mParameters = parameters;
mDictionary = dictionary;
}
public IProject getProject() {
return mProject;
}
public IProjectDescription getDescription() {
return mDescription;
}
public Map<String, Object> getParameters() {
return mParameters;
}
public HashMap<String, String> getDictionary() {
return mDictionary;
}
}
/** /**
* Creates the android project. * Creates the android project.
* @return True if the project could be created. * @return True if the project could be created.
*/ */
private boolean createAndroidProject() { private boolean createAndroidProjects() {
final ProjectInfo mainData = collectMainPageInfo();
if (mMainPage != null && mainData == null) {
return false;
}
final ProjectInfo testData = collectTestPageInfo();
if (mTestPage != null && testData == null) {
return false;
}
// Create a monitored operation to create the actual project
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
createProjectAsync(monitor, mainData, testData);
}
};
// Run the operation in a different thread
runAsyncOperation(op);
return true;
}
/**
* Collects all the parameters needed to create the main project.
* @return A new {@link ProjectInfo} on success. Returns null if the project cannot be
* created because parameters are incorrect or should not be created because there
* is no main page.
*/
private ProjectInfo collectMainPageInfo() {
if (mMainPage == null) {
return null;
}
IMainInfo info = mMainPage.getMainInfo();
IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IProject project = workspace.getRoot().getProject(mMainPage.getProjectName()); final IProject project = workspace.getRoot().getProject(info.getProjectName());
final IProjectDescription description = workspace.newProjectDescription(project.getName()); final IProjectDescription description = workspace.newProjectDescription(project.getName());
// keep some variables to make them available once the wizard closes // keep some variables to make them available once the wizard closes
mPackageName = mMainPage.getPackageName(); mPackageName = info.getPackageName();
final Map<String, Object> parameters = new HashMap<String, Object>(); final Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(PARAM_PROJECT, mMainPage.getProjectName()); parameters.put(PARAM_PROJECT, info.getProjectName());
parameters.put(PARAM_PACKAGE, mPackageName); parameters.put(PARAM_PACKAGE, mPackageName);
parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME); parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME);
parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder()); parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder());
parameters.put(PARAM_IS_NEW_PROJECT, mMainPage.isNewProject()); parameters.put(PARAM_IS_NEW_PROJECT, info.isNewProject());
parameters.put(PARAM_SRC_FOLDER, mMainPage.getSourceFolder()); parameters.put(PARAM_SRC_FOLDER, info.getSourceFolder());
parameters.put(PARAM_SDK_TARGET, mMainPage.getSdkTarget()); parameters.put(PARAM_SDK_TARGET, info.getSdkTarget());
parameters.put(PARAM_MIN_SDK_VERSION, mMainPage.getMinSdkVersion()); parameters.put(PARAM_MIN_SDK_VERSION, info.getMinSdkVersion());
if (mMainPage.isCreateActivity()) { if (info.isCreateActivity()) {
// An activity name can be of the form ".package.Class" or ".Class". // An activity name can be of the form ".package.Class" or ".Class".
// The initial dot is ignored, as it is always added later in the templates. // The initial dot is ignored, as it is always added later in the templates.
String activityName = mMainPage.getActivityName(); String activityName = info.getActivityName();
if (activityName.startsWith(".")) { //$NON-NLS-1$ if (activityName.startsWith(".")) { //$NON-NLS-1$
activityName = activityName.substring(1); activityName = activityName.substring(1);
} }
@@ -269,31 +411,81 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// create a dictionary of string that will contain name+content. // create a dictionary of string that will contain name+content.
// we'll put all the strings into values/strings.xml // we'll put all the strings into values/strings.xml
final HashMap<String, String> stringDictionary = new HashMap<String, String>(); final HashMap<String, String> dictionary = new HashMap<String, String>();
stringDictionary.put(STRING_APP_NAME, mMainPage.getApplicationName()); dictionary.put(STRING_APP_NAME, info.getApplicationName());
IPath path = mMainPage.getLocationPath(); IPath path = info.getLocationPath();
IPath defaultLocation = Platform.getLocation(); IPath defaultLocation = Platform.getLocation();
if (!path.equals(defaultLocation)) { if (!path.equals(defaultLocation)) {
description.setLocation(path); description.setLocation(path);
} }
if (mMainPage.isNewProject() && !mMainPage.useDefaultLocation() && if (info.isNewProject() && !info.useDefaultLocation() &&
!validateNewProjectLocationIsEmpty(path)) { !validateNewProjectLocationIsEmpty(path)) {
return false; return null;
} }
// Create a monitored operation to create the actual project return new ProjectInfo(project, description, parameters, dictionary);
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
createProjectAsync(project, description, monitor, parameters, stringDictionary);
} }
};
// Run the operation in a different thread /**
runAsyncOperation(op); * Collects all the parameters needed to create the test project.
return true; *
* @return A new {@link ProjectInfo} on success. Returns null if the project cannot be
* created because parameters are incorrect or should not be created because there
* is no test page.
*/
private ProjectInfo collectTestPageInfo() {
if (mTestPage == null) {
return null;
}
TestInfo info = mTestPage.getTestInfo();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IProject project = workspace.getRoot().getProject(info.getProjectName());
final IProjectDescription description = workspace.newProjectDescription(project.getName());
final Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(PARAM_PROJECT, info.getProjectName());
parameters.put(PARAM_PACKAGE, info.getPackageName());
parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME);
parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder());
parameters.put(PARAM_IS_NEW_PROJECT, true);
parameters.put(PARAM_SRC_FOLDER, info.getSourceFolder());
parameters.put(PARAM_SDK_TARGET, info.getSdkTarget());
parameters.put(PARAM_MIN_SDK_VERSION, info.getMinSdkVersion());
// Test-specific parameters
parameters.put(PARAM_TEST_TARGET_PACKAGE, info.getTargetPackageName());
if (info.isTestingSelf()) {
parameters.put(PARAM_TARGET_SELF, true);
}
if (info.isTestingMain()) {
parameters.put(PARAM_TARGET_MAIN, true);
}
if (info.isTestingExisting()) {
parameters.put(PARAM_TARGET_EXISTING, true);
parameters.put(PARAM_REFERENCE_PROJECT, info.getExistingTestedProject());
}
// create a dictionary of string that will contain name+content.
// we'll put all the strings into values/strings.xml
final HashMap<String, String> dictionary = new HashMap<String, String>();
dictionary.put(STRING_APP_NAME, info.getApplicationName());
IPath path = info.getLocationPath();
IPath defaultLocation = Platform.getLocation();
if (!path.equals(defaultLocation)) {
description.setLocation(path);
}
if (!info.useDefaultLocation() && !validateNewProjectLocationIsEmpty(path)) {
return null;
}
return new ProjectInfo(project, description, parameters, dictionary);
} }
/** /**
@@ -328,27 +520,77 @@ public class NewProjectWizard extends Wizard implements INewWizard {
} }
/** /**
* Creates the actual project, sets its nature and adds the required folders * Creates the actual project(s). This is run asynchronously in a different thread.
* and files to it. This is run asynchronously in a different thread.
* *
* @param project The project to create.
* @param description A description of the project.
* @param monitor An existing monitor. * @param monitor An existing monitor.
* @param parameters Template parameters. * @param mainData Data for main project. Can be null.
* @param stringDictionary String definition.
* @throws InvocationTargetException to wrap any unmanaged exception and * @throws InvocationTargetException to wrap any unmanaged exception and
* return it to the calling thread. The method can fail if it fails * return it to the calling thread. The method can fail if it fails
* to create or modify the project or if it is canceled by the user. * to create or modify the project or if it is canceled by the user.
*/ */
private void createProjectAsync(IProject project, IProjectDescription description, private void createProjectAsync(IProgressMonitor monitor,
IProgressMonitor monitor, Map<String, Object> parameters, ProjectInfo mainData,
Map<String, String> stringDictionary) ProjectInfo testData)
throws InvocationTargetException { throws InvocationTargetException {
monitor.beginTask("Create Android Project", 100); monitor.beginTask("Create Android Project", 100);
try { try {
IProject mainProject = null;
if (mainData != null) {
mainProject = createEclipseProject(
new SubProgressMonitor(monitor, 50),
mainData.getProject(),
mainData.getDescription(),
mainData.getParameters(),
mainData.getDictionary());
}
if (testData != null) {
Map<String, Object> parameters = testData.getParameters();
if (parameters.containsKey(PARAM_TARGET_MAIN) && mainProject != null) {
parameters.put(PARAM_REFERENCE_PROJECT, mainProject);
}
createEclipseProject(
new SubProgressMonitor(monitor, 50),
testData.getProject(),
testData.getDescription(),
parameters,
testData.getDictionary());
}
} catch (CoreException e) {
throw new InvocationTargetException(e);
} catch (IOException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
/**
* Creates the actual project, sets its nature and adds the required folders
* and files to it. This is run asynchronously in a different thread.
*
* @param monitor An existing monitor.
* @param project The project to create.
* @param description A description of the project.
* @param parameters Template parameters.
* @param dictionary String definition.
* @return The project newly created
*/
private IProject createEclipseProject(IProgressMonitor monitor,
IProject project,
IProjectDescription description,
Map<String, Object> parameters,
Map<String, String> dictionary)
throws CoreException, IOException {
// Create project and open it // Create project and open it
project.create(description, new SubProgressMonitor(monitor, 10)); project.create(description, new SubProgressMonitor(monitor, 10));
if (monitor.isCanceled()) throw new OperationCanceledException(); if (monitor.isCanceled()) throw new OperationCanceledException();
project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10)); project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10));
// Add the Java and android nature to the project // Add the Java and android nature to the project
@@ -379,17 +621,17 @@ public class NewProjectWizard extends Wizard implements INewWizard {
if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) { if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) {
// Create files in the project if they don't already exist // Create files in the project if they don't already exist
addManifest(project, parameters, stringDictionary, monitor); addManifest(project, parameters, dictionary, monitor);
// add the default app icon // add the default app icon
addIcon(project, monitor); addIcon(project, monitor);
// Create the default package components // Create the default package components
addSampleCode(project, sourceFolders[0], parameters, stringDictionary, monitor); addSampleCode(project, sourceFolders[0], parameters, dictionary, monitor);
// add the string definition file if needed // add the string definition file if needed
if (stringDictionary.size() > 0) { if (dictionary.size() > 0) {
addStringDictionaryFile(project, stringDictionary, monitor); addStringDictionaryFile(project, dictionary, monitor);
} }
// Set output location // Set output location
@@ -397,6 +639,31 @@ public class NewProjectWizard extends Wizard implements INewWizard {
monitor); monitor);
} }
// Create the reference to the target project
if (parameters.containsKey(PARAM_REFERENCE_PROJECT)) {
IProject refProject = (IProject) parameters.get(PARAM_REFERENCE_PROJECT);
if (refProject != null) {
IProjectDescription desc = project.getDescription();
// Add out reference to the existing project reference.
// We just created a project with no references so we don't need to expand
// the currently-empty current list.
desc.setReferencedProjects(new IProject[] { refProject });
project.setDescription(desc, IResource.KEEP_HISTORY, new SubProgressMonitor(monitor, 10));
IClasspathEntry entry = JavaCore.newProjectEntry(
refProject.getFullPath(), //path
new IAccessRule[0], //accessRules
false, //combineAccessRules
new IClasspathAttribute[0], //extraAttributes
false //isExported
);
ProjectHelper.addEntryToClasspath(javaProject, entry);
}
}
Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET), Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET),
null /* apkConfigMap*/); null /* apkConfigMap*/);
@@ -404,13 +671,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// Necessary for existing projects and good for new ones to. // Necessary for existing projects and good for new ones to.
ProjectHelper.fixProject(project); ProjectHelper.fixProject(project);
} catch (CoreException e) { return project;
throw new InvocationTargetException(e);
} catch (IOException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
} }
/** /**
@@ -442,7 +703,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* *
* @param project The Java Project to update. * @param project The Java Project to update.
* @param parameters Template Parameters. * @param parameters Template Parameters.
* @param stringDictionary String List to be added to a string definition * @param dictionary String List to be added to a string definition
* file. This map will be filled by this method. * file. This map will be filled by this method.
* @param monitor An existing monitor. * @param monitor An existing monitor.
* @throws CoreException if the method fails to update the project. * @throws CoreException if the method fails to update the project.
@@ -450,7 +711,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* project. * project.
*/ */
private void addManifest(IProject project, Map<String, Object> parameters, private void addManifest(IProject project, Map<String, Object> parameters,
Map<String, String> stringDictionary, IProgressMonitor monitor) Map<String, String> dictionary, IProgressMonitor monitor)
throws CoreException, IOException { throws CoreException, IOException {
// get IFile to the manifest and check if it's not already there. // get IFile to the manifest and check if it's not already there.
@@ -480,7 +741,26 @@ public class NewProjectWizard extends Wizard implements INewWizard {
manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities); manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities);
} else { } else {
// remove the activity(ies) from the manifest // remove the activity(ies) from the manifest
manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, ""); manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, ""); //$NON-NLS-1$
}
// Handle the case of the test projects
if (parameters.containsKey(PARAM_TEST_TARGET_PACKAGE)) {
// Set the uses-library needed by the test project
String usesLibrary = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_USES_LIBRARY);
manifestTemplate = manifestTemplate.replaceAll(PH_TEST_USES_LIBRARY, usesLibrary);
// Set the instrumentation element needed by the test project
String instru = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_INSTRUMENTATION);
manifestTemplate = manifestTemplate.replaceAll(PH_TEST_INSTRUMENTATION, instru);
// Replace PARAM_TEST_TARGET_PACKAGE itself now
manifestTemplate = replaceParameters(manifestTemplate, parameters);
} else {
// remove the unused entries
manifestTemplate = manifestTemplate.replaceAll(PH_TEST_USES_LIBRARY, ""); //$NON-NLS-1$
manifestTemplate = manifestTemplate.replaceAll(PH_TEST_INSTRUMENTATION, ""); //$NON-NLS-1$
} }
String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION); String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION);
@@ -584,7 +864,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* *
* @param project The Java Project to update. * @param project The Java Project to update.
* @param parameters Template Parameters. * @param parameters Template Parameters.
* @param stringDictionary String List to be added to a string definition * @param dictionary String List to be added to a string definition
* file. This map will be filled by this method. * file. This map will be filled by this method.
* @param monitor An existing monitor. * @param monitor An existing monitor.
* @throws CoreException if the method fails to update the project. * @throws CoreException if the method fails to update the project.
@@ -592,7 +872,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* project. * project.
*/ */
private void addSampleCode(IProject project, String sourceFolder, private void addSampleCode(IProject project, String sourceFolder,
Map<String, Object> parameters, Map<String, String> stringDictionary, Map<String, Object> parameters, Map<String, String> dictionary,
IProgressMonitor monitor) throws CoreException, IOException { IProgressMonitor monitor) throws CoreException, IOException {
// create the java package directories. // create the java package directories.
IFolder pkgFolder = project.getFolder(sourceFolder); IFolder pkgFolder = project.getFolder(sourceFolder);
@@ -643,9 +923,9 @@ public class NewProjectWizard extends Wizard implements INewWizard {
if (!file.exists()) { if (!file.exists()) {
copyFile(LAYOUT_TEMPLATE, file, parameters, monitor); copyFile(LAYOUT_TEMPLATE, file, parameters, monitor);
if (activityName != null) { if (activityName != null) {
stringDictionary.put(STRING_HELLO_WORLD, "Hello World, " + activityName + "!"); dictionary.put(STRING_HELLO_WORLD, "Hello World, " + activityName + "!");
} else { } else {
stringDictionary.put(STRING_HELLO_WORLD, "Hello World!"); dictionary.put(STRING_HELLO_WORLD, "Hello World!");
} }
} }
} }

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2009 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.wizards.newproject;
/**
* A "New Test Android Project" Wizard.
* <p/>
* This is really the {@link NewProjectWizard} that only displays the "test project" page.
*/
public class NewTestProjectWizard extends NewProjectWizard {
public NewTestProjectWizard() {
super(AvailablePages.TEST_PROJECT_ONLY);
}
}

View File

@@ -5,6 +5,8 @@
android:versionName="1.0"> android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="APPLICATION_NAME"> <application android:icon="@drawable/icon" android:label="APPLICATION_NAME">
ACTIVITIES ACTIVITIES
TEST-USES-LIBRARY
</application> </application>
USES-SDK USES-SDK
TEST-INSTRUMENTATION
</manifest> </manifest>

View File

@@ -0,0 +1 @@
<instrumentation android:targetPackage="TEST_TARGET_PCKG" android:name="android.test.InstrumentationTestRunner" />

View File

@@ -0,0 +1 @@
<uses-library android:name="android.test.runner" />

View File

@@ -15,6 +15,11 @@
*/ */
package com.android.ide.eclipse.adt.wizards.newproject; package com.android.ide.eclipse.adt.wizards.newproject;
import com.android.sdklib.IAndroidTarget;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import java.io.File; import java.io.File;
/** /**
@@ -26,46 +31,60 @@ public class StubSampleProjectCreationPage extends NewProjectCreationPage {
private String mSampleProjectName; private String mSampleProjectName;
private String mOsSdkLocation; private String mOsSdkLocation;
public StubSampleProjectCreationPage(String pageName, public StubSampleProjectCreationPage(String sampleProjectName, String osSdkLocation) {
String sampleProjectName, String osSdkLocation) { super();
super(pageName);
this.mSampleProjectName = sampleProjectName; this.mSampleProjectName = sampleProjectName;
this.mOsSdkLocation = osSdkLocation; this.mOsSdkLocation = osSdkLocation;
} }
@Override @Override
public IMainInfo getMainInfo() {
return new IMainInfo() {
public String getProjectName() { public String getProjectName() {
return mSampleProjectName; return mSampleProjectName;
} }
@Override
public String getPackageName() { public String getPackageName() {
return "com.android.samples"; return "com.android.samples";
} }
@Override
public String getActivityName() { public String getActivityName() {
return mSampleProjectName; return mSampleProjectName;
} }
@Override
public String getApplicationName() { public String getApplicationName() {
return mSampleProjectName; return mSampleProjectName;
} }
@Override
public boolean isNewProject() { public boolean isNewProject() {
return false; return false;
} }
@Override
public String getProjectLocation() {
return mOsSdkLocation + File.separator + "samples" + File.separator + mSampleProjectName;
}
@Override
public String getSourceFolder() { public String getSourceFolder() {
return "src"; return "src";
} }
public IPath getLocationPath() {
return new Path(mOsSdkLocation + File.separator +
"samples" + File.separator +
mSampleProjectName);
}
public String getMinSdkVersion() {
return null;
}
public IAndroidTarget getSdkTarget() {
return null;
}
public boolean isCreateActivity() {
return false;
}
public boolean useDefaultLocation() {
return false;
}
};
}
} }

View File

@@ -49,8 +49,7 @@ public class StubSampleProjectWizard extends NewProjectWizard {
*/ */
@Override @Override
protected NewProjectCreationPage createMainPage() { protected NewProjectCreationPage createMainPage() {
return new StubSampleProjectCreationPage(MAIN_PAGE_NAME, return new StubSampleProjectCreationPage(mSampleProjectName, mOsSdkLocation);
mSampleProjectName, mOsSdkLocation);
} }
/** /**

View File

@@ -67,8 +67,6 @@ public class EclipseTestCollector {
/** /**
* Returns true if given class should be added to suite * Returns true if given class should be added to suite
* @param testClass
* @return
*/ */
protected boolean isTestClass(Class<?> testClass) { protected boolean isTestClass(Class<?> testClass) {
return TestCase.class.isAssignableFrom(testClass) && return TestCase.class.isAssignableFrom(testClass) &&
@@ -78,8 +76,6 @@ public class EclipseTestCollector {
/** /**
* Returns true if given class has a public constructor * Returns true if given class has a public constructor
* @param testClass
* @return
*/ */
protected boolean hasPublicConstructor(Class<?> testClass) { protected boolean hasPublicConstructor(Class<?> testClass) {
try { try {
@@ -94,7 +90,6 @@ public class EclipseTestCollector {
* Load the class given by the plugin aka bundle file path * Load the class given by the plugin aka bundle file path
* @param filePath - path of class in bundle * @param filePath - path of class in bundle
* @param expectedPackage - expected package of class * @param expectedPackage - expected package of class
* @return
* @throws ClassNotFoundException * @throws ClassNotFoundException
*/ */
protected Class<?> getClass(String filePath, String expectedPackage) throws ClassNotFoundException { protected Class<?> getClass(String filePath, String expectedPackage) throws ClassNotFoundException {

View File

@@ -28,6 +28,7 @@ import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Listener;
@@ -397,4 +398,21 @@ public class SdkTargetSelector {
} }
} }
} }
/** Enables or disables the controls. */
public void setEnabled(boolean enabled) {
if (mInnerGroup != null && mTable != null && !mTable.isDisposed()) {
enableControl(mInnerGroup, enabled);
}
}
/** Enables or disables controls; recursive for composite controls. */
private void enableControl(Control c, boolean enabled) {
c.setEnabled(enabled);
if (c instanceof Composite)
for (Control c2 : ((Composite) c).getChildren()) {
enableControl(c2, enabled);
}
}
} }