aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.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/Parameter.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java417
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