aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java946
1 files changed, 946 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
new file mode 100644
index 000000000..57cf5c824
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java
@@ -0,0 +1,946 @@
+/*
+ * 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.adt.internal.wizards.templates;
+
+import static com.android.SdkConstants.CLASS_ACTIVITY;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_API;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_MIN_BUILD_API;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DEFAULT;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_ID;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING;
+import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl;
+import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectChooserHelper.ProjectCombo;
+import com.android.ide.eclipse.adt.internal.wizards.templates.Parameter.Constraint;
+import com.android.ide.eclipse.adt.internal.wizards.templates.Parameter.Type;
+import com.android.tools.lint.detector.api.LintUtils;
+import com.google.common.collect.Lists;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.ui.IJavaElementSearchConstants;
+import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.ui.dialogs.ITypeInfoFilterExtension;
+import org.eclipse.jdt.ui.dialogs.ITypeInfoRequestor;
+import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.SelectionDialog;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * First wizard page in the "New Project From Template" wizard (which is parameterized
+ * via template.xml files)
+ */
+public class NewTemplatePage extends WizardPage
+ implements ModifyListener, SelectionListener, FocusListener {
+ /** The default width to use for the wizard page */
+ static final int WIZARD_PAGE_WIDTH = 600;
+
+ private final NewTemplateWizardState mValues;
+ private final boolean mChooseProject;
+ private int mCustomMinSdk = -1;
+ private int mCustomBuildApi = -1;
+ private boolean mIgnore;
+ private boolean mShown;
+ private Control mFirst;
+ // TODO: Move decorators to the Parameter objects?
+ private Map<String, ControlDecoration> mDecorations = new HashMap<String, ControlDecoration>();
+ private Label mHelpIcon;
+ private Label mTipLabel;
+ private ImageControl mPreview;
+ private Image mPreviewImage;
+ private boolean mDisposePreviewImage;
+ private ProjectCombo mProjectButton;
+ private StringEvaluator mEvaluator;
+
+ private TemplateMetadata mShowingTemplate;
+
+ /**
+ * Creates a new {@link NewTemplatePage}
+ *
+ * @param values the wizard state
+ * @param chooseProject whether the wizard should present a project chooser,
+ * and update {@code values}' project field
+ */
+ NewTemplatePage(NewTemplateWizardState values, boolean chooseProject) {
+ super("newTemplatePage"); //$NON-NLS-1$
+ mValues = values;
+ mChooseProject = chooseProject;
+ }
+
+ /**
+ * @param minSdk a minimum SDK to use, provided chooseProject is false. If
+ * it is true, then the minimum SDK used for validation will be
+ * the one of the project
+ * @param buildApi the build API to use
+ */
+ void setCustomMinSdk(int minSdk, int buildApi) {
+ assert !mChooseProject;
+ //assert buildApi >= minSdk;
+ mCustomMinSdk = minSdk;
+ mCustomBuildApi = buildApi;
+ }
+
+ @Override
+ public void createControl(Composite parent2) {
+ Composite parent = new Composite(parent2, SWT.NULL);
+ setControl(parent);
+ GridLayout parentLayout = new GridLayout(3, false);
+ parentLayout.verticalSpacing = 0;
+ parentLayout.marginWidth = 0;
+ parentLayout.marginHeight = 0;
+ parentLayout.horizontalSpacing = 0;
+ parent.setLayout(parentLayout);
+
+ // Reserve enough width (since the panel is created lazily later)
+ Label label = new Label(parent, SWT.NONE);
+ GridData data = new GridData();
+ data.widthHint = WIZARD_PAGE_WIDTH;
+ label.setLayoutData(data);
+ }
+
+ @SuppressWarnings("unused") // SWT constructors have side effects and aren't unused
+ private void onEnter() {
+ TemplateMetadata template = mValues.getTemplateHandler().getTemplate();
+ if (template == mShowingTemplate) {
+ return;
+ }
+ mShowingTemplate = template;
+
+ Composite parent = (Composite) getControl();
+
+ Control[] children = parent.getChildren();
+ if (children.length > 0) {
+ for (Control c : parent.getChildren()) {
+ c.dispose();
+ }
+ for (ControlDecoration decoration : mDecorations.values()) {
+ decoration.dispose();
+ }
+ mDecorations.clear();
+ }
+
+ Composite container = new Composite(parent, SWT.NULL);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ GridLayout gl_container = new GridLayout(3, false);
+ gl_container.horizontalSpacing = 10;
+ container.setLayout(gl_container);
+
+ if (mChooseProject) {
+ // Project: [button]
+ String tooltip = "The Android Project where the new resource will be created.";
+ Label projectLabel = new Label(container, SWT.NONE);
+ projectLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ projectLabel.setText("Project:");
+ projectLabel.setToolTipText(tooltip);
+
+ ProjectChooserHelper helper =
+ new ProjectChooserHelper(getShell(), null /* filter */);
+ mProjectButton = new ProjectCombo(helper, container, mValues.project);
+ mProjectButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ mProjectButton.setToolTipText(tooltip);
+ mProjectButton.addSelectionListener(this);
+
+ //Label projectSeparator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
+ //projectSeparator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
+ }
+
+ // Add parameters
+ mFirst = null;
+ String thumb = null;
+ if (template != null) {
+ thumb = template.getThumbnailPath();
+ String title = template.getTitle();
+ if (title != null && !title.isEmpty()) {
+ setTitle(title);
+ }
+ String description = template.getDescription();
+ if (description != null && !description.isEmpty()) {
+ setDescription(description);
+ }
+
+ Map<String, String> defaults = mValues.defaults;
+ Set<String> seen = null;
+ if (LintUtils.assertionsEnabled()) {
+ seen = new HashSet<String>();
+ }
+
+ List<Parameter> parameters = template.getParameters();
+ for (Parameter parameter : parameters) {
+ Parameter.Type type = parameter.type;
+
+ if (type == Parameter.Type.SEPARATOR) {
+ Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
+ separator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1));
+ continue;
+ }
+
+ String id = parameter.id;
+ assert id != null && !id.isEmpty() : ATTR_ID;
+ Object value = defaults.get(id);
+ if (value == null) {
+ value = parameter.value;
+ }
+
+ String name = parameter.name;
+ String help = parameter.help;
+
+ // Required
+ assert name != null && !name.isEmpty() : ATTR_NAME;
+ // Ensure id's are unique:
+ assert seen != null && seen.add(id) : id;
+
+ // Skip attributes that were already provided by the surrounding
+ // context. For example, when adding into an existing project,
+ // provide the minimum SDK automatically from the project.
+ if (mValues.hidden != null && mValues.hidden.contains(id)) {
+ continue;
+ }
+
+ switch (type) {
+ case STRING: {
+ // TODO: Look at the constraints to add validators here
+ // TODO: If I type.equals("layout") add resource validator for layout
+ // names
+ // TODO: If I type.equals("class") make class validator
+
+ // TODO: Handle package and id better later
+ Label label = new Label(container, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false,
+ 1, 1));
+ label.setText(name);
+
+ Text text = new Text(container, SWT.BORDER);
+ text.setData(parameter);
+ parameter.control = text;
+
+ if (parameter.constraints.contains(Constraint.EXISTS)) {
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 1, 1));
+
+ Button button = new Button(container, SWT.FLAT);
+ button.setData(parameter);
+ button.setText("...");
+ button.addSelectionListener(this);
+ } else {
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 2, 1));
+ }
+
+ boolean hasValue = false;
+ if (value instanceof String) {
+ String stringValue = (String) value;
+ hasValue = !stringValue.isEmpty();
+ text.setText(stringValue);
+ mValues.parameters.put(id, value);
+ }
+
+ if (!hasValue) {
+ if (parameter.constraints.contains(Constraint.EMPTY)) {
+ text.setMessage("Optional");
+ } else if (parameter.constraints.contains(Constraint.NONEMPTY)) {
+ text.setMessage("Required");
+ }
+ }
+
+ text.addModifyListener(this);
+ text.addFocusListener(this);
+
+ if (mFirst == null) {
+ mFirst = text;
+ }
+
+ if (help != null && !help.isEmpty()) {
+ text.setToolTipText(help);
+ ControlDecoration decoration = createFieldDecoration(id, text, help);
+ }
+ break;
+ }
+ case BOOLEAN: {
+ Label label = new Label(container, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false,
+ 1, 1));
+
+ Button checkBox = new Button(container, SWT.CHECK);
+ checkBox.setText(name);
+ checkBox.setData(parameter);
+ parameter.control = checkBox;
+ checkBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 2, 1));
+
+ if (value instanceof Boolean) {
+ Boolean selected = (Boolean) value;
+ checkBox.setSelection(selected);
+ mValues.parameters.put(id, value);
+ }
+
+ checkBox.addSelectionListener(this);
+ checkBox.addFocusListener(this);
+
+ if (mFirst == null) {
+ mFirst = checkBox;
+ }
+
+ if (help != null && !help.isEmpty()) {
+ checkBox.setToolTipText(help);
+ ControlDecoration decoration = createFieldDecoration(id, checkBox,
+ help);
+ }
+ break;
+ }
+ case ENUM: {
+ Label label = new Label(container, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false,
+ 1, 1));
+ label.setText(name);
+
+ Combo combo = createOptionCombo(parameter, container, mValues.parameters,
+ this, this);
+ combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
+ 2, 1));
+
+ if (mFirst == null) {
+ mFirst = combo;
+ }
+
+ if (help != null && !help.isEmpty()) {
+ ControlDecoration decoration = createFieldDecoration(id, combo, help);
+ }
+ break;
+ }
+ case SEPARATOR:
+ // Already handled above
+ assert false : type;
+ break;
+ default:
+ assert false : type;
+ }
+ }
+ }
+
+ // Preview
+ mPreview = new ImageControl(parent, SWT.NONE, null);
+ mPreview.setDisposeImage(false); // Handled manually in this class
+ GridData gd_mImage = new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1);
+ gd_mImage.widthHint = PREVIEW_WIDTH + 2 * PREVIEW_PADDING;
+ mPreview.setLayoutData(gd_mImage);
+
+ Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
+ GridData separatorData = new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1);
+ separatorData.heightHint = 16;
+ separator.setLayoutData(separatorData);
+
+ // Generic help
+ mHelpIcon = new Label(parent, 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(parent, SWT.WRAP);
+ mTipLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+ setPreview(thumb);
+
+ parent.layout(true, true);
+ // TODO: This is a workaround for the fact that (at least on OSX) you end up
+ // with some visual artifacts from the control decorations in the upper left corner
+ // (outside the parent widget itself) from the initial control decoration placement
+ // prior to layout. Therefore, perform a redraw. A better solution would be to
+ // delay creation of the control decorations until layout has been performed.
+ // Let's do that soon.
+ parent.getParent().redraw();
+ }
+
+ @NonNull
+ static Combo createOptionCombo(
+ @NonNull Parameter parameter,
+ @NonNull Composite container,
+ @NonNull Map<String, Object> valueMap,
+ @NonNull SelectionListener selectionListener,
+ @NonNull FocusListener focusListener) {
+ Combo combo = new Combo(container, SWT.READ_ONLY);
+
+ List<Element> options = parameter.getOptions();
+ assert options.size() > 0;
+ int selected = 0;
+ List<String> ids = Lists.newArrayList();
+ List<Integer> minSdks = Lists.newArrayList();
+ List<Integer> minBuildApis = Lists.newArrayList();
+ List<String> labels = Lists.newArrayList();
+ for (int i = 0, n = options.size(); i < n; i++) {
+ Element option = options.get(i);
+ String optionId = option.getAttribute(ATTR_ID);
+ assert optionId != null && !optionId.isEmpty() : ATTR_ID;
+ String isDefault = option.getAttribute(ATTR_DEFAULT);
+ if (isDefault != null && !isDefault.isEmpty() &&
+ Boolean.valueOf(isDefault)) {
+ selected = i;
+ }
+ NodeList childNodes = option.getChildNodes();
+ assert childNodes.getLength() == 1 &&
+ childNodes.item(0).getNodeType() == Node.TEXT_NODE;
+ String optionLabel = childNodes.item(0).getNodeValue().trim();
+
+ String minApiString = option.getAttribute(ATTR_MIN_API);
+ int minSdk = 1;
+ if (minApiString != null && !minApiString.isEmpty()) {
+ try {
+ minSdk = Integer.parseInt(minApiString);
+ } catch (NumberFormatException nufe) {
+ // Templates aren't allowed to contain codenames, should
+ // always be an integer
+ AdtPlugin.log(nufe, null);
+ minSdk = 1;
+ }
+ }
+ String minBuildApiString = option.getAttribute(ATTR_MIN_BUILD_API);
+ int minBuildApi = 1;
+ if (minBuildApiString != null && !minBuildApiString.isEmpty()) {
+ try {
+ minBuildApi = Integer.parseInt(minBuildApiString);
+ } catch (NumberFormatException nufe) {
+ // Templates aren't allowed to contain codenames, should
+ // always be an integer
+ AdtPlugin.log(nufe, null);
+ minBuildApi = 1;
+ }
+ }
+ minSdks.add(minSdk);
+ minBuildApis.add(minBuildApi);
+ ids.add(optionId);
+ labels.add(optionLabel);
+ }
+ combo.setData(parameter);
+ parameter.control = combo;
+ combo.setData(ATTR_ID, ids.toArray(new String[ids.size()]));
+ combo.setData(ATTR_MIN_API, minSdks.toArray(new Integer[minSdks.size()]));
+ combo.setData(ATTR_MIN_BUILD_API, minBuildApis.toArray(
+ new Integer[minBuildApis.size()]));
+ assert labels.size() > 0;
+ combo.setItems(labels.toArray(new String[labels.size()]));
+ combo.select(selected);
+
+ combo.addSelectionListener(selectionListener);
+ combo.addFocusListener(focusListener);
+
+ valueMap.put(parameter.id, ids.get(selected));
+
+ if (parameter.help != null && !parameter.help.isEmpty()) {
+ combo.setToolTipText(parameter.help);
+ }
+
+ return combo;
+ }
+
+ private void setPreview(String thumb) {
+ Image oldImage = mPreviewImage;
+ boolean dispose = mDisposePreviewImage;
+ mPreviewImage = null;
+
+ if (thumb == null || thumb.isEmpty()) {
+ mPreviewImage = TemplateMetadata.getDefaultTemplateIcon();
+ mDisposePreviewImage = false;
+ } else {
+ byte[] data = mValues.getTemplateHandler().readTemplateResource(thumb);
+ if (data != null) {
+ try {
+ mPreviewImage = new Image(getControl().getDisplay(),
+ new ByteArrayInputStream(data));
+ mDisposePreviewImage = true;
+ } catch (Exception e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+ if (mPreviewImage == null) {
+ return;
+ }
+ }
+
+ mPreview.setImage(mPreviewImage);
+ mPreview.fitToWidth(PREVIEW_WIDTH);
+
+ if (oldImage != null && dispose) {
+ oldImage.dispose();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ if (mPreviewImage != null && mDisposePreviewImage) {
+ mDisposePreviewImage = false;
+ mPreviewImage.dispose();
+ mPreviewImage = null;
+ }
+ }
+
+ private ControlDecoration createFieldDecoration(String id, Control control,
+ String description) {
+ ControlDecoration decoration = new ControlDecoration(control, SWT.LEFT);
+ decoration.setMarginWidth(2);
+ FieldDecoration errorFieldIndicator = FieldDecorationRegistry.getDefault().
+ getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION);
+ decoration.setImage(errorFieldIndicator.getImage());
+ decoration.setDescriptionText(description);
+ control.setToolTipText(description);
+ mDecorations.put(id, decoration);
+
+ return decoration;
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ // Force user to reach this page before hitting Finish
+ return mShown && super.isPageComplete();
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ onEnter();
+ }
+
+ super.setVisible(visible);
+
+ if (mFirst != null) {
+ mFirst.setFocus();
+ }
+
+ if (visible) {
+ mShown = true;
+ }
+
+ validatePage();
+ }
+
+ /** Returns the parameter associated with the given control */
+ @Nullable
+ static Parameter getParameter(Control control) {
+ return (Parameter) control.getData();
+ }
+
+ /**
+ * Returns the current string evaluator, if any
+ *
+ * @return the evaluator or null
+ */
+ @Nullable
+ public StringEvaluator getEvaluator() {
+ return mEvaluator;
+ }
+
+ // ---- Validation ----
+
+ private void validatePage() {
+ int minSdk = getMinSdk();
+ int buildApi = getBuildApi();
+ IStatus status = mValues.getTemplateHandler().validateTemplate(minSdk, buildApi);
+
+ if (status == null || status.isOK()) {
+ if (mChooseProject && mValues.project == null) {
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ "Please select an Android project.");
+ }
+ }
+
+ for (Parameter parameter : mShowingTemplate.getParameters()) {
+ if (parameter.type == Parameter.Type.SEPARATOR) {
+ continue;
+ }
+ IInputValidator validator = parameter.getValidator(mValues.project);
+ if (validator != null) {
+ ControlDecoration decoration = mDecorations.get(parameter.id);
+ String value = parameter.value == null ? "" : parameter.value.toString();
+ String error = validator.isValid(value);
+ if (error != null) {
+ IStatus s = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, error);
+ if (decoration != null) {
+ updateDecorator(decoration, s, parameter.help);
+ }
+ if (status == null || status.isOK()) {
+ status = s;
+ }
+ } else if (decoration != null) {
+ updateDecorator(decoration, null, parameter.help);
+ }
+ }
+
+ if (status == null || status.isOK()) {
+ if (parameter.control instanceof Combo) {
+ status = validateCombo(status, parameter, minSdk, buildApi);
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+ /** Validates the given combo */
+ static IStatus validateCombo(IStatus status, Parameter parameter, int minSdk, int buildApi) {
+ Combo combo = (Combo) parameter.control;
+ int index = combo.getSelectionIndex();
+ return validateCombo(status, parameter, index, minSdk, buildApi);
+ }
+
+ /** Validates the given combo assuming the value at the given index is chosen */
+ static IStatus validateCombo(IStatus status, Parameter parameter, int index,
+ int minSdk, int buildApi) {
+ Combo combo = (Combo) parameter.control;
+ Integer[] optionIds = (Integer[]) combo.getData(ATTR_MIN_API);
+ // Check minSdk
+ if (index != -1 && index < optionIds.length) {
+ Integer requiredMinSdk = optionIds[index];
+ if (requiredMinSdk > minSdk) {
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format(
+ "%1$s \"%2$s\" requires a minimum SDK version of at " +
+ "least %3$d, and the current min version is %4$d",
+ parameter.name, combo.getItems()[index], requiredMinSdk, minSdk));
+ }
+ }
+
+ // Check minimum build target
+ optionIds = (Integer[]) combo.getData(ATTR_MIN_BUILD_API);
+ if (index != -1 && index < optionIds.length) {
+ Integer requiredBuildApi = optionIds[index];
+ if (requiredBuildApi > buildApi) {
+ status = new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+ String.format(
+ "%1$s \"%2$s\" requires a build target API version of at " +
+ "least %3$d, and the current version is %4$d",
+ parameter.name, combo.getItems()[index], requiredBuildApi, buildApi));
+ }
+ }
+ return status;
+ }
+
+ private int getMinSdk() {
+ return mChooseProject ? mValues.getMinSdk() : mCustomMinSdk;
+ }
+
+ private int getBuildApi() {
+ return mChooseProject ? mValues.getBuildApi() : mCustomBuildApi;
+ }
+
+ private void updateDecorator(ControlDecoration decorator, IStatus status, String help) {
+ if (help != null && !help.isEmpty()) {
+ decorator.setDescriptionText(status != null ? status.getMessage() : help);
+
+ int severity = status != null ? status.getSeverity() : IStatus.OK;
+ 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());
+ } else {
+ if (status == null || status.isOK()) {
+ decorator.hide();
+ } else {
+ decorator.show();
+ }
+ }
+ }
+
+ // ---- Implements ModifyListener ----
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (mIgnore) {
+ return;
+ }
+
+ Object source = e.getSource();
+ if (source instanceof Text) {
+ Text text = (Text) source;
+ editParameter(text, text.getText().trim());
+ }
+
+ validatePage();
+ }
+
+ // ---- Implements SelectionListener ----
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (mIgnore) {
+ return;
+ }
+
+ Object source = e.getSource();
+ if (source == mProjectButton) {
+ mValues.project = mProjectButton.getSelectedProject();
+ } else if (source instanceof Combo) {
+ Combo combo = (Combo) source;
+ String[] optionIds = (String[]) combo.getData(ATTR_ID);
+ int index = combo.getSelectionIndex();
+ if (index != -1 && index < optionIds.length) {
+ String optionId = optionIds[index];
+ editParameter(combo, optionId);
+ TemplateMetadata template = mValues.getTemplateHandler().getTemplate();
+ if (template != null) {
+ setPreview(template.getThumbnailPath());
+ }
+ }
+ } else if (source instanceof Button) {
+ Button button = (Button) source;
+ Parameter parameter = (Parameter) button.getData();
+ if (parameter.type == Type.BOOLEAN) {
+ // Checkbox parameter
+ editParameter(button, button.getSelection());
+
+ TemplateMetadata template = mValues.getTemplateHandler().getTemplate();
+ if (template != null) {
+ setPreview(template.getThumbnailPath());
+ }
+ } else {
+ // Choose button for some other parameter, usually a text
+ String activity = chooseActivity();
+ if (activity != null) {
+ setValue(parameter, activity);
+ }
+ }
+ }
+
+ validatePage();
+ }
+
+ private String chooseActivity() {
+ try {
+ // Compute a search scope: We need to merge all the subclasses
+ // android.app.Fragment and android.support.v4.app.Fragment
+ IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
+ IProject project = mValues.project;
+ IJavaProject javaProject = BaseProjectHelper.getJavaProject(project);
+ IType activityType = null;
+
+ if (javaProject != null) {
+ activityType = javaProject.findType(CLASS_ACTIVITY);
+ }
+ if (activityType == null) {
+ IJavaProject[] projects = BaseProjectHelper.getAndroidProjects(null);
+ for (IJavaProject p : projects) {
+ activityType = p.findType(CLASS_ACTIVITY);
+ if (activityType != null) {
+ break;
+ }
+ }
+ }
+ if (activityType != null) {
+ NullProgressMonitor monitor = new NullProgressMonitor();
+ ITypeHierarchy hierarchy = activityType.newTypeHierarchy(monitor);
+ IType[] classes = hierarchy.getAllSubtypes(activityType);
+ scope = SearchEngine.createJavaSearchScope(classes, IJavaSearchScope.SOURCES);
+ }
+
+ Shell parent = AdtPlugin.getShell();
+ final SelectionDialog dialog = JavaUI.createTypeDialog(
+ parent,
+ new ProgressMonitorDialog(parent),
+ scope,
+ IJavaElementSearchConstants.CONSIDER_CLASSES, false,
+ // Use ? as a default filter to fill dialog with matches
+ "?", //$NON-NLS-1$
+ new TypeSelectionExtension() {
+ @Override
+ public ITypeInfoFilterExtension getFilterExtension() {
+ return new ITypeInfoFilterExtension() {
+ @Override
+ public boolean select(ITypeInfoRequestor typeInfoRequestor) {
+ int modifiers = typeInfoRequestor.getModifiers();
+ if (!Flags.isPublic(modifiers)
+ || Flags.isInterface(modifiers)
+ || Flags.isEnum(modifiers)) {
+ return false;
+ }
+ return true;
+ }
+ };
+ }
+ });
+
+ dialog.setTitle("Choose Activity Class");
+ dialog.setMessage("Select an Activity class (? = any character, * = any string):");
+ if (dialog.open() == IDialogConstants.CANCEL_ID) {
+ return null;
+ }
+
+ Object[] types = dialog.getResult();
+ if (types != null && types.length > 0) {
+ return ((IType) types[0]).getFullyQualifiedName();
+ }
+ } catch (JavaModelException e) {
+ AdtPlugin.log(e, null);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
+ return null;
+ }
+
+ private void editParameter(Control control, Object value) {
+ Parameter parameter = getParameter(control);
+ if (parameter != null) {
+ String id = parameter.id;
+ parameter.value = value;
+ parameter.edited = value != null && !value.toString().isEmpty();
+ mValues.parameters.put(id, value);
+
+ // Update dependent variables, if any
+ List<Parameter> parameters = mShowingTemplate.getParameters();
+ for (Parameter p : parameters) {
+ if (p == parameter || p.suggest == null || p.edited ||
+ p.type == Parameter.Type.SEPARATOR) {
+ continue;
+ }
+ if (!p.suggest.contains(id)) {
+ continue;
+ }
+
+ try {
+ if (mEvaluator == null) {
+ mEvaluator = new StringEvaluator();
+ }
+ String updated = mEvaluator.evaluate(p.suggest, parameters);
+ if (updated != null && !updated.equals(p.value)) {
+ setValue(p, updated);
+ }
+ } catch (Throwable t) {
+ // Pass: Ignore updating if something wrong happens
+ t.printStackTrace(); // during development only
+ }
+ }
+ }
+ }
+
+ private void setValue(Parameter p, String value) {
+ p.value = value;
+ mValues.parameters.put(p.id, value);
+
+ // Update form widgets
+ boolean prevIgnore = mIgnore;
+ try {
+ mIgnore = true;
+ if (p.control instanceof Text) {
+ ((Text) p.control).setText(value);
+ } else if (p.control instanceof Button) {
+ // TODO: Handle
+ } else if (p.control instanceof Combo) {
+ // TODO: Handle
+ } else if (p.control != null) {
+ assert false : p.control;
+ }
+ } finally {
+ mIgnore = prevIgnore;
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ // ---- Implements FocusListener ----
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ Object source = e.getSource();
+ String tip = "";
+
+ if (source instanceof Control) {
+ Control control = (Control) source;
+ Parameter parameter = getParameter(control);
+ if (parameter != null) {
+ ControlDecoration decoration = mDecorations.get(parameter.id);
+ if (decoration != null) {
+ tip = decoration.getDescriptionText();
+ }
+ }
+ }
+
+ mTipLabel.setText(tip);
+ mHelpIcon.setVisible(tip.length() > 0);
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ mTipLabel.setText("");
+ mHelpIcon.setVisible(false);
+ }
+}