| /* |
| * Copyright (C) 2007 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. |
| */ |
| |
| /* |
| * References: |
| * org.eclipse.jdt.internal.ui.wizards.JavaProjectWizard |
| * org.eclipse.jdt.internal.ui.wizards.JavaProjectWizardFirstPage |
| */ |
| |
| 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.common.AndroidConstants; |
| import com.android.ide.eclipse.common.project.AndroidManifestParser; |
| import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity; |
| import com.android.sdklib.IAndroidTarget; |
| import com.android.sdklib.SdkConstants; |
| import com.android.sdklib.project.ProjectProperties; |
| import com.android.sdklib.project.ProjectProperties.PropertyType; |
| import com.android.sdkuilib.SdkTargetSelector; |
| |
| import org.eclipse.core.filesystem.URIUtil; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jdt.core.JavaConventions; |
| import org.eclipse.jface.wizard.WizardPage; |
| import org.eclipse.osgi.util.TextProcessor; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.DirectoryDialog; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Text; |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.net.URI; |
| import java.util.regex.Pattern; |
| |
| /** |
| * NewAndroidProjectCreationPage is a project creation page that provides the |
| * following fields: |
| * <ul> |
| * <li> Project name |
| * <li> SDK Target |
| * <li> Application name |
| * <li> Package name |
| * <li> Activity name |
| * </ul> |
| * 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. |
| */ |
| public class NewProjectCreationPage extends WizardPage { |
| |
| // constants |
| /** 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$ |
| /** Initial value for the Create New Project radio; False means Create From Existing would be |
| * the default.*/ |
| private static final boolean INITIAL_CREATE_NEW_PROJECT = true; |
| /** Initial value for the Use Default Location check box. */ |
| 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. */ |
| private static final Pattern sProjectNamePattern = Pattern.compile("^[\\w][\\w. -]*$"); //$NON-NLS-1$ |
| /** Last user-browsed location, static so that it be remembered for the whole session */ |
| private static String sCustomLocationOsPath = ""; //$NON-NLS-1$ |
| private static boolean sAutoComputeCustomLocation = true; |
| |
| private final int MSG_NONE = 0; |
| private final int MSG_WARNING = 1; |
| private final int MSG_ERROR = 2; |
| |
| private String mUserPackageName = ""; //$NON-NLS-1$ |
| private String mUserActivityName = ""; //$NON-NLS-1$ |
| private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY; |
| private String mSourceFolder = ""; //$NON-NLS-1$ |
| |
| // widgets |
| private Text mProjectNameField; |
| private Text mPackageNameField; |
| private Text mActivityNameField; |
| private Text mApplicationNameField; |
| private Button mCreateNewProjectRadio; |
| private Button mUseDefaultLocation; |
| private Label mLocationLabel; |
| private Text mLocationPathField; |
| private Button mBrowseButton; |
| private Button mCreateActivityCheck; |
| private Text mMinSdkVersionField; |
| private SdkTargetSelector mSdkTargetSelector; |
| private ITargetChangeListener mSdkTargetChangeListener; |
| |
| private boolean mInternalLocationPathUpdate; |
| protected boolean mInternalProjectNameUpdate; |
| protected boolean mInternalApplicationNameUpdate; |
| private boolean mInternalCreateActivityUpdate; |
| private boolean mInternalActivityNameUpdate; |
| protected boolean mProjectNameModifiedByUser; |
| protected 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); |
| setPageComplete(false); |
| } |
| |
| // --- 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. |
| */ |
| public IPath getLocationPath() { |
| return new Path(getProjectLocation()); |
| } |
| |
| /** 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(); |
| } |
| |
| /** 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(); |
| } |
| |
| /** 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 New Project" radio. */ |
| public boolean isNewProject() { |
| return mCreateNewProjectRadio == null ? INITIAL_CREATE_NEW_PROJECT |
| : mCreateNewProjectRadio.getSelection(); |
| } |
| |
| /** 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(); |
| } |
| |
| /** |
| * Overrides @DialogPage.setVisible(boolean) to put the focus in the project name when |
| * the dialog is made visible. |
| */ |
| @Override |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| if (visible) { |
| mProjectNameField.setFocus(); |
| } |
| } |
| |
| // --- UI creation --- |
| |
| /** |
| * Creates the top level control for this dialog page under the given parent |
| * composite. |
| * |
| * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite) |
| */ |
| public void createControl(Composite parent) { |
| Composite composite = new Composite(parent, SWT.NULL); |
| composite.setFont(parent.getFont()); |
| |
| initializeDialogUnits(parent); |
| |
| composite.setLayout(new GridLayout()); |
| composite.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| createProjectNameGroup(composite); |
| createLocationGroup(composite); |
| createTargetGroup(composite); |
| createPropertiesGroup(composite); |
| |
| // Update state the first time |
| enableLocationWidgets(); |
| |
| // Show description the first time |
| setErrorMessage(null); |
| setMessage(null); |
| setControl(composite); |
| |
| // Validate. This will complain about the first empty field. |
| setPageComplete(validatePage()); |
| } |
| |
| @Override |
| public void dispose() { |
| |
| if (mSdkTargetChangeListener != null) { |
| AdtPlugin.getDefault().removeTargetListener(mSdkTargetChangeListener); |
| mSdkTargetChangeListener = null; |
| } |
| |
| super.dispose(); |
| } |
| |
| /** |
| * Creates the group for the project name: |
| * [label: "Project Name"] [text field] |
| * |
| * @param parent the parent composite |
| */ |
| private final void createProjectNameGroup(Composite parent) { |
| Composite group = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 2; |
| group.setLayout(layout); |
| group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| // new project label |
| Label label = new Label(group, SWT.NONE); |
| label.setText("Project name:"); |
| label.setFont(parent.getFont()); |
| label.setToolTipText("Name of the Eclipse project to create. It cannot be empty."); |
| |
| // new project name entry field |
| mProjectNameField = new Text(group, SWT.BORDER); |
| GridData data = new GridData(GridData.FILL_HORIZONTAL); |
| mProjectNameField.setToolTipText("Name of the Eclipse project to create. It cannot be empty."); |
| mProjectNameField.setLayoutData(data); |
| mProjectNameField.setFont(parent.getFont()); |
| mProjectNameField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| if (!mInternalProjectNameUpdate) { |
| mProjectNameModifiedByUser = true; |
| } |
| updateLocationPathField(null); |
| } |
| }); |
| } |
| |
| |
| /** |
| * Creates the group for the Project options: |
| * [radio] Create new project |
| * [radio] Create project from existing sources |
| * [check] Use default location |
| * Location [text field] [browse button] |
| * |
| * @param parent the parent composite |
| */ |
| private final void createLocationGroup(Composite parent) { |
| 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.setFont(parent.getFont()); |
| group.setText("Contents"); |
| |
| mCreateNewProjectRadio = new Button(group, SWT.RADIO); |
| mCreateNewProjectRadio.setText("Create new project in workspace"); |
| mCreateNewProjectRadio.setSelection(INITIAL_CREATE_NEW_PROJECT); |
| Button existing_project_radio = new Button(group, SWT.RADIO); |
| existing_project_radio.setText("Create project from existing source"); |
| existing_project_radio.setSelection(!INITIAL_CREATE_NEW_PROJECT); |
| |
| mUseDefaultLocation = new Button(group, SWT.CHECK); |
| mUseDefaultLocation.setText("Use default location"); |
| mUseDefaultLocation.setSelection(INITIAL_USE_DEFAULT_LOCATION); |
| |
| SelectionListener location_listener = new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| super.widgetSelected(e); |
| enableLocationWidgets(); |
| extractNamesFromAndroidManifest(); |
| setPageComplete(validatePage()); |
| } |
| }; |
| |
| mCreateNewProjectRadio.addSelectionListener(location_listener); |
| existing_project_radio.addSelectionListener(location_listener); |
| mUseDefaultLocation.addSelectionListener(location_listener); |
| |
| Composite location_group = new Composite(group, SWT.NONE); |
| location_group.setLayout(new GridLayout(4, /* num columns */ |
| false /* columns of not equal size */)); |
| location_group.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| location_group.setFont(parent.getFont()); |
| |
| mLocationLabel = new Label(location_group, SWT.NONE); |
| mLocationLabel.setText("Location:"); |
| |
| mLocationPathField = new Text(location_group, SWT.BORDER); |
| GridData data = new GridData(GridData.FILL, /* horizontal alignment */ |
| GridData.BEGINNING, /* vertical alignment */ |
| true, /* grabExcessHorizontalSpace */ |
| false, /* grabExcessVerticalSpace */ |
| 2, /* horizontalSpan */ |
| 1); /* verticalSpan */ |
| mLocationPathField.setLayoutData(data); |
| mLocationPathField.setFont(parent.getFont()); |
| mLocationPathField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| onLocationPathFieldModified(); |
| } |
| }); |
| |
| mBrowseButton = new Button(location_group, SWT.PUSH); |
| mBrowseButton.setText("Browse..."); |
| setButtonLayoutData(mBrowseButton); |
| mBrowseButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| openDirectoryBrowser(); |
| } |
| }); |
| } |
| |
| /** |
| * Creates the target group. |
| * It only contains an SdkTargetSelector. |
| */ |
| private void createTargetGroup(Composite parent) { |
| Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); |
| // Layout has 1 column |
| group.setLayout(new GridLayout()); |
| group.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| group.setFont(parent.getFont()); |
| group.setText("Target"); |
| |
| // The selector is created without targets. They are added below in the change listener. |
| mSdkTargetSelector = new SdkTargetSelector(group, null); |
| |
| mSdkTargetChangeListener = new ITargetChangeListener() { |
| public void onProjectTargetChange(IProject changedProject) { |
| // Ignore |
| } |
| |
| public void onTargetsLoaded() { |
| // Update the sdk target selector with the new targets |
| |
| // get the targets from the sdk |
| IAndroidTarget[] targets = null; |
| if (Sdk.getCurrent() != null) { |
| targets = Sdk.getCurrent().getTargets(); |
| } |
| mSdkTargetSelector.setTargets(targets); |
| |
| // If there's only one target, select it |
| if (targets != null && targets.length == 1) { |
| mSdkTargetSelector.setSelection(targets[0]); |
| } |
| } |
| }; |
| |
| 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()); |
| } |
| }); |
| } |
| |
| /** |
| * 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] |
| * - Activity name [text field] |
| * - Application name [text field] |
| * |
| * @param parent the parent composite |
| */ |
| private final void createPropertiesGroup(Composite parent) { |
| // package specification group |
| Group group = new Group(parent, SWT.SHADOW_ETCHED_IN); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 2; |
| group.setLayout(layout); |
| group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| group.setFont(parent.getFont()); |
| group.setText("Properties"); |
| |
| // new application label |
| Label label = new Label(group, SWT.NONE); |
| label.setText("Application name:"); |
| label.setFont(parent.getFont()); |
| label.setToolTipText("Name of the Application. This is a free string. It can be empty."); |
| |
| // new application name entry field |
| mApplicationNameField = new Text(group, SWT.BORDER); |
| GridData data = new GridData(GridData.FILL_HORIZONTAL); |
| mApplicationNameField.setToolTipText("Name of the Application. This is a free string. It can be empty."); |
| mApplicationNameField.setLayoutData(data); |
| mApplicationNameField.setFont(parent.getFont()); |
| mApplicationNameField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| if (!mInternalApplicationNameUpdate) { |
| mApplicationNameModifiedByUser = true; |
| } |
| } |
| }); |
| |
| // new package label |
| label = new Label(group, SWT.NONE); |
| label.setText("Package name:"); |
| label.setFont(parent.getFont()); |
| label.setToolTipText("Namespace of the Package to create. This must be a Java namespace with at least two components."); |
| |
| // new package name entry field |
| mPackageNameField = new Text(group, SWT.BORDER); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| mPackageNameField.setToolTipText("Namespace of the Package to create. This must be a Java namespace with at least two components."); |
| mPackageNameField.setLayoutData(data); |
| mPackageNameField.setFont(parent.getFont()); |
| mPackageNameField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| onPackageNameFieldModified(); |
| } |
| }); |
| |
| // new activity label |
| mCreateActivityCheck = new Button(group, SWT.CHECK); |
| mCreateActivityCheck.setText("Create Activity:"); |
| mCreateActivityCheck.setToolTipText("Specifies if you want to create a default Activity."); |
| mCreateActivityCheck.setFont(parent.getFont()); |
| mCreateActivityCheck.setSelection(INITIAL_CREATE_ACTIVITY); |
| mCreateActivityCheck.addListener(SWT.Selection, new Listener() { |
| public void handleEvent(Event event) { |
| onCreateActivityCheckModified(); |
| enableLocationWidgets(); |
| } |
| }); |
| |
| // new activity name entry field |
| mActivityNameField = new Text(group, SWT.BORDER); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| mActivityNameField.setToolTipText("Name of the Activity class to create. Must be a valid Java identifier."); |
| mActivityNameField.setLayoutData(data); |
| mActivityNameField.setFont(parent.getFont()); |
| mActivityNameField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| onActivityNameFieldModified(); |
| } |
| }); |
| |
| // min sdk version label |
| label = new Label(group, SWT.NONE); |
| label.setText("Min SDK Version:"); |
| label.setFont(parent.getFont()); |
| label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty."); |
| |
| // min sdk version entry field |
| mMinSdkVersionField = new Text(group, SWT.BORDER); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty."); |
| mMinSdkVersionField.setLayoutData(data); |
| mMinSdkVersionField.setFont(parent.getFont()); |
| mMinSdkVersionField.addListener(SWT.Modify, new Listener() { |
| public void handleEvent(Event event) { |
| onMinSdkVersionFieldModified(); |
| setPageComplete(validatePage()); |
| } |
| }); |
| } |
| |
| |
| //--- Internal getters & setters ------------------ |
| |
| /** Returns the location path field value with spaces trimmed. */ |
| private String getLocationPathFieldValue() { |
| return mLocationPathField == null ? "" : mLocationPathField.getText().trim(); |
| } |
| |
| /** Returns the current project location, depending on the Use Default Location check box. */ |
| public String getProjectLocation() { |
| if (isNewProject() && useDefaultLocation()) { |
| return Platform.getLocation().toString(); |
| } else { |
| return getLocationPathFieldValue(); |
| } |
| } |
| |
| /** |
| * Creates a project resource handle for the current project name field |
| * value. |
| * <p> |
| * This method does not create the project resource; this is the |
| * responsibility of <code>IProject::create</code> invoked by the new |
| * project resource wizard. |
| * </p> |
| * |
| * @return the new project resource handle |
| */ |
| private IProject getProjectHandle() { |
| return ResourcesPlugin.getWorkspace().getRoot().getProject(getProjectName()); |
| } |
| |
| // --- UI Callbacks ---- |
| |
| /** |
| * 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 location_enabled = !is_new_project || !use_default; |
| boolean create_activity = isCreateActivity(); |
| |
| mUseDefaultLocation.setEnabled(is_new_project); |
| |
| mLocationLabel.setEnabled(location_enabled); |
| mLocationPathField.setEnabled(location_enabled); |
| mBrowseButton.setEnabled(location_enabled); |
| |
| mPackageNameField.setEnabled(is_new_project); |
| mCreateActivityCheck.setEnabled(is_new_project); |
| mActivityNameField.setEnabled(is_new_project & create_activity); |
| |
| updateLocationPathField(null); |
| updatePackageAndActivityFields(); |
| } |
| |
| /** |
| * Updates the location directory path field. |
| * <br/> |
| * When custom user selection is enabled, use the abs_dir argument if not null and also |
| * save it internally. If abs_dir is null, restore the last saved abs_dir. This allows the |
| * user selection to be remembered when the user switches from default to custom. |
| * <br/> |
| * When custom user selection is disabled, use the workspace default location with the |
| * current project name. This does not change the internally cached abs_dir. |
| * |
| * @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 custom_location = !is_new_project || !use_default; |
| |
| if (!mInternalLocationPathUpdate) { |
| mInternalLocationPathUpdate = true; |
| if (custom_location) { |
| if (abs_dir != null) { |
| // We get here if the user selected a directory with the "Browse" button. |
| // Disable auto-compute of the custom location unless the user selected |
| // the exact same path. |
| sAutoComputeCustomLocation = sAutoComputeCustomLocation && |
| abs_dir.equals(sCustomLocationOsPath); |
| sCustomLocationOsPath = TextProcessor.process(abs_dir); |
| } else if (sAutoComputeCustomLocation || |
| (!is_new_project && !new File(sCustomLocationOsPath).isDirectory())) { |
| // By default select the samples directory of the current target |
| IAndroidTarget target = getSdkTarget(); |
| if (target != null) { |
| sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES); |
| } |
| |
| // If we don't have a target, select the base directory of the |
| // "universal sdk". If we don't even have that, use a root drive. |
| if (sCustomLocationOsPath == null || sCustomLocationOsPath.length() == 0) { |
| if (Sdk.getCurrent() != null) { |
| sCustomLocationOsPath = Sdk.getCurrent().getSdkLocation(); |
| } else { |
| sCustomLocationOsPath = File.listRoots()[0].getAbsolutePath(); |
| } |
| } |
| } |
| if (!mLocationPathField.getText().equals(sCustomLocationOsPath)) { |
| mLocationPathField.setText(sCustomLocationOsPath); |
| } |
| } else { |
| String value = Platform.getLocation().append(getProjectName()).toString(); |
| value = TextProcessor.process(value); |
| if (!mLocationPathField.getText().equals(value)) { |
| mLocationPathField.setText(value); |
| } |
| } |
| setPageComplete(validatePage()); |
| mInternalLocationPathUpdate = false; |
| } |
| } |
| |
| /** |
| * The location path field is either modified internally (from updateLocationPathField) |
| * or manually by the user when the custom_location mode is not set. |
| * |
| * Ignore the internal modification. When modified by the user, memorize the choice and |
| * validate the page. |
| */ |
| private void onLocationPathFieldModified() { |
| if (!mInternalLocationPathUpdate) { |
| // When the updates doesn't come from updateLocationPathField, it must be the user |
| // editing the field manually, in which case we want to save the value internally |
| // and we disable auto-compute of the custom location (to avoid overriding the user |
| // value) |
| String newPath = getLocationPathFieldValue(); |
| sAutoComputeCustomLocation = sAutoComputeCustomLocation && |
| newPath.equals(sCustomLocationOsPath); |
| sCustomLocationOsPath = newPath; |
| extractNamesFromAndroidManifest(); |
| setPageComplete(validatePage()); |
| } |
| } |
| |
| /** |
| * The package name field is either modified internally (from extractNamesFromAndroidManifest) |
| * or manually by the user when the custom_location mode is not set. |
| * |
| * Ignore the internal modification. When modified by the user, memorize the choice and |
| * validate the page. |
| */ |
| private void onPackageNameFieldModified() { |
| if (isNewProject()) { |
| mUserPackageName = getPackageName(); |
| setPageComplete(validatePage()); |
| } |
| } |
| |
| /** |
| * The create activity checkbox is either modified internally (from |
| * extractNamesFromAndroidManifest) or manually by the user. |
| * |
| * Ignore the internal modification. When modified by the user, memorize the choice and |
| * validate the page. |
| */ |
| private void onCreateActivityCheckModified() { |
| if (isNewProject() && !mInternalCreateActivityUpdate) { |
| mUserCreateActivityCheck = isCreateActivity(); |
| } |
| setPageComplete(validatePage()); |
| } |
| |
| /** |
| * The activity name field is either modified internally (from extractNamesFromAndroidManifest) |
| * or manually by the user when the custom_location mode is not set. |
| * |
| * Ignore the internal modification. When modified by the user, memorize the choice and |
| * validate the page. |
| */ |
| private void onActivityNameFieldModified() { |
| if (isNewProject() && !mInternalActivityNameUpdate) { |
| mUserActivityName = getActivityName(); |
| setPageComplete(validatePage()); |
| } |
| } |
| |
| /** |
| * 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. |
| */ |
| private void onMinSdkVersionFieldModified() { |
| if (mInternalMinSdkVersionUpdate) { |
| return; |
| } |
| |
| try { |
| int version = Integer.parseInt(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(); |
| if (curr_target != null && curr_target.getApiVersionNumber() == version) { |
| return; |
| } |
| |
| for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { |
| if (target.getApiVersionNumber() == version) { |
| mSdkTargetSelector.setSelection(target); |
| break; |
| } |
| } |
| } 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. |
| */ |
| private void onSdkTargetModified() { |
| IAndroidTarget target = getSdkTarget(); |
| |
| if (target != null && !mMinSdkVersionModifiedByUser) { |
| mInternalMinSdkVersionUpdate = true; |
| mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber())); |
| mInternalMinSdkVersionUpdate = false; |
| } |
| } |
| |
| /** |
| * Called when the radio buttons are changed between the "create new project" and the |
| * "use existing source" mode. This reverts the fields to whatever the user manually |
| * entered before. |
| */ |
| private void updatePackageAndActivityFields() { |
| if (isNewProject()) { |
| if (mUserPackageName.length() > 0 && |
| !mPackageNameField.getText().equals(mUserPackageName)) { |
| mPackageNameField.setText(mUserPackageName); |
| } |
| |
| if (mUserActivityName.length() > 0 && |
| !mActivityNameField.getText().equals(mUserActivityName)) { |
| mInternalActivityNameUpdate = true; |
| mActivityNameField.setText(mUserActivityName); |
| mInternalActivityNameUpdate = false; |
| } |
| |
| if (mUserCreateActivityCheck != mCreateActivityCheck.getSelection()) { |
| mInternalCreateActivityUpdate = true; |
| mCreateActivityCheck.setSelection(mUserCreateActivityCheck); |
| mInternalCreateActivityUpdate = false; |
| } |
| } |
| } |
| |
| /** |
| * Extract names from an android manifest. |
| * This is done only if the user selected the "use existing source" and a manifest xml file |
| * can actually be found in the custom user directory. |
| */ |
| private void extractNamesFromAndroidManifest() { |
| if (isNewProject()) { |
| return; |
| } |
| |
| String projectLocation = getProjectLocation(); |
| File f = new File(projectLocation); |
| if (!f.isDirectory()) { |
| return; |
| } |
| |
| 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; |
| int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK; |
| try { |
| packageName = manifestData.getPackage(); |
| minSdkVersion = manifestData.getApiLevelRequirement(); |
| |
| // try to get the first launcher activity. If none, just take the first activity. |
| activity = manifestData.getLauncherActivity(); |
| if (activity == null) { |
| Activity[] activities = manifestData.getActivities(); |
| if (activities != null && activities.length > 0) { |
| activity = activities[0]; |
| } |
| } |
| } catch (Exception e) { |
| // ignore exceptions |
| } |
| |
| if (packageName != null && packageName.length() > 0) { |
| mPackageNameField.setText(packageName); |
| } |
| |
| if (activity != null) { |
| activityName = AndroidManifestParser.extractActivityName(activity.getName(), |
| packageName); |
| } |
| |
| if (activityName != null && activityName.length() > 0) { |
| mInternalActivityNameUpdate = true; |
| mInternalCreateActivityUpdate = true; |
| mActivityNameField.setText(activityName); |
| mCreateActivityCheck.setSelection(true); |
| mInternalCreateActivityUpdate = false; |
| mInternalActivityNameUpdate = false; |
| |
| // If project name and application names are empty, use the activity |
| // name as a default. If the activity name has dots, it's a part of a |
| // package specification and only the last identifier must be used. |
| if (activityName.indexOf('.') != -1) { |
| String[] ids = activityName.split(AndroidConstants.RE_DOT); |
| activityName = ids[ids.length - 1]; |
| } |
| if (mProjectNameField.getText().length() == 0 || |
| !mProjectNameModifiedByUser) { |
| mInternalProjectNameUpdate = true; |
| mProjectNameField.setText(activityName); |
| mInternalProjectNameUpdate = false; |
| } |
| if (mApplicationNameField.getText().length() == 0 || |
| !mApplicationNameModifiedByUser) { |
| mInternalApplicationNameUpdate = true; |
| mApplicationNameField.setText(activityName); |
| mInternalApplicationNameUpdate = false; |
| } |
| } else { |
| mInternalActivityNameUpdate = true; |
| mInternalCreateActivityUpdate = true; |
| mActivityNameField.setText(""); //$NON-NLS-1$ |
| 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) { |
| // Package name is a java identifier, so it's most suitable for |
| // an application name. |
| |
| if (mApplicationNameField.getText().length() == 0 || |
| !mApplicationNameModifiedByUser) { |
| mInternalApplicationNameUpdate = true; |
| mApplicationNameField.setText(packageName); |
| mInternalApplicationNameUpdate = false; |
| } |
| |
| // For the project name, remove any dots |
| packageName = packageName.replace('.', '_'); |
| if (mProjectNameField.getText().length() == 0 || |
| !mProjectNameModifiedByUser) { |
| mInternalProjectNameUpdate = true; |
| 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 |
| p.merge(PropertyType.BUILD).merge(PropertyType.DEFAULT); |
| String v = p.getProperty(ProjectProperties.PROPERTY_TARGET); |
| IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(v); |
| if (target != null) { |
| mSdkTargetSelector.setSelection(target); |
| foundTarget = true; |
| } |
| } |
| |
| if (!foundTarget && minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK) { |
| try { |
| for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { |
| if (target.getApiVersionNumber() == minSdkVersion) { |
| mSdkTargetSelector.setSelection(target); |
| foundTarget = true; |
| break; |
| } |
| } |
| } catch(NumberFormatException e) { |
| // ignore |
| } |
| } |
| |
| if (!foundTarget) { |
| for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { |
| if (projectLocation.startsWith(target.getLocation())) { |
| mSdkTargetSelector.setSelection(target); |
| foundTarget = true; |
| break; |
| } |
| } |
| } |
| |
| if (!foundTarget) { |
| mInternalMinSdkVersionUpdate = true; |
| mMinSdkVersionField.setText( |
| minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" : |
| Integer.toString(minSdkVersion)); //$NON-NLS-1$ |
| mInternalMinSdkVersionUpdate = false; |
| } |
| } |
| |
| /** |
| * Returns whether this page's controls currently all contain valid values. |
| * |
| * @return <code>true</code> if all controls are valid, and |
| * <code>false</code> if at least one is invalid |
| */ |
| protected boolean validatePage() { |
| IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| |
| int status = validateProjectField(workspace); |
| if ((status & MSG_ERROR) == 0) { |
| status |= validateLocationPath(workspace); |
| } |
| if ((status & MSG_ERROR) == 0) { |
| status |= validateSdkTarget(); |
| } |
| if ((status & MSG_ERROR) == 0) { |
| status |= validatePackageField(); |
| } |
| if ((status & MSG_ERROR) == 0) { |
| status |= validateActivityField(); |
| } |
| if ((status & MSG_ERROR) == 0) { |
| status |= validateMinSdkVersionField(); |
| } |
| if ((status & MSG_ERROR) == 0) { |
| status |= validateSourceFolder(); |
| } |
| 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 project name field. |
| * |
| * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. |
| */ |
| private int validateProjectField(IWorkspace workspace) { |
| // Validate project field |
| String projectFieldContents = getProjectName(); |
| if (projectFieldContents.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()) { |
| 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); |
| if (!nameStatus.isOK()) { |
| return setStatus(nameStatus.getMessage(), MSG_ERROR); |
| } |
| |
| if (getProjectHandle().exists()) { |
| return setStatus("A project with that name already exists in the workspace", |
| MSG_ERROR); |
| } |
| |
| return MSG_NONE; |
| } |
| |
| /** |
| * Validates the location path field. |
| * |
| * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. |
| */ |
| private int validateLocationPath(IWorkspace workspace) { |
| Path path = new Path(getProjectLocation()); |
| if (isNewProject()) { |
| if (!useDefaultLocation()) { |
| // If not using the default value validate the location. |
| URI uri = URIUtil.toURI(path.toOSString()); |
| IStatus locationStatus = workspace.validateProjectLocationURI(getProjectHandle(), |
| uri); |
| if (!locationStatus.isOK()) { |
| return setStatus(locationStatus.getMessage(), MSG_ERROR); |
| } else { |
| // The location is valid as far as Eclipse is concerned (i.e. mostly not |
| // an existing workspace project.) Check it either doesn't exist or is |
| // a directory that is empty. |
| File f = path.toFile(); |
| if (f.exists() && !f.isDirectory()) { |
| return setStatus("A directory name must be specified.", MSG_ERROR); |
| } else if (f.isDirectory()) { |
| // However if the directory exists, we should put a warning if it is not |
| // empty. We don't put an error (we'll ask the user again for confirmation |
| // before using the directory.) |
| String[] l = f.list(); |
| if (l.length != 0) { |
| return setStatus("The selected output directory is not empty.", |
| MSG_WARNING); |
| } |
| } |
| } |
| } else { |
| // Otherwise validate the path string is not empty |
| if (getProjectLocation().length() == 0) { |
| return setStatus("A directory name must be specified.", MSG_ERROR); |
| } |
| |
| File dest = path.append(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); |
| } |
| } |
| } else { |
| // Must be an existing directory |
| File f = path.toFile(); |
| 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); |
| if (!manifestFile.isFile()) { |
| return setStatus( |
| String.format("File %1$s not found in %2$s.", |
| AndroidConstants.FN_ANDROID_MANIFEST, f.getName()), |
| MSG_ERROR); |
| } |
| |
| // Parse it and check the important fields. |
| AndroidManifestParser manifestData = AndroidManifestParser.parseForData(osPath); |
| if (manifestData == null) { |
| return setStatus( |
| String.format("File %1$s could not be parsed.", osPath), |
| MSG_ERROR); |
| } |
| |
| String packageName = manifestData.getPackage(); |
| if (packageName == null || packageName.length() == 0) { |
| return setStatus( |
| String.format("No package name defined in %1$s.", osPath), |
| MSG_ERROR); |
| } |
| |
| 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()) { |
| return setStatus( |
| String.format("No activity name defined in %1$s.", osPath), |
| MSG_ERROR); |
| } |
| } |
| |
| // If there's already a .project, tell the user to use import instead. |
| if (path.append(".project").toFile().exists()) { //$NON-NLS-1$ |
| return setStatus("An Eclipse project already exists in this directory. Consider using File > Import > Existing Project instead.", |
| MSG_WARNING); |
| } |
| } |
| |
| return MSG_NONE; |
| } |
| |
| /** |
| * 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) { |
| return setStatus("An SDK Target must be specified.", MSG_ERROR); |
| } |
| return MSG_NONE; |
| } |
| |
| /** |
| * 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) { |
| return MSG_NONE; |
| } |
| |
| int version = AndroidManifestParser.INVALID_MIN_SDK; |
| try { |
| // If not empty, it must be a valid integer > 0 |
| version = Integer.parseInt(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) { |
| return setStatus("The API level for the selected SDK target does not match the Min SDK version.", |
| MSG_WARNING); |
| } |
| |
| return MSG_NONE; |
| } |
| |
| /** |
| * Validates the activity name field. |
| * |
| * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. |
| */ |
| private int validateActivityField() { |
| // Disregard if not creating an activity |
| if (!isCreateActivity()) { |
| return MSG_NONE; |
| } |
| |
| // Validate activity field |
| String activityFieldContents = 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 = ""; |
| 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, |
| "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ |
| if (!status.isOK()) { |
| result = setStatus(status.getMessage(), |
| status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); |
| } |
| |
| // Check it's a valid package string |
| if (result != MSG_ERROR && packageName.length() > 0) { |
| status = JavaConventions.validatePackageName(packageName, |
| "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ |
| if (!status.isOK()) { |
| result = setStatus(status.getMessage() + " (in the activity name)", |
| status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); |
| } |
| } |
| |
| |
| return result; |
| } |
| |
| /** |
| * Validates the package name field. |
| * |
| * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. |
| */ |
| private int validatePackageField() { |
| // Validate package field |
| String packageFieldContents = getPackageName(); |
| if (packageFieldContents.length() == 0) { |
| return setStatus("Package name must be specified.", MSG_ERROR); |
| } |
| |
| // Check it's a valid package string |
| int result = MSG_NONE; |
| IStatus status = JavaConventions.validatePackageName(packageFieldContents, "1.5", "1.5"); //$NON-NLS-1$ $NON-NLS-2$ |
| if (!status.isOK()) { |
| result = setStatus(status.getMessage(), |
| status.getSeverity() == IStatus.ERROR ? MSG_ERROR : MSG_WARNING); |
| } |
| |
| // The Android Activity Manager does not accept packages names with only one |
| // identifier. Check the package name has at least one dot in them (the previous rule |
| // validated that if such a dot exist, it's not the first nor last characters of the |
| // string.) |
| if (result != MSG_ERROR && packageFieldContents.indexOf('.') == -1) { |
| return setStatus("Package name must have at least two identifiers.", MSG_ERROR); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Validates that an existing project actually has a source folder. |
| * |
| * For project in "use existing source" mode, this tries to find the source folder. |
| * A source folder should be just under the project directory and it should have all |
| * the directories composing the package+activity name. |
| * |
| * As a side effect, it memorizes the source folder in mSourceFolder. |
| * |
| * TODO: support multiple source folders for multiple activities. |
| * |
| * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. |
| */ |
| 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()) { |
| return MSG_NONE; |
| } |
| |
| String osTarget = getActivityName(); |
| |
| if (osTarget.indexOf('.') == -1) { |
| osTarget = getPackageName() + File.separator + osTarget; |
| } else if (osTarget.indexOf('.') == 0) { |
| osTarget = getPackageName() + osTarget; |
| } |
| osTarget = osTarget.replace('.', File.separatorChar) + AndroidConstants.DOT_JAVA; |
| |
| String projectPath = getProjectLocation(); |
| File projectDir = new File(projectPath); |
| File[] all_dirs = projectDir.listFiles(new FileFilter() { |
| public boolean accept(File pathname) { |
| return pathname.isDirectory(); |
| } |
| }); |
| for (File f : all_dirs) { |
| Path path = new Path(f.getAbsolutePath()); |
| File java_activity = path.append(osTarget).toFile(); |
| if (java_activity.isFile()) { |
| mSourceFolder = f.getName(); |
| return MSG_NONE; |
| } |
| } |
| |
| if (all_dirs.length > 0) { |
| return setStatus( |
| String.format("%1$s can not be found under %2$s.", osTarget, projectPath), |
| MSG_ERROR); |
| } else { |
| return setStatus( |
| String.format("No source folders can be found in %1$s.", projectPath), |
| MSG_ERROR); |
| } |
| } |
| |
| /** |
| * Sets the error message for the wizard with the given message icon. |
| * |
| * @param message The wizard message type, one of MSG_ERROR or MSG_WARNING. |
| * @return As a convenience, always returns messageType so that the caller can return |
| * immediately. |
| */ |
| private int setStatus(String message, int messageType) { |
| if (message == null) { |
| setErrorMessage(null); |
| setMessage(null); |
| } else if (!message.equals(getMessage())) { |
| setMessage(message, messageType == MSG_WARNING ? WizardPage.WARNING : WizardPage.ERROR); |
| } |
| return messageType; |
| } |
| |
| } |