IDEA-89094 Validate names of android resources

This commit is contained in:
Eugene Kudelevsky
2012-07-24 13:35:24 +04:00
parent a6b571e622
commit e641a6f01f
8 changed files with 88 additions and 2 deletions
@@ -417,4 +417,7 @@ cannot.find.zip.align=The zipalign tool was not found in the SDK.\n\nPlease upda
file.name.not.specified.error=File name is not specified
root.element.not.specified.error=Root element is not specified
directory.not.specified.error=Directory is not specified
android.manifest.merger.not.supported.error=Manifest merging is not supported. Please, reconfigure your manifest files
android.manifest.merger.not.supported.error=Manifest merging is not supported. Please, reconfigure your manifest files
invalid.file.resource.name.error=Resource file name must contain only lowercase a-z, 0-9, or _
invalid.file.resource.name.error1=Invalid resource file name
invalid.resource.name.error=Invalid resource name ''{0}''
@@ -34,6 +34,7 @@ import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.uipreview.DeviceConfiguratorPanel;
import org.jetbrains.android.uipreview.InvalidOptionValueException;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.android.util.ModuleListCellRendererWrapper;
import org.jetbrains.annotations.NotNull;
@@ -252,6 +253,12 @@ public class CreateResourceFileDialog extends DialogWrapper {
Messages.showErrorDialog(myPanel, AndroidBundle.message("directory.not.specified.error"), CommonBundle.getErrorTitle());
return;
}
final String errorMessage = AndroidResourceUtil.getInvalidResourceFileNameMessage(fileName);
if (errorMessage != null) {
Messages.showErrorDialog(myPanel, errorMessage, CommonBundle.getErrorTitle());
return;
}
myValidator = createValidator(subdirName);
if (myValidator == null || myValidator.checkInput(fileName) && myValidator.canClose(fileName)) {
super.doOKAction();
@@ -27,6 +27,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiDirectory;
@@ -78,7 +79,7 @@ public class CreateTypedResourceFileAction extends CreateElementActionBase {
@NotNull
@Override
protected PsiElement[] invokeDialog(Project project, PsiDirectory directory) {
MyInputValidator validator = new MyInputValidator(project, directory);
MyInputValidator validator = new MyValidator(project, directory);
Messages.showInputDialog(project, AndroidBundle.message("new.file.dialog.text"),
AndroidBundle.message("new.typed.resource.dialog.title", myResourcePresentableName),
Messages.getQuestionIcon(), "", validator);
@@ -203,4 +204,20 @@ public class CreateTypedResourceFileAction extends CreateElementActionBase {
}
throw new IllegalArgumentException("Incorrect resource folder type");
}
private class MyValidator extends MyInputValidator implements InputValidatorEx {
public MyValidator(Project project, PsiDirectory directory) {
super(project, directory);
}
@Override
public boolean checkInput(String inputString) {
return getErrorText(inputString) == null;
}
@Override
public String getErrorText(String inputString) {
return AndroidResourceUtil.getInvalidResourceFileNameMessage(inputString);
}
}
}
@@ -15,6 +15,7 @@
*/
package org.jetbrains.android.dom.resources;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.GenericAttributeValue;
import com.intellij.util.xml.GenericDomValue;
import com.intellij.util.xml.Required;
@@ -25,5 +26,6 @@ import org.jetbrains.android.dom.AndroidDomElement;
*/
public interface ResourceElement extends GenericDomValue<String>, AndroidDomElement {
@Required
@Convert(ResourceNameConverter.class)
GenericAttributeValue<String> getName();
}
@@ -0,0 +1,30 @@
package org.jetbrains.android.dom.resources;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.Converter;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
/**
* @author Eugene.Kudelevsky
*/
public class ResourceNameConverter extends Converter<String> {
@Override
public String fromString(@Nullable @NonNls String s, ConvertContext context) {
return s != null && StringUtil.isJavaIdentifier(AndroidResourceUtil.getFieldNameByResourceName(s))
? s : null;
}
@Override
public String toString(@Nullable String s, ConvertContext context) {
return s;
}
@Override
public String getErrorMessage(@Nullable String s, ConvertContext context) {
return AndroidBundle.message("invalid.resource.name.error", s);
}
}
@@ -806,4 +806,18 @@ public class AndroidResourceUtil {
public static String getFieldNameByResourceName(@NotNull String fieldName) {
return fieldName.replace('.', '_').replace('-', '_').replace(':', '_');
}
@Nullable
public static String getInvalidResourceFileNameMessage(@NotNull String fileName) {
for (int i = 0, n = fileName.length(); i < n; i++) {
char c = fileName.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '.')) {
return AndroidBundle.message("invalid.file.resource.name.error");
}
}
if (!StringUtil.isJavaIdentifier(getFieldNameByResourceName(fileName))) {
return AndroidBundle.message("invalid.file.resource.name.error1");
}
return null;
}
}
@@ -0,0 +1,9 @@
<resources>
<string name="<error>1a</error>">a</string>
<string name="a1">a</string>
<item name="<error>**</error>">a</item>
<integer name="<error>a b</error>">1</integer>
<integer name="a_b">1</integer>
<string name="a-b">1</string>
<string name="a.b">1</string>
</resources>
@@ -214,6 +214,10 @@ public class AndroidValueResourcesTest extends AndroidDomTest {
doTestHighlighting();
}
public void testNameValidation() throws Throwable {
doTestHighlighting();
}
public void testResourceReferenceAsValueCompletion1() throws Throwable {
doTestCompletion();
}