com.android.ide.common.xml.XmlAttributeSortOrder Maven / Gradle / Ivy
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.common.xml;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import org.w3c.dom.Attr;
import java.util.Comparator;
import static com.android.SdkConstants.ATTR_COLOR;
import static com.android.SdkConstants.ATTR_ID;
import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
import static com.android.SdkConstants.ATTR_NAME;
import static com.android.SdkConstants.ATTR_STYLE;
import static com.android.SdkConstants.XMLNS;
import static com.google.common.base.Strings.nullToEmpty;
/** Order to use when sorting attributes */
public enum XmlAttributeSortOrder {
NO_SORTING("none"), //$NON-NLS-1$
ALPHABETICAL("alpha"), //$NON-NLS-1$
LOGICAL("logical"); //$NON-NLS-1$
XmlAttributeSortOrder(String key) {
this.key = key;
}
public final String key;
/**
* @return a comparator for use by this attribute sort order
*/
@Nullable
public Comparator getAttributeComparator() {
switch (this) {
case NO_SORTING:
return null;
case ALPHABETICAL:
return ALPHABETICAL_COMPARATOR;
case LOGICAL:
default:
return SORTED_ORDER_COMPARATOR;
}
}
/** Comparator which can be used to sort attributes in the coding style priority order */
private static final Comparator SORTED_ORDER_COMPARATOR = new Comparator() {
@Override
public int compare(Attr attr1, Attr attr2) {
// Namespace declarations should always go first
String prefix1 = attr1.getPrefix();
String prefix2 = attr2.getPrefix();
if (XMLNS.equals(prefix1)) {
if (XMLNS.equals(prefix2)) {
return 0;
}
return -1;
} else if (XMLNS.equals(attr2.getPrefix())) {
return 1;
}
// Sort by preferred attribute order
String name1 = prefix1 != null ? attr1.getLocalName() : attr1.getName();
String name2 = prefix2 != null ? attr2.getLocalName() : attr2.getName();
return compareAttributes(prefix1, name1, prefix2, name2);
}
};
/**
* Comparator which can be used to sort attributes into alphabetical order (but xmlns
* is always first)
*/
private static final Comparator ALPHABETICAL_COMPARATOR = new Comparator() {
@Override
public int compare(Attr attr1, Attr attr2) {
// Namespace declarations should always go first
if (XMLNS.equals(attr1.getPrefix())) {
if (XMLNS.equals(attr2.getPrefix())) {
return 0;
}
return -1;
} else if (XMLNS.equals(attr2.getPrefix())) {
return 1;
}
// Sort by name rather than local name to ensure we sort by namespaces first,
// then by names.
return attr1.getName().compareTo(attr2.getName());
}
};
/**
* Returns {@link Comparator} values for ordering attributes in the following
* order:
*
* - id
*
- style
*
- layout_width
*
- layout_height
*
- other layout params, sorted alphabetically
*
- other attributes, sorted alphabetically
*
*
* @param name1 the first attribute name to compare
* @param name2 the second attribute name to compare
* @return a negative number if name1 should be ordered before name2
*/
public static int compareAttributes(String name1, String name2) {
int priority1 = getAttributePriority(name1);
int priority2 = getAttributePriority(name2);
if (priority1 != priority2) {
return priority1 - priority2;
}
// Sort remaining attributes alphabetically
return name1.compareTo(name2);
}
/**
* Returns {@link Comparator} values for ordering attributes in the following
* order:
*
* - id
*
- style
*
- layout_width
*
- layout_height
*
- other layout params, sorted alphabetically
*
- other attributes, sorted alphabetically, first by namespace, then by name
*
* @param prefix1 the namespace prefix, if any, of {@code name1}
* @param name1 the first attribute name to compare
* @param prefix2 the namespace prefix, if any, of {@code name2}
* @param name2 the second attribute name to compare
* @return a negative number if name1 should be ordered before name2
*/
public static int compareAttributes(
@Nullable String prefix1, @NonNull String name1,
@Nullable String prefix2, @NonNull String name2) {
int priority1 = getAttributePriority(name1);
int priority2 = getAttributePriority(name2);
if (priority1 != priority2) {
return priority1 - priority2;
}
int namespaceDelta = nullToEmpty(prefix1).compareTo(nullToEmpty(prefix2));
if (namespaceDelta != 0) {
return namespaceDelta;
}
// Sort remaining attributes alphabetically
return name1.compareTo(name2);
}
/** Returns a sorting priority for the given attribute name */
private static int getAttributePriority(String name) {
if (ATTR_ID.equals(name)) {
return 10;
}
if (ATTR_NAME.equals(name)) {
return 15;
}
if (ATTR_STYLE.equals(name)) {
return 20;
}
if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) {
// Width and height are special cased because we (a) want width and height
// before the other layout attributes, and (b) we want width to sort before height
// even though it comes after it alphabetically.
if (name.equals(ATTR_LAYOUT_WIDTH)) {
return 30;
}
if (name.equals(ATTR_LAYOUT_HEIGHT)) {
return 40;
}
return 50;
}
// "color" sorts to the end
if (ATTR_COLOR.equals(name)) {
return 100;
}
return 60;
}
}