diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java new file mode 100644 index 000000000..5ea1edc0e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/ResourceNameValidator.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2010 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.resources; + +import static com.android.SdkConstants.DOT_XML; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.resources.ResourceItem; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils; +import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; +import com.android.resources.ResourceFolderType; +import com.android.resources.ResourceType; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jdt.core.JavaConventions; +import org.eclipse.jface.dialogs.IInputValidator; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Validator which ensures that new Android resource names are valid. + */ +public class ResourceNameValidator implements IInputValidator { + /** Set of existing names to check for conflicts with */ + private Set<String> mExisting; + + /** If true, the validated name must be unique */ + private boolean mUnique = true; + + /** If true, the validated name must exist */ + private boolean mExist; + + /** + * True if the resource name being considered is a "file" based resource (where the + * resource name is the actual file name, rather than just a value attribute inside an + * XML file name of arbitrary name + */ + private boolean mIsFileType; + + /** + * True if the resource type can point to image resources + */ + private boolean mIsImageType; + + /** If true, allow .xml as a name suffix */ + private boolean mAllowXmlExtension; + + private ResourceNameValidator(boolean allowXmlExtension, Set<String> existing, + boolean isFileType, boolean isImageType) { + mAllowXmlExtension = allowXmlExtension; + mExisting = existing; + mIsFileType = isFileType; + mIsImageType = isImageType; + } + + /** + * Makes the resource name validator require that names are unique. + * + * @return this, for construction chaining + */ + public ResourceNameValidator unique() { + mUnique = true; + mExist = false; + + return this; + } + + /** + * Makes the resource name validator require that names already exist + * + * @return this, for construction chaining + */ + public ResourceNameValidator exist() { + mExist = true; + mUnique = false; + + return this; + } + + @Override + public String isValid(String newText) { + // IValidator has the same interface as SWT's IInputValidator + try { + if (newText == null || newText.trim().length() == 0) { + return "Enter a new name"; + } + + if (mAllowXmlExtension && newText.endsWith(DOT_XML)) { + newText = newText.substring(0, newText.length() - DOT_XML.length()); + } + + if (mAllowXmlExtension && mIsImageType + && ImageUtils.hasImageExtension(newText)) { + newText = newText.substring(0, newText.lastIndexOf('.')); + } + + if (!mIsFileType) { + newText = newText.replace('.', '_'); + } + + if (newText.indexOf('.') != -1 && !newText.endsWith(DOT_XML)) { + if (mIsImageType) { + return "The filename must end with .xml or .png"; + } else { + return "The filename must end with .xml"; + } + } + + // Resource names must be valid Java identifiers, since they will + // be represented as Java identifiers in the R file: + if (!Character.isJavaIdentifierStart(newText.charAt(0))) { + return "The resource name must begin with a character"; + } + for (int i = 1, n = newText.length(); i < n; i++) { + char c = newText.charAt(i); + if (!Character.isJavaIdentifierPart(c)) { + return String.format("'%1$c' is not a valid resource name character", c); + } + } + + if (mIsFileType) { + char first = newText.charAt(0); + if (!(first >= 'a' && first <= 'z')) { + return String.format( + "File-based resource names must start with a lowercase letter."); + } + + // AAPT only allows lowercase+digits+_: + // "%s: Invalid file name: must contain only [a-z0-9_.]"," + for (int i = 0, n = newText.length(); i < n; i++) { + char c = newText.charAt(i); + if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_')) { + return String.format( + "File-based resource names must contain only lowercase a-z, 0-9, or _."); + } + } + } + + String level = "1.5"; //$NON-NLS-1$ + IStatus validIdentifier = JavaConventions.validateIdentifier(newText, level, level); + if (!validIdentifier.isOK()) { + return String.format("%1$s is not a valid name (reserved Java keyword)", newText); + } + + + if (mExisting != null && (mUnique || mExist)) { + boolean exists = mExisting.contains(newText); + if (mUnique && exists) { + return String.format("%1$s already exists", newText); + } else if (mExist && !exists) { + return String.format("%1$s does not exist", newText); + } + } + + return null; + } catch (Exception e) { + AdtPlugin.log(e, "Validation failed: %s", e.toString()); + return ""; //$NON-NLS-1$ + } + } + + /** + * Creates a new {@link ResourceNameValidator} + * + * @param allowXmlExtension if true, allow .xml to be entered as a suffix for the + * resource name + * @param type the resource type of the resource name being validated + * @return a new {@link ResourceNameValidator} + */ + public static ResourceNameValidator create(boolean allowXmlExtension, + ResourceFolderType type) { + boolean isFileType = type != ResourceFolderType.VALUES; + return new ResourceNameValidator(allowXmlExtension, null, isFileType, + type == ResourceFolderType.DRAWABLE); + } + + /** + * Creates a new {@link ResourceNameValidator} + * + * @param allowXmlExtension if true, allow .xml to be entered as a suffix for the + * resource name + * @param existing An optional set of names that already exist (and therefore will not + * be considered valid if entered as the new name) + * @param type the resource type of the resource name being validated + * @return a new {@link ResourceNameValidator} + */ + public static ResourceNameValidator create(boolean allowXmlExtension, Set<String> existing, + ResourceType type) { + boolean isFileType = ResourceHelper.isFileBasedResourceType(type); + return new ResourceNameValidator(allowXmlExtension, existing, isFileType, + type == ResourceType.DRAWABLE).unique(); + } + + /** + * Creates a new {@link ResourceNameValidator}. By default, the name will need to be + * unique in the project. + * + * @param allowXmlExtension if true, allow .xml to be entered as a suffix for the + * resource name + * @param project the project to validate new resource names for + * @param type the resource type of the resource name being validated + * @return a new {@link ResourceNameValidator} + */ + public static ResourceNameValidator create(boolean allowXmlExtension, + @Nullable IProject project, + @NonNull ResourceType type) { + Set<String> existing = null; + if (project != null) { + existing = new HashSet<String>(); + ResourceManager manager = ResourceManager.getInstance(); + ProjectResources projectResources = manager.getProjectResources(project); + Collection<ResourceItem> items = projectResources.getResourceItemsOfType(type); + for (ResourceItem item : items) { + existing.add(item.getName()); + } + } + + boolean isFileType = ResourceHelper.isFileBasedResourceType(type); + return new ResourceNameValidator(allowXmlExtension, existing, isFileType, + type == ResourceType.DRAWABLE); + } +} |