blob: 4270b00baaedf9bd7039c2ace592f3bfd050a5c2 [file] [log] [blame]
package org.jetbrains.android.dom.converters;
import com.android.SdkConstants;
import com.android.annotations.VisibleForTesting;
import com.intellij.psi.xml.XmlElement;
import com.intellij.util.containers.HashMap;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.ResolvingConverter;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class DimensionConverter extends ResolvingConverter<String> implements AttributeValueDocumentationProvider {
public static final DimensionConverter INSTANCE = new DimensionConverter();
private static final Map<String, String> ourUnits = new HashMap<String, String>();
static {
ourUnits.put(SdkConstants.UNIT_DP, "<b>Density-independent Pixels</b> - an abstract unit " +
"that is based on the physical density of the screen.");
ourUnits.put(SdkConstants.UNIT_SP, "<b>Scale-independent Pixels</b> - this is like the dp unit, " +
"but it is also scaled by the user's font size preference.");
ourUnits.put(SdkConstants.UNIT_PT, "<b>Points</b> - 1/72 of an inch based on the physical size of the screen.");
ourUnits.put(SdkConstants.UNIT_MM, "<b>Millimeters</b> - based on the physical size of the screen.");
ourUnits.put(SdkConstants.UNIT_IN, "<b>Inches</b> - based on the physical size of the screen.");
ourUnits.put(SdkConstants.UNIT_PX, "<b>Pixels</b> - corresponds to actual pixels on the screen. Not recommended.");
}
@NotNull
@Override
public Collection<? extends String> getVariants(ConvertContext context) {
final XmlElement element = context.getXmlElement();
if (element == null) {
return Collections.emptyList();
}
final String value = ResourceReferenceConverter.getValue(element);
if (value == null) {
return Collections.emptyList();
}
final String intPrefix = getIntegerPrefix(value);
if (intPrefix.isEmpty()) {
return Collections.emptyList();
}
final List<String> result = new ArrayList<String>(ourUnits.size());
for (String unit : ourUnits.keySet()) {
result.add(intPrefix + unit);
}
return result;
}
@Nullable
@Override
public String fromString(@Nullable @NonNls String s, ConvertContext context) {
final String unit = getUnitFromValue(s);
if (unit == null || unit.isEmpty()) {
return null;
}
if (SdkConstants.UNIT_DIP.equals(unit)) {
return s;
}
return ourUnits.get(unit) != null ? s : null;
}
@Nullable
@Override
public String toString(@Nullable String s, ConvertContext context) {
return s;
}
@Override
public String getErrorMessage(@Nullable String s, ConvertContext context) {
final String unit = getUnitFromValue(s);
if (unit != null && !unit.isEmpty()) {
if (unit.startsWith(",")) {
return "Use a dot instead of a comma as the decimal mark";
}
return "Unknown unit '" + unit + "'";
}
return super.getErrorMessage(s, context);
}
@Nullable
public static String getUnitFromValue(@Nullable String value) {
if (value == null) {
return null;
}
final String intPrefix = getIntegerPrefix(value);
if (intPrefix.isEmpty()) {
return null;
}
return value.substring(intPrefix.length());
}
@VisibleForTesting
@NotNull
static String getIntegerPrefix(@NotNull String s) {
if (s.length() == 0) {
return "";
}
final StringBuilder intPrefixBuilder = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
final char c = s.charAt(i);
if (!Character.isDigit(c) && c != '.' && (i > 0 || c != '-')) {
break;
}
intPrefixBuilder.append(c);
}
return intPrefixBuilder.toString();
}
@Override
public String getDocumentation(@NotNull String value) {
final String unit = getUnitFromValue(value);
if (unit == null) {
return null;
}
final String description = ourUnits.get(unit);
if (description == null || description.length() == 0) {
return null;
}
return "<html><body>" + description + "</body></html>";
}
}