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
Thumbs.db

View File

@@ -1,3 +1,7 @@
0.9.2:
- New wizard to create Android JUnit Test Projects.
0.9.1:
- 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.

View File

@@ -90,7 +90,7 @@
class="com.android.ide.eclipse.adt.wizards.newproject.NewProjectWizard"
finalPerspective="org.eclipse.jdt.ui.JavaPerspective"
hasPages="true"
icon="icons/android.png"
icon="icons/new_adt_project.png"
id="com.android.ide.eclipse.adt.project.NewProjectWizard"
name="Android Project"
preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective"
@@ -98,10 +98,22 @@
<wizard
canFinishEarly="false"
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"
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"
name="Android XML File"
preferredPerspectives="org.eclipse.jdt.ui.JavaPerspective"
@@ -220,11 +232,22 @@
value="com.android.ide.eclipse.adt.AndroidNature">
</filter>
<action
class="com.android.ide.eclipse.adt.project.NewXmlFileWizardAction"
class="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
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..."
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
class="com.android.ide.eclipse.adt.project.ExportAction"
@@ -483,6 +506,15 @@
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android XML file">
</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
class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
icon="icons/new_adt_project.png"

View File

@@ -70,6 +70,22 @@ public final class ProjectHelper {
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.
* @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
ProjectHelper.checkAndFixCompilerCompliance(javaProject);
}
/**
* Checks the project compiler compliance level is supported.
* @param javaProject The project to check

View File

@@ -200,7 +200,8 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage
label.setText("Configuration:");
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.heightHint = ConfigurationSelector.HEIGHT_HINT;
mConfigSelector.setLayoutData(gd);

View File

@@ -4,7 +4,7 @@
* 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
@@ -23,7 +23,9 @@ import org.eclipse.ui.IWorkbenchWizard;
/**
* 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 {

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;
/**
* 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.
*/
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

@@ -4,7 +4,7 @@
* 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
@@ -28,6 +28,7 @@ import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart;
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.
* 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}
@@ -60,6 +62,9 @@ import org.eclipse.ui.internal.util.Util;
/** The result from the dialog */
private int mDialogResult;
private ISelection mSelection;
private IWorkbench mWorkbench;
/** Returns the wizard that was created by {@link #run(IAction)}. */
public IWorkbenchWizard getWizard() {
return mWizard;
@@ -70,7 +75,7 @@ import org.eclipse.ui.internal.util.Util;
public int getDialogResult() {
return mDialogResult;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
*/
@@ -89,19 +94,23 @@ import org.eclipse.ui.internal.util.Util;
* Opens and display the Android New Project Wizard.
* <p/>
* Most of this implementation is extracted from {@link NewWizardShortcutAction#run()}.
*
*
* @param action The action that got us here. Can be null when used internally.
* @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
*/
public void run(IAction action) {
// get the workbench and the current window
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbench workbench = mWorkbench != null ? mWorkbench : PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
// This code from NewWizardShortcutAction#run() gets the current window selection
// 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;
if (selection instanceof IStructuredSelection) {
selectionToPass = (IStructuredSelection) selection;
@@ -123,16 +132,16 @@ import org.eclipse.ui.internal.util.Util;
// Create the wizard and initialize it with the selection
mWizard = instanciateWizard(action);
mWizard.init(workbench, selectionToPass);
// It's not visible yet until a dialog is created and opened
Shell parent = window.getShell();
WizardDialogEx dialog = new WizardDialogEx(parent, mWizard);
dialog.create();
if (mWizard instanceof IUpdateWizardDialog) {
((IUpdateWizardDialog) mWizard).updateWizardDialog(dialog);
}
// This code comes straight from NewWizardShortcutAction#run()
Point defaultSize = dialog.getShell().getSize();
dialog.getShell().setSize(
@@ -140,13 +149,13 @@ import org.eclipse.ui.internal.util.Util;
Math.max(SIZING_WIZARD_HEIGHT, defaultSize.y));
window.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
IWorkbenchHelpContextIds.NEW_WIZARD_SHORTCUT);
mDialogResult = dialog.open();
}
/**
* Called by {@link #run(IAction)} to instantiate the actual wizard.
*
*
* @param action The action parameter from {@link #run(IAction)}.
* This can be null.
* @return A new wizard instance. Must not be null.
@@ -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)
*/
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.sdk.Sdk;
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.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity;
@@ -79,11 +80,13 @@ import java.util.regex.Pattern;
* Note: this class is public so that it can be accessed from unit tests.
* It is however an internal class. Its API may change without notice.
* It should semantically be considered as a private final class.
* Do not derive from this class.
* Do not derive from this class.
*/
public class NewProjectCreationPage extends WizardPage {
// constants
private static final String MAIN_PAGE_NAME = "newAndroidProjectPage"; //$NON-NLS-1$
/** Initial value for all name fields (project, activity, application, package). Used
* whenever a value is requested before controls are created. */
private static final String INITIAL_NAME = ""; //$NON-NLS-1$
@@ -94,7 +97,7 @@ public class NewProjectCreationPage extends WizardPage {
private static final boolean INITIAL_USE_DEFAULT_LOCATION = true;
/** Initial value for the Create Activity check box. */
private static final boolean INITIAL_CREATE_ACTIVITY = true;
/** Pattern for characters accepted in a project name. Since this will be used as a
* directory name, we're being a bit conservative on purpose. It cannot start with a space. */
@@ -106,7 +109,13 @@ public class NewProjectCreationPage extends WizardPage {
private final int MSG_NONE = 0;
private final int MSG_WARNING = 1;
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 mUserActivityName = ""; //$NON-NLS-1$
private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY;
@@ -128,98 +137,160 @@ public class NewProjectCreationPage extends WizardPage {
private ITargetChangeListener mSdkTargetChangeListener;
private boolean mInternalLocationPathUpdate;
protected boolean mInternalProjectNameUpdate;
protected boolean mInternalApplicationNameUpdate;
private boolean mInternalProjectNameUpdate;
private boolean mInternalApplicationNameUpdate;
private boolean mInternalCreateActivityUpdate;
private boolean mInternalActivityNameUpdate;
protected boolean mProjectNameModifiedByUser;
protected boolean mApplicationNameModifiedByUser;
private boolean mProjectNameModifiedByUser;
private boolean mApplicationNameModifiedByUser;
private boolean mInternalMinSdkVersionUpdate;
private boolean mMinSdkVersionModifiedByUser;
/**
* Creates a new project creation wizard page.
*
* @param pageName the name of this page
*/
public NewProjectCreationPage(String pageName) {
super(pageName);
public NewProjectCreationPage() {
super(MAIN_PAGE_NAME);
setPageComplete(false);
setTitle("New Android Project");
setDescription("Creates a new Android Project resource.");
}
// --- Getters used by NewProjectWizard ---
/**
* 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.
* 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 IPath getLocationPath() {
return new Path(getProjectLocation());
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();
}
/** Returns the value of the project name field with leading and trailing spaces removed. */
public String getProjectName() {
return mProjectNameField == null ? INITIAL_NAME : mProjectNameField.getText().trim();
}
/** Returns the value of the package name field with spaces trimmed. */
public String getPackageName() {
return mPackageNameField == null ? INITIAL_NAME : mPackageNameField.getText().trim();
}
/**
* 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
* 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.
*/
public IPath getLocationPath() {
return new Path(getProjectLocation());
}
/** Returns the value of the activity name field with spaces trimmed. */
public String getActivityName() {
return mActivityNameField == null ? INITIAL_NAME : mActivityNameField.getText().trim();
}
/** Returns the value of the project name field with leading and trailing spaces removed. */
public String getProjectName() {
return mProjectNameField == null ? INITIAL_NAME : mProjectNameField.getText().trim();
}
/** Returns the value of the min sdk version field with spaces trimmed. */
public String getMinSdkVersion() {
return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim();
}
/** Returns the value of the package name field with spaces trimmed. */
public String getPackageName() {
return mPackageNameField == null ? INITIAL_NAME : mPackageNameField.getText().trim();
}
/** Returns the value of the application name field with spaces trimmed. */
public String getApplicationName() {
// Return the name of the activity as default application name.
return mApplicationNameField == null ? getActivityName()
: mApplicationNameField.getText().trim();
/** Returns the value of the activity name field with spaces trimmed. */
public String getActivityName() {
return mActivityNameField == null ? INITIAL_NAME : mActivityNameField.getText().trim();
}
}
/** Returns the value of the min sdk version field with spaces trimmed. */
public String getMinSdkVersion() {
return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim(); //$NON-NLS-1$
}
/** Returns the value of the "Create New Project" radio. */
public boolean isNewProject() {
return mCreateNewProjectRadio == null ? INITIAL_CREATE_NEW_PROJECT
: mCreateNewProjectRadio.getSelection();
}
/** Returns the value of the application name field with spaces trimmed. */
public String getApplicationName() {
// Return the name of the activity as default application name.
return mApplicationNameField == null ? getActivityName()
: mApplicationNameField.getText().trim();
/** Returns the value of the "Create Activity" checkbox. */
public boolean isCreateActivity() {
return mCreateActivityCheck == null ? INITIAL_CREATE_ACTIVITY
: mCreateActivityCheck.getSelection();
}
}
/** Returns the value of the Use Default Location field. */
public boolean useDefaultLocation() {
return mUseDefaultLocation == null ? INITIAL_USE_DEFAULT_LOCATION
: mUseDefaultLocation.getSelection();
}
/** Returns the value of the "Create New Project" radio. */
public boolean isNewProject() {
return mCreateNewProjectRadio == null ? INITIAL_CREATE_NEW_PROJECT
: mCreateNewProjectRadio.getSelection();
}
/** Returns the internal source folder (for the "existing project" mode) or the default
* "src" constant. */
public String getSourceFolder() {
if (isNewProject() || mSourceFolder == null || mSourceFolder.length() == 0) {
return SdkConstants.FD_SOURCES;
} else {
return mSourceFolder;
/** Returns the value of the "Create Activity" checkbox. */
public boolean isCreateActivity() {
return mCreateActivityCheck == null ? INITIAL_CREATE_ACTIVITY
: mCreateActivityCheck.getSelection();
}
/** Returns the value of the Use Default Location field. */
public boolean useDefaultLocation() {
return mUseDefaultLocation == null ? INITIAL_USE_DEFAULT_LOCATION
: mUseDefaultLocation.getSelection();
}
/** Returns the internal source folder (for the "existing project" mode) or the default
* "src" constant. */
public String getSourceFolder() {
if (isNewProject() || mSourceFolder == null || mSourceFolder.length() == 0) {
return SdkConstants.FD_SOURCES;
} else {
return mSourceFolder;
}
}
/** Returns the current sdk target or null if none has been selected yet. */
public IAndroidTarget getSdkTarget() {
return mSdkTargetSelector == null ? null : mSdkTargetSelector.getSelected();
}
}
/** Returns the current sdk target or null if none has been selected yet. */
public IAndroidTarget getSdkTarget() {
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;
}
/**
@@ -231,6 +302,7 @@ public class NewProjectCreationPage extends WizardPage {
super.setVisible(visible);
if (visible) {
mProjectNameField.setFocus();
validatePageComplete();
}
}
@@ -265,17 +337,17 @@ public class NewProjectCreationPage extends WizardPage {
setControl(composite);
// Validate. This will complain about the first empty field.
setPageComplete(validatePage());
validatePageComplete();
}
@Override
public void dispose() {
if (mSdkTargetChangeListener != null) {
AdtPlugin.getDefault().removeTargetListener(mSdkTargetChangeListener);
mSdkTargetChangeListener = null;
}
super.dispose();
}
@@ -328,7 +400,7 @@ public class NewProjectCreationPage extends WizardPage {
Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
// Layout has 4 columns of non-equal size
group.setLayout(new GridLayout());
group.setLayoutData(new GridData(GridData.FILL_BOTH));
group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
group.setFont(parent.getFont());
group.setText("Contents");
@@ -349,7 +421,7 @@ public class NewProjectCreationPage extends WizardPage {
super.widgetSelected(e);
enableLocationWidgets();
extractNamesFromAndroidManifest();
setPageComplete(validatePage());
validatePageComplete();
}
};
@@ -358,9 +430,9 @@ public class NewProjectCreationPage extends WizardPage {
mUseDefaultLocation.addSelectionListener(location_listener);
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 */));
location_group.setLayoutData(new GridData(GridData.FILL_BOTH));
location_group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
location_group.setFont(parent.getFont());
mLocationLabel = new Label(location_group, SWT.NONE);
@@ -371,7 +443,7 @@ public class NewProjectCreationPage extends WizardPage {
GridData.BEGINNING, /* vertical alignment */
true, /* grabExcessHorizontalSpace */
false, /* grabExcessVerticalSpace */
2, /* horizontalSpan */
1, /* horizontalSpan */
1); /* verticalSpan */
mLocationPathField.setLayoutData(data);
mLocationPathField.setFont(parent.getFont());
@@ -387,7 +459,7 @@ public class NewProjectCreationPage extends WizardPage {
mBrowseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openDirectoryBrowser();
onOpenDirectoryBrowser();
}
});
}
@@ -403,7 +475,7 @@ public class NewProjectCreationPage extends WizardPage {
group.setLayoutData(new GridData(GridData.FILL_BOTH));
group.setFont(parent.getFont());
group.setText("Build Target");
// The selector is created without targets. They are added below in the change listener.
mSdkTargetSelector = new SdkTargetSelector(group, null);
@@ -428,51 +500,22 @@ public class NewProjectCreationPage extends WizardPage {
}
}
};
AdtPlugin.getDefault().addTargetListener(mSdkTargetChangeListener);
// Invoke it once to initialize the targets
mSdkTargetChangeListener.onTargetsLoaded();
mSdkTargetSelector.setSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
onSdkTargetModified();
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:
* - Package name [text field]
@@ -508,7 +551,7 @@ public class NewProjectCreationPage extends WizardPage {
if (!mInternalApplicationNameUpdate) {
mApplicationNameModifiedByUser = true;
}
}
}
});
// new package label
@@ -569,7 +612,7 @@ public class NewProjectCreationPage extends WizardPage {
mMinSdkVersionField.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event event) {
onMinSdkVersionFieldModified();
setPageComplete(validatePage());
validatePageComplete();
}
});
}
@@ -579,12 +622,12 @@ public class NewProjectCreationPage extends WizardPage {
/** Returns the location path field value with spaces trimmed. */
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. */
public String getProjectLocation() {
if (isNewProject() && useDefaultLocation()) {
private String getProjectLocation() {
if (mInfo.isNewProject() && mInfo.useDefaultLocation()) {
return Platform.getLocation().toString();
} else {
return getLocationPathFieldValue();
@@ -603,22 +646,51 @@ public class NewProjectCreationPage extends WizardPage {
* @return the new project resource handle
*/
private IProject getProjectHandle() {
return ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName());
return ResourcesPlugin.getWorkspace().getRoot().getProject(mInfo.getProjectName());
}
// --- 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:
* 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.
*/
private void enableLocationWidgets() {
boolean is_new_project = isNewProject();
boolean use_default = useDefaultLocation();
boolean is_new_project = mInfo.isNewProject();
boolean use_default = mInfo.useDefaultLocation();
boolean location_enabled = !is_new_project || !use_default;
boolean create_activity = isCreateActivity();
boolean create_activity = mInfo.isCreateActivity();
mUseDefaultLocation.setEnabled(is_new_project);
mLocationLabel.setEnabled(location_enabled);
@@ -646,8 +718,8 @@ public class NewProjectCreationPage extends WizardPage {
* @param abs_dir A new absolute directory path or null to use the default.
*/
private void updateLocationPathField(String abs_dir) {
boolean is_new_project = isNewProject();
boolean use_default = useDefaultLocation();
boolean is_new_project = mInfo.isNewProject();
boolean use_default = mInfo.useDefaultLocation();
boolean custom_location = !is_new_project || !use_default;
if (!mInternalLocationPathUpdate) {
@@ -663,7 +735,7 @@ public class NewProjectCreationPage extends WizardPage {
} else if (sAutoComputeCustomLocation ||
(!is_new_project && !new File(sCustomLocationOsPath).isDirectory())) {
// By default select the samples directory of the current target
IAndroidTarget target = getSdkTarget();
IAndroidTarget target = mInfo.getSdkTarget();
if (target != null) {
sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES);
}
@@ -682,13 +754,13 @@ public class NewProjectCreationPage extends WizardPage {
mLocationPathField.setText(sCustomLocationOsPath);
}
} else {
String value = Platform.getLocation().append(getProjectName()).toString();
String value = Platform.getLocation().append(mInfo.getProjectName()).toString();
value = TextProcessor.process(value);
if (!mLocationPathField.getText().equals(value)) {
mLocationPathField.setText(value);
}
}
setPageComplete(validatePage());
validatePageComplete();
mInternalLocationPathUpdate = false;
}
}
@@ -711,7 +783,7 @@ public class NewProjectCreationPage extends WizardPage {
newPath.equals(sCustomLocationOsPath);
sCustomLocationOsPath = newPath;
extractNamesFromAndroidManifest();
setPageComplete(validatePage());
validatePageComplete();
}
}
@@ -723,9 +795,9 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page.
*/
private void onPackageNameFieldModified() {
if (isNewProject()) {
mUserPackageName = getPackageName();
setPageComplete(validatePage());
if (mInfo.isNewProject()) {
mUserPackageName = mInfo.getPackageName();
validatePageComplete();
}
}
@@ -737,10 +809,10 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page.
*/
private void onCreateActivityCheckModified() {
if (isNewProject() && !mInternalCreateActivityUpdate) {
mUserCreateActivityCheck = isCreateActivity();
if (mInfo.isNewProject() && !mInternalCreateActivityUpdate) {
mUserCreateActivityCheck = mInfo.isCreateActivity();
}
setPageComplete(validatePage());
validatePageComplete();
}
/**
@@ -751,15 +823,15 @@ public class NewProjectCreationPage extends WizardPage {
* validate the page.
*/
private void onActivityNameFieldModified() {
if (isNewProject() && !mInternalActivityNameUpdate) {
mUserActivityName = getActivityName();
setPageComplete(validatePage());
if (mInfo.isNewProject() && !mInternalActivityNameUpdate) {
mUserActivityName = mInfo.getActivityName();
validatePageComplete();
}
}
/**
* Called when the min sdk version field has been modified.
*
*
* Ignore the internal modifications. When modified by the user, try to match
* a target with the same API level.
*/
@@ -769,16 +841,16 @@ public class NewProjectCreationPage extends WizardPage {
}
try {
int version = Integer.parseInt(getMinSdkVersion());
int version = Integer.parseInt(mInfo.getMinSdkVersion());
// 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
// 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) {
return;
}
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (target.getApiVersionNumber() == version) {
mSdkTargetSelector.setSelection(target);
@@ -788,20 +860,18 @@ public class NewProjectCreationPage extends WizardPage {
} catch (NumberFormatException e) {
// ignore
}
mMinSdkVersionModifiedByUser = true;
}
/**
* Called when an SDK target is modified.
*
* If the minSdkVersion field hasn't been modified by the user yet, we change it
* to reflect the sdk api level that has just been selected.
*
* Also changes the minSdkVersion field to reflect the sdk api level that has
* just been selected.
*/
private void onSdkTargetModified() {
IAndroidTarget target = getSdkTarget();
if (target != null && !mMinSdkVersionModifiedByUser) {
IAndroidTarget target = mInfo.getSdkTarget();
if (target != null) {
mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
mInternalMinSdkVersionUpdate = false;
@@ -814,7 +884,7 @@ public class NewProjectCreationPage extends WizardPage {
* entered before.
*/
private void updatePackageAndActivityFields() {
if (isNewProject()) {
if (mInfo.isNewProject()) {
if (mUserPackageName.length() > 0 &&
!mPackageNameField.getText().equals(mUserPackageName)) {
mPackageNameField.setText(mUserPackageName);
@@ -826,7 +896,7 @@ public class NewProjectCreationPage extends WizardPage {
mActivityNameField.setText(mUserActivityName);
mInternalActivityNameUpdate = false;
}
if (mUserCreateActivityCheck != mCreateActivityCheck.getSelection()) {
mInternalCreateActivityUpdate = true;
mCreateActivityCheck.setSelection(mUserCreateActivityCheck);
@@ -841,7 +911,7 @@ public class NewProjectCreationPage extends WizardPage {
* can actually be found in the custom user directory.
*/
private void extractNamesFromAndroidManifest() {
if (isNewProject()) {
if (mInfo.isNewProject()) {
return;
}
@@ -853,12 +923,12 @@ public class NewProjectCreationPage extends WizardPage {
Path path = new Path(f.getPath());
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath);
if (manifestData == null) {
return;
}
String packageName = null;
Activity activity = null;
String activityName = null;
@@ -882,7 +952,7 @@ public class NewProjectCreationPage extends WizardPage {
if (packageName != null && packageName.length() > 0) {
mPackageNameField.setText(packageName);
}
if (activity != null) {
activityName = AndroidManifestParser.extractActivityName(activity.getName(),
packageName);
@@ -922,7 +992,7 @@ public class NewProjectCreationPage extends WizardPage {
mCreateActivityCheck.setSelection(false);
mInternalCreateActivityUpdate = false;
mInternalActivityNameUpdate = false;
// There is no activity name to use to fill in the project and application
// name. However if there's a package name, we can use this as a base.
if (packageName != null && packageName.length() > 0) {
@@ -944,13 +1014,13 @@ public class NewProjectCreationPage extends WizardPage {
mProjectNameField.setText(packageName);
mInternalProjectNameUpdate = false;
}
}
}
// Select the target matching the manifest's sdk or build properties, if any
boolean foundTarget = false;
ProjectProperties p = ProjectProperties.create(projectLocation, null);
if (p != null) {
// Check the {build|default}.properties files if present
@@ -976,7 +1046,7 @@ public class NewProjectCreationPage extends WizardPage {
// ignore
}
}
if (!foundTarget) {
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (projectLocation.startsWith(target.getLocation())) {
@@ -990,8 +1060,8 @@ public class NewProjectCreationPage extends WizardPage {
if (!foundTarget) {
mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText(
minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" :
Integer.toString(minSdkVersion)); //$NON-NLS-1$
minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" //$NON-NLS-1$
: Integer.toString(minSdkVersion));
mInternalMinSdkVersionUpdate = false;
}
}
@@ -1002,7 +1072,7 @@ public class NewProjectCreationPage extends WizardPage {
* @return <code>true</code> if all controls are valid, and
* <code>false</code> if at least one is invalid
*/
protected boolean validatePage() {
private boolean validatePage() {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
int status = validateProjectField(workspace);
@@ -1027,11 +1097,18 @@ public class NewProjectCreationPage extends WizardPage {
if (status == MSG_NONE) {
setStatus(null, MSG_NONE);
}
// Return false if there's an error so that the finish button be disabled.
return (status & MSG_ERROR) == 0;
}
/**
* Validates the page and updates the Next/Finish buttons
*/
private void validatePageComplete() {
setPageComplete(validatePage());
}
/**
* Validates the project name field.
*
@@ -1039,19 +1116,19 @@ public class NewProjectCreationPage extends WizardPage {
*/
private int validateProjectField(IWorkspace workspace) {
// Validate project field
String projectFieldContents = getProjectName();
if (projectFieldContents.length() == 0) {
String projectName = mInfo.getProjectName();
if (projectName.length() == 0) {
return setStatus("Project name must be specified", MSG_ERROR);
}
// Limit the project name to shell-agnostic characters since it will be used to
// 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.",
MSG_ERROR);
}
IStatus nameStatus = workspace.validateName(projectFieldContents, IResource.PROJECT);
IStatus nameStatus = workspace.validateName(projectName, IResource.PROJECT);
if (!nameStatus.isOK()) {
return setStatus(nameStatus.getMessage(), MSG_ERROR);
}
@@ -1061,6 +1138,13 @@ public class NewProjectCreationPage extends WizardPage {
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;
}
@@ -1071,8 +1155,8 @@ public class NewProjectCreationPage extends WizardPage {
*/
private int validateLocationPath(IWorkspace workspace) {
Path path = new Path(getProjectLocation());
if (isNewProject()) {
if (!useDefaultLocation()) {
if (mInfo.isNewProject()) {
if (!mInfo.useDefaultLocation()) {
// If not using the default value validate the location.
URI uri = URIUtil.toURI(path.toOSString());
IStatus locationStatus = workspace.validateProjectLocationURI(getProjectHandle(),
@@ -1103,10 +1187,10 @@ public class NewProjectCreationPage extends WizardPage {
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()) {
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 {
@@ -1115,7 +1199,7 @@ public class NewProjectCreationPage extends WizardPage {
if (!f.isDirectory()) {
return setStatus("An existing directory name must be specified.", MSG_ERROR);
}
// Check there's an android manifest in the directory
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
File manifestFile = new File(osPath);
@@ -1144,7 +1228,7 @@ public class NewProjectCreationPage extends WizardPage {
Activity[] activities = manifestData.getActivities();
if (activities == null || activities.length == 0) {
// This is acceptable now as long as no activity needs to be created
if (isCreateActivity()) {
if (mInfo.isCreateActivity()) {
return setStatus(
String.format("No activity name defined in %1$s.", osPath),
MSG_ERROR);
@@ -1163,11 +1247,11 @@ public class NewProjectCreationPage extends WizardPage {
/**
* Validates the sdk target choice.
*
*
* @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE.
*/
private int validateSdkTarget() {
if (getSdkTarget() == null) {
if (mInfo.getSdkTarget() == null) {
return setStatus("An SDK Target must be specified.", MSG_ERROR);
}
return MSG_NONE;
@@ -1175,29 +1259,29 @@ public class NewProjectCreationPage extends WizardPage {
/**
* Validates the sdk target choice.
*
*
* @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE.
*/
private int validateMinSdkVersionField() {
// If the min sdk version is empty, it is always accepted.
if (getMinSdkVersion().length() == 0) {
if (mInfo.getMinSdkVersion().length() == 0) {
return MSG_NONE;
}
int version = AndroidManifestParser.INVALID_MIN_SDK;
try {
// If not empty, it must be a valid integer > 0
version = Integer.parseInt(getMinSdkVersion());
version = Integer.parseInt(mInfo.getMinSdkVersion());
} catch (NumberFormatException e) {
// ignore
}
if (version < 1) {
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.",
MSG_WARNING);
}
@@ -1212,36 +1296,36 @@ public class NewProjectCreationPage extends WizardPage {
*/
private int validateActivityField() {
// Disregard if not creating an activity
if (!isCreateActivity()) {
if (!mInfo.isCreateActivity()) {
return MSG_NONE;
}
// Validate activity field
String activityFieldContents = getActivityName();
String activityFieldContents = mInfo.getActivityName();
if (activityFieldContents.length() == 0) {
return setStatus("Activity name must be specified.", MSG_ERROR);
}
// The activity field can actually contain part of a sub-package name
// or it can start with a dot "." to indicates it comes from the parent package name.
String packageName = "";
String packageName = ""; //$NON-NLS-1$
int pos = activityFieldContents.lastIndexOf('.');
if (pos >= 0) {
packageName = activityFieldContents.substring(0, pos);
if (packageName.startsWith(".")) { //$NON-NLS-1$
packageName = packageName.substring(1);
}
activityFieldContents = activityFieldContents.substring(pos + 1);
}
// the activity field can contain a simple java identifier, or a
// package name or one that starts with a dot. So if it starts with a dot,
// ignore this dot -- the rest must look like a package name.
if (activityFieldContents.charAt(0) == '.') {
activityFieldContents = activityFieldContents.substring(1);
}
// Check it's a valid activity string
int result = MSG_NONE;
IStatus status = JavaConventions.validateTypeVariableName(activityFieldContents,
@@ -1272,7 +1356,7 @@ public class NewProjectCreationPage extends WizardPage {
*/
private int validatePackageField() {
// Validate package field
String packageFieldContents = getPackageName();
String packageFieldContents = mInfo.getPackageName();
if (packageFieldContents.length() == 0) {
return setStatus("Package name must be specified.", MSG_ERROR);
}
@@ -1312,16 +1396,16 @@ public class NewProjectCreationPage extends WizardPage {
private int validateSourceFolder() {
// This check does nothing when creating a new project.
// This check is also useless when no activity is present or created.
if (isNewProject() || !isCreateActivity()) {
if (mInfo.isNewProject() || !mInfo.isCreateActivity()) {
return MSG_NONE;
}
String osTarget = getActivityName();
String osTarget = mInfo.getActivityName();
if (osTarget.indexOf('.') == -1) {
osTarget = getPackageName() + File.separator + osTarget;
osTarget = mInfo.getPackageName() + File.separator + osTarget;
} else if (osTarget.indexOf('.') == 0) {
osTarget = getPackageName() + osTarget;
osTarget = mInfo.getPackageName() + osTarget;
}
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.ProjectHelper;
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.sdklib.IAndroidTarget;
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.Platform;
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.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
@@ -71,27 +75,54 @@ import java.util.Map.Entry;
* Note: this class is public so that it can be accessed from unit tests.
* It is however an internal class. Its API may change without notice.
* It should semantically be considered as a private final class.
* Do not derive from this class.
* Do not derive from this class.
*/
public class NewProjectWizard extends Wizard implements INewWizard {
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_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$
private static final String PARAM_PACKAGE = "PACKAGE"; //$NON-NLS-1$
private static final String PARAM_PROJECT = "PROJECT_NAME"; //$NON-NLS-1$
private static final String PARAM_STRING_NAME = "STRING_NAME"; //$NON-NLS-1$
private static final String PARAM_STRING_CONTENT = "STRING_CONTENT"; //$NON-NLS-1$
private static final String PARAM_IS_NEW_PROJECT = "IS_NEW_PROJECT"; //$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_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$
/**
* 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 PH_ACTIVITIES = "ACTIVITIES"; //$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_STRINGS = "STRINGS"; //$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_APPLICATION = "APPLICATION_NAME"; //$NON-NLS-1$
private static final String PARAM_PACKAGE = "PACKAGE"; //$NON-NLS-1$
private static final String PARAM_PROJECT = "PROJECT_NAME"; //$NON-NLS-1$
private static final String PARAM_STRING_NAME = "STRING_NAME"; //$NON-NLS-1$
private static final String PARAM_STRING_CONTENT = "STRING_CONTENT"; //$NON-NLS-1$
private static final String PARAM_IS_NEW_PROJECT = "IS_NEW_PROJECT"; //$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_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_USES_SDK = "USES-SDK"; //$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_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 =
SdkConstants.FD_OUTPUT + AndroidConstants.WS_SEP;
@@ -117,6 +148,12 @@ public class NewProjectWizard extends Wizard implements INewWizard {
+ "uses-sdk.template"; //$NON-NLS-1$
private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY
+ "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
+ "strings.template"; //$NON-NLS-1$
@@ -124,11 +161,11 @@ public class NewProjectWizard extends Wizard implements INewWizard {
+ "string.template"; //$NON-NLS-1$
private static final String ICON = "icon.png"; //$NON-NLS-1$
private static final String STRINGS_FILE = "strings.xml"; //$NON-NLS-1$
private static final String STRINGS_FILE = "strings.xml"; //$NON-NLS-1$
private static final String STRING_RSRC_PREFIX = "@string/"; //$NON-NLS-1$
private static final String STRING_APP_NAME = "app_name"; //$NON-NLS-1$
private static final String STRING_HELLO_WORLD = "hello"; //$NON-NLS-1$
private static final String STRING_RSRC_PREFIX = "@string/"; //$NON-NLS-1$
private static final String STRING_APP_NAME = "app_name"; //$NON-NLS-1$
private static final String STRING_HELLO_WORLD = "hello"; //$NON-NLS-1$
private static final String[] DEFAULT_DIRECTORIES = new String[] {
BIN_DIRECTORY, RES_DIRECTORY, ASSETS_DIRECTORY };
@@ -136,15 +173,23 @@ public class NewProjectWizard extends Wizard implements INewWizard {
DRAWABLE_DIRECTORY, LAYOUT_DIRECTORY, VALUES_DIRECTORY};
private static final String PROJECT_LOGO_LARGE = "icons/android_large.png"; //$NON-NLS-1$
private static final String JAVA_ACTIVITY_TEMPLATE = "java_file.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$
protected static final String MAIN_PAGE_NAME = "newAndroidProjectPage"; //$NON-NLS-1$
private static final String JAVA_ACTIVITY_TEMPLATE = "java_file.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 NewProjectCreationPage mMainPage;
private NewTestProjectCreationPage mTestPage;
/** Package name available when the wizard completes. */
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
@@ -155,13 +200,14 @@ public class NewProjectWizard extends Wizard implements INewWizard {
setWindowTitle("New Android Project");
setImageDescriptor();
mMainPage = createMainPage();
mMainPage.setTitle("New Android Project");
mMainPage.setDescription("Creates a new Android Project resource.");
if (mAvailablePages == AvailablePages.ANDROID_AND_TEST_PROJECT) {
mMainPage = createMainPage();
}
mTestPage = createTestPage();
}
/**
* Creates the wizard page.
* Creates the main wizard page.
* <p/>
* Please do NOT override this method.
* <p/>
@@ -170,7 +216,20 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* to maintain compatibility between different versions of the plugin.
*/
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 --
@@ -182,7 +241,15 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*/
@Override
public void addPages() {
addPage(mMainPage);
if (mAvailablePages == AvailablePages.ANDROID_AND_TEST_PROJECT) {
addPage(mMainPage);
}
addPage(mTestPage);
if (mMainPage != null && mTestPage != null) {
mTestPage.setMainInfo(mMainPage.getMainInfo());
mMainPage.setTestInfo(mTestPage.getTestInfo());
}
}
/**
@@ -195,7 +262,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*/
@Override
public boolean performFinish() {
if (!createAndroidProject()) {
if (!createAndroidProjects()) {
return false;
}
@@ -206,21 +273,21 @@ public class NewProjectWizard extends Wizard implements INewWizard {
}
// -- 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() {
return mPackageName;
}
// -- Custom Methods --
/**
* Before actually creating the project for a new project (as opposed to using an
* existing project), we check if the target location is a directory that either does
* not exist or is empty.
*
*
* If it's not empty, ask the user for confirmation.
*
*
* @param destination The destination folder where the new project is to be created.
* @return True if the destination doesn't exist yet or is an empty directory or is
* accepted by the user.
@@ -234,33 +301,108 @@ public class NewProjectWizard extends Wizard implements INewWizard {
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.
* @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();
final IProject project = workspace.getRoot().getProject(mMainPage.getProjectName());
final IProject project = workspace.getRoot().getProject(info.getProjectName());
final IProjectDescription description = workspace.newProjectDescription(project.getName());
// 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>();
parameters.put(PARAM_PROJECT, mMainPage.getProjectName());
parameters.put(PARAM_PROJECT, info.getProjectName());
parameters.put(PARAM_PACKAGE, mPackageName);
parameters.put(PARAM_APPLICATION, STRING_RSRC_PREFIX + STRING_APP_NAME);
parameters.put(PARAM_SDK_TOOLS_DIR, AdtPlugin.getOsSdkToolsFolder());
parameters.put(PARAM_IS_NEW_PROJECT, mMainPage.isNewProject());
parameters.put(PARAM_SRC_FOLDER, mMainPage.getSourceFolder());
parameters.put(PARAM_SDK_TARGET, mMainPage.getSdkTarget());
parameters.put(PARAM_MIN_SDK_VERSION, mMainPage.getMinSdkVersion());
if (mMainPage.isCreateActivity()) {
parameters.put(PARAM_IS_NEW_PROJECT, info.isNewProject());
parameters.put(PARAM_SRC_FOLDER, info.getSourceFolder());
parameters.put(PARAM_SDK_TARGET, info.getSdkTarget());
parameters.put(PARAM_MIN_SDK_VERSION, info.getMinSdkVersion());
if (info.isCreateActivity()) {
// 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.
String activityName = mMainPage.getActivityName();
String activityName = info.getActivityName();
if (activityName.startsWith(".")) { //$NON-NLS-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.
// we'll put all the strings into values/strings.xml
final HashMap<String, String> stringDictionary = new HashMap<String, String>();
stringDictionary.put(STRING_APP_NAME, mMainPage.getApplicationName());
final HashMap<String, String> dictionary = new HashMap<String, String>();
dictionary.put(STRING_APP_NAME, info.getApplicationName());
IPath path = mMainPage.getLocationPath();
IPath path = info.getLocationPath();
IPath defaultLocation = Platform.getLocation();
if (!path.equals(defaultLocation)) {
description.setLocation(path);
}
if (mMainPage.isNewProject() && !mMainPage.useDefaultLocation() &&
if (info.isNewProject() && !info.useDefaultLocation() &&
!validateNewProjectLocationIsEmpty(path)) {
return false;
return null;
}
// Create a monitored operation to create the actual project
WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws InvocationTargetException {
createProjectAsync(project, description, monitor, parameters, stringDictionary);
}
};
return new ProjectInfo(project, description, parameters, dictionary);
}
// Run the operation in a different thread
runAsyncOperation(op);
return true;
/**
* Collects all the parameters needed to create the test 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 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,82 +520,46 @@ public class NewProjectWizard extends Wizard implements INewWizard {
}
/**
* Creates the actual project, sets its nature and adds the required folders
* and files to it. This is run asynchronously in a different thread.
* Creates the actual project(s). 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 parameters Template parameters.
* @param stringDictionary String definition.
* @param mainData Data for main project. Can be null.
* @throws InvocationTargetException to wrap any unmanaged exception and
* 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.
*/
private void createProjectAsync(IProject project, IProjectDescription description,
IProgressMonitor monitor, Map<String, Object> parameters,
Map<String, String> stringDictionary)
throws InvocationTargetException {
private void createProjectAsync(IProgressMonitor monitor,
ProjectInfo mainData,
ProjectInfo testData)
throws InvocationTargetException {
monitor.beginTask("Create Android Project", 100);
try {
// Create project and open it
project.create(description, new SubProgressMonitor(monitor, 10));
if (monitor.isCanceled()) throw new OperationCanceledException();
project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10));
IProject mainProject = null;
// Add the Java and android nature to the project
AndroidNature.setupProjectNatures(project, monitor);
// Create folders in the project if they don't already exist
addDefaultDirectories(project, AndroidConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor);
String[] sourceFolders = new String[] {
(String) parameters.get(PARAM_SRC_FOLDER),
GEN_SRC_DIRECTORY
};
addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolders, monitor);
// Create the resource folders in the project if they don't already exist.
addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor);
// Setup class path: mark folders as source folders
IJavaProject javaProject = JavaCore.create(project);
for (String sourceFolder : sourceFolders) {
setupSourceFolder(javaProject, sourceFolder, monitor);
}
// Mark the gen source folder as derived
IFolder genSrcFolder = project.getFolder(AndroidConstants.WS_ROOT + GEN_SRC_DIRECTORY);
if (genSrcFolder.exists()) {
genSrcFolder.setDerived(true);
if (mainData != null) {
mainProject = createEclipseProject(
new SubProgressMonitor(monitor, 50),
mainData.getProject(),
mainData.getDescription(),
mainData.getParameters(),
mainData.getDictionary());
}
if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) {
// Create files in the project if they don't already exist
addManifest(project, parameters, stringDictionary, monitor);
if (testData != null) {
// add the default app icon
addIcon(project, monitor);
// Create the default package components
addSampleCode(project, sourceFolders[0], parameters, stringDictionary, monitor);
// add the string definition file if needed
if (stringDictionary.size() > 0) {
addStringDictionaryFile(project, stringDictionary, monitor);
Map<String, Object> parameters = testData.getParameters();
if (parameters.containsKey(PARAM_TARGET_MAIN) && mainProject != null) {
parameters.put(PARAM_REFERENCE_PROJECT, mainProject);
}
// Set output location
javaProject.setOutputLocation(project.getFolder(BIN_DIRECTORY).getFullPath(),
monitor);
createEclipseProject(
new SubProgressMonitor(monitor, 50),
testData.getProject(),
testData.getDescription(),
parameters,
testData.getDictionary());
}
Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET),
null /* apkConfigMap*/);
// Fix the project to make sure all properties are as expected.
// Necessary for existing projects and good for new ones to.
ProjectHelper.fixProject(project);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} catch (IOException e) {
@@ -413,6 +569,111 @@ public class NewProjectWizard extends Wizard implements INewWizard {
}
}
/**
* 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
project.create(description, new SubProgressMonitor(monitor, 10));
if (monitor.isCanceled()) throw new OperationCanceledException();
project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 10));
// Add the Java and android nature to the project
AndroidNature.setupProjectNatures(project, monitor);
// Create folders in the project if they don't already exist
addDefaultDirectories(project, AndroidConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor);
String[] sourceFolders = new String[] {
(String) parameters.get(PARAM_SRC_FOLDER),
GEN_SRC_DIRECTORY
};
addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolders, monitor);
// Create the resource folders in the project if they don't already exist.
addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor);
// Setup class path: mark folders as source folders
IJavaProject javaProject = JavaCore.create(project);
for (String sourceFolder : sourceFolders) {
setupSourceFolder(javaProject, sourceFolder, monitor);
}
// Mark the gen source folder as derived
IFolder genSrcFolder = project.getFolder(AndroidConstants.WS_ROOT + GEN_SRC_DIRECTORY);
if (genSrcFolder.exists()) {
genSrcFolder.setDerived(true);
}
if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) {
// Create files in the project if they don't already exist
addManifest(project, parameters, dictionary, monitor);
// add the default app icon
addIcon(project, monitor);
// Create the default package components
addSampleCode(project, sourceFolders[0], parameters, dictionary, monitor);
// add the string definition file if needed
if (dictionary.size() > 0) {
addStringDictionaryFile(project, dictionary, monitor);
}
// Set output location
javaProject.setOutputLocation(project.getFolder(BIN_DIRECTORY).getFullPath(),
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),
null /* apkConfigMap*/);
// Fix the project to make sure all properties are as expected.
// Necessary for existing projects and good for new ones to.
ProjectHelper.fixProject(project);
return project;
}
/**
* Adds default directories to the project.
*
@@ -442,7 +703,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*
* @param project The Java Project to update.
* @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.
* @param monitor An existing monitor.
* @throws CoreException if the method fails to update the project.
@@ -450,7 +711,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* project.
*/
private void addManifest(IProject project, Map<String, Object> parameters,
Map<String, String> stringDictionary, IProgressMonitor monitor)
Map<String, String> dictionary, IProgressMonitor monitor)
throws CoreException, IOException {
// get IFile to the manifest and check if it's not already there.
@@ -466,23 +727,42 @@ public class NewProjectWizard extends Wizard implements INewWizard {
if (parameters.containsKey(PARAM_ACTIVITY)) {
// now get the activity template
String activityTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_ACTIVITIES);
// Replace all keyword parameters to make main activity.
String activities = replaceParameters(activityTemplate, parameters);
// set the intent.
String intent = AdtPlugin.readEmbeddedTextFile(TEMPLATE_INTENT_LAUNCHER);
// set the intent to the main activity
activities = activities.replaceAll(PH_INTENT_FILTERS, intent);
// set the activity(ies) in the manifest
manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities);
} else {
// 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);
if (minSdkVersion != null && minSdkVersion.length() > 0) {
String usesSdkTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_USES_SDK);
@@ -584,7 +864,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
*
* @param project The Java Project to update.
* @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.
* @param monitor An existing monitor.
* @throws CoreException if the method fails to update the project.
@@ -592,12 +872,12 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* project.
*/
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 {
// create the java package directories.
IFolder pkgFolder = project.getFolder(sourceFolder);
String packageName = (String) parameters.get(PARAM_PACKAGE);
// The PARAM_ACTIVITY key will be absent if no activity should be created,
// in which case activityName will be null.
String activityName = (String) parameters.get(PARAM_ACTIVITY);
@@ -610,7 +890,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
int pos = packageName.lastIndexOf('.');
activityName = packageName.substring(pos + 1);
packageName = packageName.substring(0, pos);
// Also update the values used in the JAVA_FILE_TEMPLATE below
// (but not the ones from the manifest so don't change the caller's dictionary)
java_activity_parameters = new HashMap<String, Object>(parameters);
@@ -643,9 +923,9 @@ public class NewProjectWizard extends Wizard implements INewWizard {
if (!file.exists()) {
copyFile(LAYOUT_TEMPLATE, file, parameters, monitor);
if (activityName != null) {
stringDictionary.put(STRING_HELLO_WORLD, "Hello World, " + activityName + "!");
dictionary.put(STRING_HELLO_WORLD, "Hello World, " + activityName + "!");
} 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">
<application android:icon="@drawable/icon" android:label="APPLICATION_NAME">
ACTIVITIES
TEST-USES-LIBRARY
</application>
USES-SDK
TEST-INSTRUMENTATION
</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;
import com.android.sdklib.IAndroidTarget;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import java.io.File;
/**
@@ -26,46 +31,60 @@ public class StubSampleProjectCreationPage extends NewProjectCreationPage {
private String mSampleProjectName;
private String mOsSdkLocation;
public StubSampleProjectCreationPage(String pageName,
String sampleProjectName, String osSdkLocation) {
super(pageName);
public StubSampleProjectCreationPage(String sampleProjectName, String osSdkLocation) {
super();
this.mSampleProjectName = sampleProjectName;
this.mOsSdkLocation = osSdkLocation;
}
@Override
public String getProjectName() {
return mSampleProjectName;
}
public IMainInfo getMainInfo() {
return new IMainInfo() {
public String getProjectName() {
return mSampleProjectName;
}
@Override
public String getPackageName() {
return "com.android.samples";
}
public String getPackageName() {
return "com.android.samples";
}
@Override
public String getActivityName() {
return mSampleProjectName;
}
public String getActivityName() {
return mSampleProjectName;
}
@Override
public String getApplicationName() {
return mSampleProjectName;
}
public String getApplicationName() {
return mSampleProjectName;
}
@Override
public boolean isNewProject() {
return false;
}
public boolean isNewProject() {
return false;
}
@Override
public String getProjectLocation() {
return mOsSdkLocation + File.separator + "samples" + File.separator + mSampleProjectName;
}
public String getSourceFolder() {
return "src";
}
@Override
public String getSourceFolder() {
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
protected NewProjectCreationPage createMainPage() {
return new StubSampleProjectCreationPage(MAIN_PAGE_NAME,
mSampleProjectName, mOsSdkLocation);
return new StubSampleProjectCreationPage(mSampleProjectName, mOsSdkLocation);
}
/**

View File

@@ -67,8 +67,6 @@ public class EclipseTestCollector {
/**
* Returns true if given class should be added to suite
* @param testClass
* @return
*/
protected boolean isTestClass(Class<?> testClass) {
return TestCase.class.isAssignableFrom(testClass) &&
@@ -78,8 +76,6 @@ public class EclipseTestCollector {
/**
* Returns true if given class has a public constructor
* @param testClass
* @return
*/
protected boolean hasPublicConstructor(Class<?> testClass) {
try {
@@ -94,7 +90,6 @@ public class EclipseTestCollector {
* Load the class given by the plugin aka bundle file path
* @param filePath - path of class in bundle
* @param expectedPackage - expected package of class
* @return
* @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.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
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);
}
}
}