blob: 57cf5c824c9d181fa7428c2366f2c8048be30bf2 [file] [log] [blame]
/*
* 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);
}
}