Java tutorial
/* * Copyright (C) 2012 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.auidt.internal.wizards.templates; import static com.android.ide.eclipse.auidt.AdtUtils.extractClassName; import static com.android.ide.eclipse.auidt.internal.wizards.templates.NewTemplatePage.WIZARD_PAGE_WIDTH; import com.android.annotations.Nullable; import com.android.ide.eclipse.auidt.AdtPlugin; import com.android.ide.eclipse.auidt.AdtUtils; import com.android.ide.eclipse.auidt.internal.editors.IconFactory; import com.android.ide.eclipse.auidt.internal.sdk.Sdk; import com.android.ide.eclipse.auidt.internal.wizards.newproject.ApplicationInfoPage; import com.android.ide.eclipse.auidt.internal.wizards.newproject.ProjectNamePage; import com.android.sdklib.AndroidVersion; import com.android.sdklib.IAndroidTarget; import com.google.common.collect.Maps; 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.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import lombok.ast.libs.org.parboiled.google.collect.Lists; /** * First wizard page in the "New Project From Template" wizard */ public class NewProjectPage extends WizardPage implements ModifyListener, SelectionListener, FocusListener { private static final String SAMPLE_PACKAGE_PREFIX = "com.example."; //$NON-NLS-1$ /** Suffix added by default to activity names */ static final String ACTIVITY_NAME_SUFFIX = "Activity"; //$NON-NLS-1$ /** Prefix added to default layout names */ static final String LAYOUT_NAME_PREFIX = "activity_"; //$NON-NLS-1$ private static final int INITIAL_MIN_SDK = 8; private final NewProjectWizardState mValues; private Map<String, Integer> mMinNameToApi; private Text mProjectText; private Text mPackageText; private Text mApplicationText; private Combo mMinSdkCombo; private boolean mIgnore; private Combo mBuildSdkCombo; private Button mChooseSdkButton; private Button mCustomIconToggle; private Button mLibraryToggle; private Button mUseDefaultLocationToggle; private Label mLocationLabel; private Text mLocationText; private Button mChooseLocationButton; private static String sLastProjectLocation = System.getProperty("user.home"); //$NON-NLS-1$ private Label mHelpIcon; private Label mTipLabel; private ControlDecoration mApplicationDec; private ControlDecoration mProjectDec; private ControlDecoration mPackageDec; private ControlDecoration mBuildTargetDec; private ControlDecoration mMinSdkDec; NewProjectPage(NewProjectWizardState values) { super("newAndroidApp"); //$NON-NLS-1$ mValues = values; setTitle("New Android Application"); setDescription("Creates a new Android Application"); } @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused @Override public void createControl(Composite parent) { Composite container = new Composite(parent, SWT.NULL); setControl(container); GridLayout gl_container = new GridLayout(4, false); gl_container.horizontalSpacing = 10; container.setLayout(gl_container); Label applicationLabel = new Label(container, SWT.NONE); applicationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); applicationLabel.setText("Application Name:"); mApplicationText = new Text(container, SWT.BORDER); mApplicationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); mApplicationText.addModifyListener(this); mApplicationText.addFocusListener(this); mApplicationDec = createFieldDecoration(mApplicationText, "The application name is shown in the Play Store, as well as in the " + "Manage Application list in Settings."); Label projectLabel = new Label(container, SWT.NONE); projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); projectLabel.setText("Project Name:"); mProjectText = new Text(container, SWT.BORDER); mProjectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); mProjectText.addModifyListener(this); mProjectText.addFocusListener(this); mProjectDec = createFieldDecoration(mProjectText, "The project name is only used by Eclipse, but must be unique within the " + "workspace. This can typically be the same as the application name."); Label packageLabel = new Label(container, SWT.NONE); packageLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); packageLabel.setText("Package Name:"); mPackageText = new Text(container, SWT.BORDER); mPackageText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); mPackageText.addModifyListener(this); mPackageText.addFocusListener(this); mPackageDec = createFieldDecoration(mPackageText, "The package name must be a unique identifier for your application.\n" + "It is typically not shown to users, but it *must* stay the same " + "for the lifetime of your application; it is how multiple versions " + "of the same application are considered the \"same app\".\nThis is " + "typically the reverse domain name of your organization plus one or " + "more application identifiers, and it must be a valid Java package " + "name."); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); Label buildSdkLabel = new Label(container, SWT.NONE); buildSdkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); buildSdkLabel.setText("Build SDK:"); mBuildSdkCombo = new Combo(container, SWT.READ_ONLY); mBuildSdkCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); IAndroidTarget[] targets = getCompilationTargets(); mMinNameToApi = Maps.newHashMap(); List<String> labels = new ArrayList<String>(targets.length); for (IAndroidTarget target : targets) { String targetLabel = String.format("%1$s (API %2$s)", target.getFullName(), target.getVersion().getApiString()); labels.add(targetLabel); mMinNameToApi.put(targetLabel, target.getVersion().getApiLevel()); } mBuildSdkCombo.setData(targets); mBuildSdkCombo.setItems(labels.toArray(new String[labels.size()])); // Pick most recent platform List<String> codeNames = Lists.newArrayList(); int selectIndex = -1; for (int i = 0, n = targets.length; i < n; i++) { IAndroidTarget target = targets[i]; AndroidVersion version = target.getVersion(); int apiLevel = version.getApiLevel(); if (version.isPreview()) { String codeName = version.getCodename(); String targetLabel = codeName + " Preview"; codeNames.add(targetLabel); mMinNameToApi.put(targetLabel, apiLevel); } else if (target.isPlatform() && (mValues.target == null || apiLevel > mValues.target.getVersion().getApiLevel())) { mValues.target = target; selectIndex = i; } } if (selectIndex != -1) { mBuildSdkCombo.select(selectIndex); } mBuildSdkCombo.addSelectionListener(this); mBuildSdkCombo.addFocusListener(this); mBuildTargetDec = createFieldDecoration(mBuildSdkCombo, "Choose a target API to compile your code against. This is typically the most " + "recent version, or the first version that supports all the APIs you want to " + "directly access"); mChooseSdkButton = new Button(container, SWT.NONE); mChooseSdkButton.setText("Choose..."); mChooseSdkButton.addSelectionListener(this); mChooseSdkButton.setEnabled(false); Label minSdkLabel = new Label(container, SWT.NONE); minSdkLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); minSdkLabel.setText("Minimum Required SDK:"); mMinSdkCombo = new Combo(container, SWT.READ_ONLY); mMinSdkCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); labels = new ArrayList<String>(24); for (String label : AdtUtils.getKnownVersions()) { labels.add(label); } assert labels.size() >= 15; // *Known* versions to ADT, not installed/available versions for (String codeName : codeNames) { labels.add(codeName); } String[] versions = labels.toArray(new String[labels.size()]); mMinSdkCombo.setItems(versions); if (mValues.target != null && mValues.target.getVersion().isPreview()) { mValues.minSdk = mValues.target.getVersion().getCodename(); mMinSdkCombo.setText(mValues.minSdk); mValues.iconState.minSdk = mValues.target.getVersion().getApiLevel(); mValues.minSdkLevel = mValues.iconState.minSdk; } else { mMinSdkCombo.select(INITIAL_MIN_SDK - 1); mValues.minSdk = Integer.toString(INITIAL_MIN_SDK); mValues.minSdkLevel = INITIAL_MIN_SDK; mValues.iconState.minSdk = INITIAL_MIN_SDK; } mMinSdkCombo.addSelectionListener(this); mMinSdkCombo.addFocusListener(this); mMinSdkDec = createFieldDecoration(mMinSdkCombo, "Choose the lowest version of Android that your application will support. Lower " + "API levels target more devices, but means fewer features are available. By " + "targeting API 8 and later, you reach approximately 93% of the market."); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); new Label(container, SWT.NONE); mCustomIconToggle = new Button(container, SWT.CHECK); mCustomIconToggle.setSelection(true); mCustomIconToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); mCustomIconToggle.setText("Create custom launcher icon"); mCustomIconToggle.setSelection(mValues.createIcon); mCustomIconToggle.addSelectionListener(this); mLibraryToggle = new Button(container, SWT.CHECK); mLibraryToggle.setSelection(true); mLibraryToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); mLibraryToggle.setText("Mark this project as a library"); mLibraryToggle.setSelection(mValues.isLibrary); mLibraryToggle.addSelectionListener(this); mUseDefaultLocationToggle = new Button(container, SWT.CHECK); mUseDefaultLocationToggle.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); mUseDefaultLocationToggle.setText("Create Project in Workspace"); mUseDefaultLocationToggle.addSelectionListener(this); mLocationLabel = new Label(container, SWT.NONE); mLocationLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 2, 1)); mLocationLabel.setText("Location:"); mLocationText = new Text(container, SWT.BORDER); mLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); mLocationText.addModifyListener(this); mChooseLocationButton = new Button(container, SWT.NONE); mChooseLocationButton.setText("Browse..."); mChooseLocationButton.addSelectionListener(this); mChooseLocationButton.setEnabled(false); setUseCustomLocation(false); Label label = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 4, 1)); mHelpIcon = new Label(container, SWT.NONE); mHelpIcon.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1)); Image icon = IconFactory.getInstance().getIcon("quickfix"); mHelpIcon.setImage(icon); mHelpIcon.setVisible(false); mTipLabel = new Label(container, SWT.WRAP); mTipLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); // Reserve space for 4 lines mTipLabel.setText("\n\n\n\n"); //$NON-NLS-1$ // Reserve enough width to accommodate the various wizard pages up front // (since they are created lazily, and we don't want the wizard to dynamically // resize itself for small size adjustments as each successive page is slightly // larger) Label dummy = new Label(container, SWT.NONE); GridData data = new GridData(); data.horizontalSpan = 4; data.widthHint = WIZARD_PAGE_WIDTH; dummy.setLayoutData(data); } private IAndroidTarget[] getCompilationTargets() { Sdk current = Sdk.getCurrent(); if (current == null) { return new IAndroidTarget[0]; } IAndroidTarget[] targets = current.getTargets(); List<IAndroidTarget> list = new ArrayList<IAndroidTarget>(); for (IAndroidTarget target : targets) { if (target.isPlatform() == false && (target.getOptionalLibraries() == null || target.getOptionalLibraries().length == 0)) { continue; } list.add(target); } return list.toArray(new IAndroidTarget[list.size()]); } private ControlDecoration createFieldDecoration(Control control, String description) { ControlDecoration dec = new ControlDecoration(control, SWT.LEFT); dec.setMarginWidth(2); FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault() .getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION); dec.setImage(errorFieldIndicator.getImage()); dec.setDescriptionText(description); control.setToolTipText(description); return dec; } @Override public void setVisible(boolean visible) { super.setVisible(visible); // DURING DEVELOPMENT ONLY //if (assertionsEnabled()) { // String uniqueProjectName = AdtUtils.getUniqueProjectName("Test", ""); // mProjectText.setText(uniqueProjectName); // mPackageText.setText("test.pkg"); //} validatePage(); } private void setUseCustomLocation(boolean en) { mUseDefaultLocationToggle.setSelection(!en); if (!en) { updateProjectLocation(mValues.projectName); } mLocationLabel.setEnabled(en); mLocationText.setEnabled(en); mChooseLocationButton.setEnabled(en); } // ---- Implements ModifyListener ---- @Override public void modifyText(ModifyEvent e) { if (mIgnore) { return; } Object source = e.getSource(); if (source == mProjectText) { mValues.projectName = mProjectText.getText(); updateProjectLocation(mValues.projectName); mValues.projectModified = true; try { mIgnore = true; if (!mValues.applicationModified) { mValues.applicationName = mValues.projectName; mApplicationText.setText(mValues.projectName); } updateActivityNames(mValues.projectName); } finally { mIgnore = false; } suggestPackage(mValues.projectName); } else if (source == mPackageText) { mValues.packageName = mPackageText.getText(); mValues.packageModified = true; } else if (source == mApplicationText) { mValues.applicationName = mApplicationText.getText(); mValues.applicationModified = true; try { mIgnore = true; if (!mValues.projectModified) { mValues.projectName = appNameToProjectName(mValues.applicationName); mProjectText.setText(mValues.projectName); updateProjectLocation(mValues.projectName); } updateActivityNames(mValues.applicationName); } finally { mIgnore = false; } suggestPackage(mValues.applicationName); } else if (source == mLocationText) { mValues.projectLocation = mLocationText.getText().trim(); } validatePage(); } private String appNameToProjectName(String appName) { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IStatus nameStatus = workspace.validateName(appName, IResource.PROJECT); if (nameStatus.isOK()) { return appName; } StringBuilder sb = new StringBuilder(appName.length()); for (int i = 0, n = appName.length(); i < n; i++) { char c = appName.charAt(i); if (Character.isLetterOrDigit(c) || c == '.' || c == '-' || c == ' ') { sb.append(c); } } return sb.toString().trim(); } /** If the project should be created in the workspace, then update the project location * based on the project name. */ private void updateProjectLocation(String projectName) { if (projectName == null) { projectName = ""; } boolean useDefaultLocation = mUseDefaultLocationToggle.getSelection(); if (useDefaultLocation) { IPath workspace = Platform.getLocation(); String projectLocation = workspace.append(projectName).toOSString(); mLocationText.setText(projectLocation); mValues.projectLocation = projectLocation; } } private void updateActivityNames(String name) { try { mIgnore = true; if (!mValues.activityNameModified) { mValues.activityName = extractClassName(name) + ACTIVITY_NAME_SUFFIX; } if (!mValues.activityTitleModified) { mValues.activityTitle = name; } } finally { mIgnore = false; } } // ---- Implements SelectionListener ---- @Override public void widgetSelected(SelectionEvent e) { if (mIgnore) { return; } Object source = e.getSource(); if (source == mChooseSdkButton) { // TODO: Open SDK chooser assert false; } else if (source == mMinSdkCombo) { mValues.minSdk = getSelectedMinSdk(); // If higher than build target, adjust build target // TODO: implement Integer minSdk = mMinNameToApi.get(mValues.minSdk); if (minSdk == null) { try { minSdk = Integer.parseInt(mValues.minSdk); } catch (NumberFormatException nufe) { minSdk = 1; } } mValues.iconState.minSdk = minSdk.intValue(); mValues.minSdkLevel = minSdk.intValue(); } else if (source == mBuildSdkCombo) { mValues.target = getSelectedBuildTarget(); // If lower than min sdk target, adjust min sdk target if (mValues.target.getVersion().isPreview()) { mValues.minSdk = mValues.target.getVersion().getCodename(); try { mIgnore = true; mMinSdkCombo.setText(mValues.minSdk); } finally { mIgnore = false; } } else { String minSdk = mValues.minSdk; int buildApiLevel = mValues.target.getVersion().getApiLevel(); if (minSdk != null && !minSdk.isEmpty() && Character.isDigit(minSdk.charAt(0)) && buildApiLevel < Integer.parseInt(minSdk)) { mValues.minSdk = Integer.toString(buildApiLevel); try { mIgnore = true; setSelectedMinSdk(buildApiLevel); } finally { mIgnore = false; } } } } else if (source == mCustomIconToggle) { mValues.createIcon = mCustomIconToggle.getSelection(); } else if (source == mLibraryToggle) { mValues.isLibrary = mLibraryToggle.getSelection(); } else if (source == mUseDefaultLocationToggle) { boolean useDefault = mUseDefaultLocationToggle.getSelection(); setUseCustomLocation(!useDefault); } else if (source == mChooseLocationButton) { String dir = promptUserForLocation(getShell()); if (dir != null) { mLocationText.setText(dir); mValues.projectLocation = dir; } } validatePage(); } private String promptUserForLocation(Shell shell) { DirectoryDialog dd = new DirectoryDialog(getShell()); dd.setMessage("Select folder where project should be created"); String curLocation = mLocationText.getText().trim(); if (!curLocation.isEmpty()) { dd.setFilterPath(curLocation); } else if (sLastProjectLocation != null) { dd.setFilterPath(sLastProjectLocation); } String dir = dd.open(); if (dir != null) { sLastProjectLocation = dir; } return dir; } private String getSelectedMinSdk() { // If you're using a preview build, such as android-JellyBean, you have // to use the codename, e.g. JellyBean, as the minimum SDK as well. IAndroidTarget buildTarget = getSelectedBuildTarget(); if (buildTarget != null && buildTarget.getVersion().isPreview()) { return buildTarget.getVersion().getCodename(); } // +1: First API level (at index 0) is 1 return Integer.toString(mMinSdkCombo.getSelectionIndex() + 1); } private void setSelectedMinSdk(int api) { mMinSdkCombo.select(api - 1); // -1: First API level (at index 0) is 1 } @Nullable private IAndroidTarget getSelectedBuildTarget() { IAndroidTarget[] targets = (IAndroidTarget[]) mBuildSdkCombo.getData(); int index = mBuildSdkCombo.getSelectionIndex(); if (index >= 0 && index < targets.length) { return targets[index]; } else { return null; } } private void suggestPackage(String original) { if (!mValues.packageModified) { // Create default package name StringBuilder sb = new StringBuilder(); sb.append(SAMPLE_PACKAGE_PREFIX); appendPackage(sb, original); mValues.packageName = sb.toString(); try { mIgnore = true; mPackageText.setText(mValues.packageName); } finally { mIgnore = false; } } } private static void appendPackage(StringBuilder sb, String string) { for (int i = 0, n = string.length(); i < n; i++) { char c = string.charAt(i); if (i == 0 && Character.isJavaIdentifierStart(c) || i != 0 && Character.isJavaIdentifierPart(c)) { sb.append(Character.toLowerCase(c)); } else if ((c == '.' || c == ' ') && (sb.length() > 0 && sb.charAt(sb.length() - 1) != '.')) { sb.append('.'); } else if (c == '-') { sb.append('_'); } } } @Override public void widgetDefaultSelected(SelectionEvent e) { } // ---- Implements FocusListener ---- @Override public void focusGained(FocusEvent e) { Object source = e.getSource(); String tip = ""; if (source == mApplicationText) { tip = mApplicationDec.getDescriptionText(); } else if (source == mProjectText) { tip = mProjectDec.getDescriptionText(); } else if (source == mBuildSdkCombo) { tip = mBuildTargetDec.getDescriptionText(); } else if (source == mMinSdkCombo) { tip = mMinSdkDec.getDescriptionText(); } else if (source == mPackageText) { tip = mPackageDec.getDescriptionText(); if (mPackageText.getText().startsWith(SAMPLE_PACKAGE_PREFIX)) { int length = SAMPLE_PACKAGE_PREFIX.length(); if (mPackageText.getText().length() > length && SAMPLE_PACKAGE_PREFIX.endsWith(".")) { //$NON-NLS-1$ length--; } mPackageText.setSelection(0, length); } } mTipLabel.setText(tip); mHelpIcon.setVisible(tip.length() > 0); } @Override public void focusLost(FocusEvent e) { mTipLabel.setText(""); mHelpIcon.setVisible(false); } // Validation private void validatePage() { IStatus status = mValues.template.validateTemplate(mValues.minSdkLevel); if (status != null && !status.isOK()) { updateDecorator(mApplicationDec, null, true); updateDecorator(mPackageDec, null, true); updateDecorator(mProjectDec, null, true); } else { IStatus appStatus = validateAppName(); if (appStatus != null && (status == null || appStatus.getSeverity() > status.getSeverity())) { status = appStatus; } IStatus projectStatus = validateProjectName(); if (projectStatus != null && (status == null || projectStatus.getSeverity() > status.getSeverity())) { status = projectStatus; } IStatus packageStatus = validatePackageName(); if (packageStatus != null && (status == null || packageStatus.getSeverity() > status.getSeverity())) { status = packageStatus; } IStatus locationStatus = validateProjectLocation(); if (locationStatus != null && (status == null || locationStatus.getSeverity() > status.getSeverity())) { status = locationStatus; } if (status == null || status.getSeverity() != IStatus.ERROR) { if (mValues.target == null) { status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, "Select an Android build target version"); } } if (status == null || status.getSeverity() != IStatus.ERROR) { if (mValues.minSdk == null || mValues.minSdk.isEmpty()) { status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, "Select a minimum SDK version"); } else { AndroidVersion version = mValues.target.getVersion(); if (version.isPreview()) { if (version.getCodename().equals(mValues.minSdk) == false) { status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Preview platforms require the min SDK version to match their codenames."); } } else if (mValues.target.getVersion().compareTo(mValues.minSdkLevel, version.isPreview() ? mValues.minSdk : null) < 0) { status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, "The minimum SDK version is higher than the build target version"); } } } } setPageComplete(status == null || status.getSeverity() != IStatus.ERROR); if (status != null) { setMessage(status.getMessage(), status.getSeverity() == IStatus.ERROR ? IMessageProvider.ERROR : IMessageProvider.WARNING); } else { setErrorMessage(null); setMessage(null); } } private IStatus validateAppName() { String appName = mValues.applicationName; IStatus status = null; if (appName == null || appName.isEmpty()) { status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Enter an application name (shown in launcher)"); } else if (Character.isLowerCase(mValues.applicationName.charAt(0))) { status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, "The application name for most apps begins with an uppercase letter"); } updateDecorator(mApplicationDec, status, true); return status; } private IStatus validateProjectName() { IStatus status = ProjectNamePage.validateProjectName(mValues.projectName); updateDecorator(mProjectDec, status, true); return status; } private IStatus validatePackageName() { IStatus status; if (mValues.packageName == null || mValues.packageName.startsWith(SAMPLE_PACKAGE_PREFIX)) { if (mValues.packageName != null && !mValues.packageName.equals(SAMPLE_PACKAGE_PREFIX)) { status = ApplicationInfoPage.validatePackage(mValues.packageName); if (status == null || status.isOK()) { status = new Status(IStatus.WARNING, AdtPlugin.PLUGIN_ID, String.format("The prefix '%1$s' is meant as a placeholder and should " + "not be used", SAMPLE_PACKAGE_PREFIX)); } } else { status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Package name must be specified."); } } else { status = ApplicationInfoPage.validatePackage(mValues.packageName); } updateDecorator(mPackageDec, status, true); return status; } private IStatus validateLocationInWorkspace() { // Validate location if (mValues.projectName != null) { File dest = Platform.getLocation().append(mValues.projectName).toFile(); if (dest.exists()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format( "There is already a file or directory named \"%1$s\" in the selected location.", mValues.projectName)); } } return null; } private IStatus validateProjectLocation() { if (mUseDefaultLocationToggle.getSelection()) { return validateLocationInWorkspace(); } String location = mLocationText.getText(); if (location.trim().isEmpty()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "Provide a valid file system location where the project should be created."); } File f = new File(location); if (f.exists()) { if (!f.isDirectory()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format("'%s' is not a valid folder.", location)); } File[] children = f.listFiles(); if (children != null && children.length > 0) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format("Folder '%s' is not empty.", location)); } } // if the folder doesn't exist, then make sure that the parent // exists and is a writeable folder File parent = f.getParentFile(); if (!parent.exists()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format("Folder '%s' does not exist.", parent.getName())); } if (!parent.isDirectory()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format("'%s' is not a folder.", parent.getName())); } if (!parent.canWrite()) { return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format("'%s' is not writeable.", parent.getName())); } return null; } private void updateDecorator(ControlDecoration decorator, IStatus status, boolean hasInfo) { if (hasInfo) { int severity = status != null ? status.getSeverity() : IStatus.OK; setDecoratorType(decorator, severity); } else { if (status == null || status.isOK()) { decorator.hide(); } else { decorator.show(); } } } private void setDecoratorType(ControlDecoration decorator, int severity) { String id; if (severity == IStatus.ERROR) { id = FieldDecorationRegistry.DEC_ERROR; } else if (severity == IStatus.WARNING) { id = FieldDecorationRegistry.DEC_WARNING; } else { id = FieldDecorationRegistry.DEC_INFORMATION; } FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault().getFieldDecoration(id); decorator.setImage(errorFieldIndicator.getImage()); } }