diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java new file mode 100644 index 000000000..3139451c7 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java @@ -0,0 +1,417 @@ +/* + * 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.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.ATTR_PACKAGE_NAME; +import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_CONSTRAINTS; +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_HELP; +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.ATTR_SUGGEST; + +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.layout.gle2.DomUtilities; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; +import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator; +import com.android.ide.eclipse.adt.internal.wizards.newproject.ApplicationInfoPage; +import com.android.resources.ResourceFolderType; +import com.android.resources.ResourceType; +import com.google.common.base.Splitter; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.swt.widgets.Control; +import org.w3c.dom.Element; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Locale; + +/** + * A template parameter editable and edited by the user. + * <p> + * Note that this class encapsulates not just the metadata provided by the + * template, but the actual editing operation of that template in the wizard: it + * also captures current values, a reference to the editing widget (such that + * related widgets can be updated when one value depends on another etc) + */ +class Parameter { + enum Type { + STRING, + BOOLEAN, + ENUM, + SEPARATOR; + // TODO: Numbers? + + public static Type get(String name) { + try { + return Type.valueOf(name.toUpperCase(Locale.US)); + } catch (IllegalArgumentException e) { + AdtPlugin.printErrorToConsole("Unexpected template type '" + name + "'"); + AdtPlugin.printErrorToConsole("Expected one of :"); + for (Type s : Type.values()) { + AdtPlugin.printErrorToConsole(" " + s.name().toLowerCase(Locale.US)); + } + } + + return STRING; + } + } + + /** + * Constraints that can be applied to a parameter which helps the UI add a + * validator etc for user input. These are typically combined into a set + * of constraints via an EnumSet. + */ + enum Constraint { + /** + * This value must be unique. This constraint usually only makes sense + * when other constraints are specified, such as {@link #LAYOUT}, which + * means that the parameter should designate a name that does not + * represent an existing layout resource name + */ + UNIQUE, + + /** + * This value must already exist. This constraint usually only makes sense + * when other constraints are specified, such as {@link #LAYOUT}, which + * means that the parameter should designate a name that already exists as + * a resource name. + */ + EXISTS, + + /** The associated value must not be empty */ + NONEMPTY, + + /** The associated value is allowed to be empty */ + EMPTY, + + /** The associated value should represent a fully qualified activity class name */ + ACTIVITY, + + /** The associated value should represent an API level */ + APILEVEL, + + /** The associated value should represent a valid class name */ + CLASS, + + /** The associated value should represent a valid package name */ + PACKAGE, + + /** The associated value should represent a valid layout resource name */ + LAYOUT, + + /** The associated value should represent a valid drawable resource name */ + DRAWABLE, + + /** The associated value should represent a valid id resource name */ + ID, + + /** The associated value should represent a valid string resource name */ + STRING; + + public static Constraint get(String name) { + try { + return Constraint.valueOf(name.toUpperCase(Locale.US)); + } catch (IllegalArgumentException e) { + AdtPlugin.printErrorToConsole("Unexpected template constraint '" + name + "'"); + if (name.indexOf(',') != -1) { + AdtPlugin.printErrorToConsole("Use | to separate constraints"); + } else { + AdtPlugin.printErrorToConsole("Expected one of :"); + for (Constraint s : Constraint.values()) { + AdtPlugin.printErrorToConsole(" " + s.name().toLowerCase(Locale.US)); + } + } + } + + return NONEMPTY; + } + } + + /** The template defining the parameter */ + public final TemplateMetadata template; + + /** The type of parameter */ + @NonNull + public final Type type; + + /** The unique id of the parameter (not displayed to the user) */ + @Nullable + public final String id; + + /** The display name for this parameter */ + @Nullable + public final String name; + + /** + * The initial value for this parameter (see also {@link #suggest} for more + * dynamic defaults + */ + @Nullable + public final String initial; + + /** + * A template expression using other template parameters for producing a + * default value based on other edited parameters, if possible. + */ + @Nullable + public final String suggest; + + /** Help for the parameter, if any */ + @Nullable + public final String help; + + /** The currently edited value */ + @Nullable + public Object value; + + /** The control showing this value */ + @Nullable + public Control control; + + /** The decoration associated with the control */ + @Nullable + public ControlDecoration decoration; + + /** Whether the parameter has been edited */ + public boolean edited; + + /** The element defining this parameter */ + @NonNull + public final Element element; + + /** The constraints applicable for this parameter */ + @NonNull + public final EnumSet<Constraint> constraints; + + /** The validator, if any, for this field */ + private IInputValidator mValidator; + + /** True if this field has no validator */ + private boolean mNoValidator; + + /** Project associated with this validator */ + private IProject mValidatorProject; + + Parameter(@NonNull TemplateMetadata template, @NonNull Element parameter) { + this.template = template; + element = parameter; + + String typeName = parameter.getAttribute(TemplateHandler.ATTR_TYPE); + assert typeName != null && !typeName.isEmpty() : TemplateHandler.ATTR_TYPE; + type = Type.get(typeName); + + id = parameter.getAttribute(ATTR_ID); + initial = parameter.getAttribute(ATTR_DEFAULT); + suggest = parameter.getAttribute(ATTR_SUGGEST); + name = parameter.getAttribute(ATTR_NAME); + help = parameter.getAttribute(ATTR_HELP); + String constraintString = parameter.getAttribute(ATTR_CONSTRAINTS); + if (constraintString != null && !constraintString.isEmpty()) { + EnumSet<Constraint> constraintSet = null; + for (String s : Splitter.on('|').omitEmptyStrings().split(constraintString)) { + Constraint constraint = Constraint.get(s); + if (constraintSet == null) { + constraintSet = EnumSet.of(constraint); + } else { + constraintSet = EnumSet.copyOf(constraintSet); + constraintSet.add(constraint); + } + } + constraints = constraintSet; + } else { + constraints = EnumSet.noneOf(Constraint.class); + } + + if (initial != null && !initial.isEmpty() && type == Type.BOOLEAN) { + value = Boolean.valueOf(initial); + } else { + value = initial; + } + } + + Parameter( + @NonNull TemplateMetadata template, + @NonNull Type type, + @NonNull String id, + @NonNull String initialValue) { + this.template = template; + this.type = type; + this.id = id; + this.value = initialValue; + element = null; + initial = null; + suggest = null; + name = id; + help = null; + constraints = EnumSet.noneOf(Constraint.class); + } + + List<Element> getOptions() { + if (element != null) { + return DomUtilities.getChildren(element); + } else { + return Collections.emptyList(); + } + } + + @Nullable + public IInputValidator getValidator(@Nullable final IProject project) { + if (mNoValidator) { + return null; + } + + if (project != mValidatorProject) { + // Force update of validators if the project changes, since the validators + // are often tied to project metadata (for example, the resource name validators + // which look for name conflicts) + mValidator = null; + mValidatorProject = project; + } + + if (mValidator == null) { + if (constraints.contains(Constraint.LAYOUT)) { + if (project != null && constraints.contains(Constraint.UNIQUE)) { + mValidator = ResourceNameValidator.create(false, project, ResourceType.LAYOUT); + } else { + mValidator = ResourceNameValidator.create(false, ResourceFolderType.LAYOUT); + } + return mValidator; + } else if (constraints.contains(Constraint.STRING)) { + if (project != null && constraints.contains(Constraint.UNIQUE)) { + mValidator = ResourceNameValidator.create(false, project, ResourceType.STRING); + } else { + mValidator = ResourceNameValidator.create(false, ResourceFolderType.VALUES); + } + return mValidator; + } else if (constraints.contains(Constraint.ID)) { + if (project != null && constraints.contains(Constraint.UNIQUE)) { + mValidator = ResourceNameValidator.create(false, project, ResourceType.ID); + } else { + mValidator = ResourceNameValidator.create(false, ResourceFolderType.VALUES); + } + return mValidator; + } else if (constraints.contains(Constraint.DRAWABLE)) { + if (project != null && constraints.contains(Constraint.UNIQUE)) { + mValidator = ResourceNameValidator.create(false, project, + ResourceType.DRAWABLE); + } else { + mValidator = ResourceNameValidator.create(false, ResourceFolderType.DRAWABLE); + } + return mValidator; + } else if (constraints.contains(Constraint.PACKAGE) + || constraints.contains(Constraint.CLASS) + || constraints.contains(Constraint.ACTIVITY)) { + mValidator = new IInputValidator() { + @Override + public String isValid(String newText) { + newText = newText.trim(); + if (newText.isEmpty()) { + if (constraints.contains(Constraint.EMPTY)) { + return null; + } else if (constraints.contains(Constraint.NONEMPTY)) { + return String.format("Enter a value for %1$s", name); + } else { + // Compatibility mode: older templates might not specify; + // in that case, accept empty + if (!"activityClass".equals(id)) { //$NON-NLS-1$ + return null; + } + } + } + IStatus status; + if (constraints.contains(Constraint.ACTIVITY)) { + status = ApplicationInfoPage.validateActivity(newText); + } else if (constraints.contains(Constraint.PACKAGE)) { + status = ApplicationInfoPage.validatePackage(newText); + } else { + assert constraints.contains(Constraint.CLASS); + status = ApplicationInfoPage.validateClass(newText); + } + if (status != null && !status.isOK()) { + return status.getMessage(); + } + + // Uniqueness + if (project != null && constraints.contains(Constraint.UNIQUE)) { + try { + // Determine the package. + // If there is a package info + + IJavaProject p = BaseProjectHelper.getJavaProject(project); + if (p != null) { + String fqcn = newText; + if (fqcn.indexOf('.') == -1) { + String pkg = null; + Parameter parameter = template.getParameter( + ATTR_PACKAGE_NAME); + if (parameter != null && parameter.value != null) { + pkg = parameter.value.toString(); + } else { + pkg = ManifestInfo.get(project).getPackage(); + } + fqcn = pkg.isEmpty() ? newText : pkg + '.' + newText; + } + + IType t = p.findType(fqcn); + if (t != null && t.exists()) { + return String.format("%1$s already exists", newText); + } + } + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + } + + return null; + } + }; + return mValidator; + } else if (constraints.contains(Constraint.NONEMPTY)) { + mValidator = new IInputValidator() { + @Override + public String isValid(String newText) { + if (newText.trim().isEmpty()) { + return String.format("Enter a value for %1$s", name); + } + + return null; + } + }; + return mValidator; + } + + // TODO: Handle EXISTS, APILEVEL (which is currently handled manually in the + // new project wizard, and never actually input by the user in a templated + // wizard) + + mNoValidator = true; + } + + return mValidator; + } +}
\ No newline at end of file |