blob: c86919dacd91c19be715f7c382f7aa7f7c3efd9a [file] [log] [blame]
package org.jetbrains.android.inspections.lint;
import com.android.resources.Density;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTagValue;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eugene.Kudelevsky
*/
class ConvertToDpQuickFix implements AndroidLintQuickFix {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.inspections.lint.ConvertToDpQuickFix");
private static final Pattern PX_ATTR_VALUE_PATTERN = Pattern.compile("(\\d+)px");
private static int ourPrevDpi = Density.DEFAULT_DENSITY;
@Override
public void apply(@NotNull PsiElement startElement, @NotNull PsiElement endElement, @NotNull AndroidQuickfixContexts.Context context) {
if (context instanceof AndroidQuickfixContexts.BatchContext) {
return;
}
final XmlTag tag = PsiTreeUtil.getParentOfType(startElement, XmlTag.class);
final List<Density> densities = new ArrayList<Density>();
for (Density density : Density.values()) {
if (density.getDpiValue() > 0) {
densities.add(density);
}
}
final String[] densityPresentableNames = new String[densities.size()];
String defaultValue = null;
String initialValue = null;
for (int i = 0; i < densities.size(); i++) {
final Density density = densities.get(i);
densityPresentableNames[i] = getLabelForDensity(density);
final int dpi = density.getDpiValue();
if (dpi == 0) {
continue;
}
if (dpi == ourPrevDpi) {
initialValue = densityPresentableNames[i];
}
else if (dpi == Density.DEFAULT_DENSITY) {
defaultValue = densityPresentableNames[i];
}
}
if (initialValue == null) {
initialValue = defaultValue;
}
if (initialValue == null) {
return;
}
final int dpi;
if (ApplicationManager.getApplication().isUnitTestMode()) {
dpi = Density.DEFAULT_DENSITY;
}
else {
final int selectedIndex = Messages
.showChooseDialog("What is the screen density the current px value works with?", "Choose density", densityPresentableNames,
initialValue, null);
if (selectedIndex < 0) {
return;
}
dpi = densities.get(selectedIndex).getDpiValue();
}
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourPrevDpi = dpi;
for (XmlAttribute attribute : tag.getAttributes()) {
final String value = attribute.getValue();
if (value != null && value.endsWith("px")) {
final String newValue = convertToDp(value, dpi);
if (newValue != null) {
attribute.setValue(newValue);
}
}
}
final XmlTagValue tagValueElement = tag.getValue();
final String tagValue = tagValueElement.getText();
if (tagValue.endsWith("px")) {
final String newValue = convertToDp(tagValue, dpi);
if (newValue != null) {
tagValueElement.setText(newValue);
}
}
}
private static String convertToDp(String value, int dpi) {
String newValue = null;
final Matcher matcher = PX_ATTR_VALUE_PATTERN.matcher(value);
if (matcher.matches()) {
final String numberString = matcher.group(1);
try {
final int px = Integer.parseInt(numberString);
final int dp = px * 160 / dpi;
newValue = Integer.toString(dp) + "dp";
}
catch (NumberFormatException nufe) {
LOG.error(nufe);
}
}
return newValue;
}
@NotNull
private static String getLabelForDensity(@NotNull Density density) {
return String.format("%1$s (%2$d)", density.getShortDisplayValue(), density.getDpiValue());
}
@Override
public boolean isApplicable(@NotNull PsiElement startElement,
@NotNull PsiElement endElement,
@NotNull AndroidQuickfixContexts.ContextType contextType) {
return contextType != AndroidQuickfixContexts.BatchContext.TYPE &&
PsiTreeUtil.getParentOfType(startElement, XmlTag.class) != null;
}
@NotNull
@Override
public String getName() {
return AndroidBundle.message("android.lint.fix.convert.to.dp");
}
}