diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java index ad7fee9ff8a5..e77187a20cde 100644 --- a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java +++ b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java @@ -165,7 +165,12 @@ public class ResourceReferenceConverter extends ResolvingConverter getResourceTypes(ConvertContext context) { - ResourceType resourceType = context.getInvocationElement().getAnnotation(ResourceType.class); + return getResourceTypes(context.getInvocationElement()); + } + + @NotNull + public Set getResourceTypes(@NotNull DomElement element) { + ResourceType resourceType = element.getAnnotation(ResourceType.class); Set types = new HashSet(myResourceTypes); if (resourceType != null) { String s = resourceType.value(); diff --git a/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java b/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java index 0715cfc35f90..d22ddd0c21c2 100644 --- a/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java +++ b/plugins/android/src/org/jetbrains/android/intentions/AndroidAddStringResourceAction.java @@ -45,8 +45,12 @@ import com.intellij.psi.xml.XmlAttributeValue; import com.intellij.psi.xml.XmlFile; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.xml.Converter; +import com.intellij.util.xml.DomManager; +import com.intellij.util.xml.GenericAttributeValue; import org.jetbrains.android.AndroidFileTemplateProvider; import org.jetbrains.android.actions.CreateXmlResourceDialog; +import org.jetbrains.android.dom.converters.ResourceReferenceConverter; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.dom.resources.ResourceElement; import org.jetbrains.android.dom.resources.ResourceValue; @@ -107,7 +111,29 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction { } } else if (file instanceof XmlFile && element instanceof XmlAttributeValue) { - return ((XmlAttributeValue)element).getValue(); + final XmlAttribute attribute = PsiTreeUtil.getParentOfType(element, XmlAttribute.class); + + if (attribute != null) { + final GenericAttributeValue domAttribute = DomManager.getDomManager(element.getProject()).getDomElement(attribute); + + if (domAttribute != null) { + final Converter converter = domAttribute.getConverter(); + + if (converter instanceof ResourceReferenceConverter) { + final ResourceValue value = (ResourceValue)domAttribute.getValue(); + + if (value != null && !value.isReference()) { + final Set types = ((ResourceReferenceConverter)converter).getResourceTypes(domAttribute); + + for (String type : types) { + if (ResourceType.STRING.getName().equals(type)) { + return ((XmlAttributeValue)element).getValue(); + } + } + } + } + } + } } return null; } @@ -141,25 +167,25 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction { static void doInvoke(Project project, Editor editor, PsiFile file, @Nullable String resName) { final AndroidFacet facet = AndroidFacet.getInstance(file); assert facet != null; - + final PsiElement element = getPsiElement(file, editor); assert element != null; - + String value = getStringLiteralValue(element, file); assert value != null; value = value.replace("'", "\\'").replace("\"", "\\\""); - + final String aPackage = getPackage(facet); if (aPackage == null) { Messages.showErrorDialog(project, AndroidBundle.message("package.not.found.error"), CommonBundle.getErrorTitle()); return; } - + if (resName == null) { final CreateXmlResourceDialog dialog = new CreateXmlResourceDialog(facet.getModule(), ResourceType.STRING); dialog.setTitle("Extract String Resource"); dialog.show(); - + if (!dialog.isOK()) { return; } @@ -180,7 +206,7 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction { assert ApplicationManager.getApplication().isUnitTestMode(); doCreate(facet.getModule(), resName, ResourceType.STRING, "strings.xml", "values", value); } - + if (resName == null) { return; } @@ -194,7 +220,7 @@ public class AndroidAddStringResourceAction extends AbstractIntentionAction { attribute.setValue(ResourceValue.referenceTo('@', null, ResourceType.STRING.getName(), resName).toString()); } } - + PsiDocumentManager.getInstance(project).commitAllDocuments(); UndoUtil.markPsiFileForUndo(file); diff --git a/plugins/android/testData/addStringRes/fromLayout1.xml b/plugins/android/testData/addStringRes/fromLayout1.xml new file mode 100644 index 000000000000..f152f913e39d --- /dev/null +++ b/plugins/android/testData/addStringRes/fromLayout1.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/plugins/android/testData/addStringRes/fromManifest.xml b/plugins/android/testData/addStringRes/fromManifest.xml new file mode 100644 index 000000000000..2997ac33cd72 --- /dev/null +++ b/plugins/android/testData/addStringRes/fromManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/plugins/android/testData/addStringRes/fromManifest1.xml b/plugins/android/testData/addStringRes/fromManifest1.xml new file mode 100644 index 000000000000..3b6843287cb9 --- /dev/null +++ b/plugins/android/testData/addStringRes/fromManifest1.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/plugins/android/testData/addStringRes/fromManifest1_after.xml b/plugins/android/testData/addStringRes/fromManifest1_after.xml new file mode 100644 index 000000000000..e7ed000835ae --- /dev/null +++ b/plugins/android/testData/addStringRes/fromManifest1_after.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/plugins/android/testData/addStringRes/fromManifest2.xml b/plugins/android/testData/addStringRes/fromManifest2.xml new file mode 100644 index 000000000000..1f1431a0ecb7 --- /dev/null +++ b/plugins/android/testData/addStringRes/fromManifest2.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/plugins/android/testSrc/org/jetbrains/android/intentions/AndroidAddStringResourceActionTest.java b/plugins/android/testSrc/org/jetbrains/android/intentions/AndroidAddStringResourceActionTest.java index 5ccbde1c42bf..c2970ace69c0 100644 --- a/plugins/android/testSrc/org/jetbrains/android/intentions/AndroidAddStringResourceActionTest.java +++ b/plugins/android/testSrc/org/jetbrains/android/intentions/AndroidAddStringResourceActionTest.java @@ -11,12 +11,18 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.android.AndroidTestCase; import org.jetbrains.annotations.Nullable; +import java.io.IOException; + /** * @author Eugene.Kudelevsky */ public class AndroidAddStringResourceActionTest extends AndroidTestCase { private static final String BASE_PATH = "addStringRes/"; + public AndroidAddStringResourceActionTest() { + super(false); + } + @Override public void setUp() throws Exception { super.setUp(); @@ -29,31 +35,31 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { super.tearDown(); } - public void test1() { + public void test1() throws IOException { doTest(); } - public void test2() { + public void test2() throws IOException { doTest(); } - public void test3() { + public void test3() throws IOException { doTest(); } - public void test4() { + public void test4() throws IOException { doTest(); } - public void test5() { + public void test5() throws IOException { doTest(); } - public void test6() { + public void test6() throws IOException { doTest(); } - public void test7() { + public void test7() throws IOException { doTest(new Runnable() { @Override public void run() { @@ -63,19 +69,19 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { }); } - public void test8() { + public void test8() throws IOException { doTest(); } - public void test9() { + public void test9() throws IOException { doTest(); } - public void test10() { + public void test10() throws IOException { doTest(); } - public void test11() { + public void test11() throws IOException { doTest(new Runnable() { @Override public void run() { @@ -85,11 +91,11 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { }); } - public void test12() { + public void test12() throws IOException { doTest(); } - public void test13() { + public void test13() throws IOException { doTest(); } @@ -100,15 +106,15 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { assertFalse(new AndroidAddStringResourceAction().isAvailable(myFixture.getProject(), myFixture.getEditor(), javaPsiFile)); } - public void testEscape() { + public void testEscape() throws IOException { doTest(getTestName(false), "strings.xml", null, true, "strings_escape_after.xml"); } - public void testNewFile() { + public void testNewFile() throws IOException { doTest("1", null, null, true); } - public void testInvalidStringsXml() { + public void testInvalidStringsXml() throws IOException { try { doTest("1", "strings_invalid.xml", null, true); fail(); @@ -121,21 +127,47 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { myFixture.checkResultByFile("res/values/strings.xml", BASE_PATH + "strings_invalid.xml", false); } - public void testFromLayout() { - final VirtualFile javaFile = myFixture.copyFileToProject(BASE_PATH + getTestName(false) + ".xml", "res/layout/layout.xml"); - doExtractAndCheckStringsXml("strings.xml", null, true, "strings_after.xml", javaFile); - myFixture.checkResultByFile(BASE_PATH + getTestName(false) + "_after.xml"); + public void testFromLayout() throws IOException { + createManifest(); + final VirtualFile file = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "res/layout/layout.xml"); + doExtractAndCheckStringsXml("strings.xml", null, true, "strings_after.xml", file); + myFixture.checkResultByFile(BASE_PATH + getTestName(true) + "_after.xml"); } - private void doTest() { + public void testFromLayout1() throws IOException { + createManifest(); + final VirtualFile file = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "res/layout/layout.xml"); + myFixture.configureFromExistingVirtualFile(file); + assertFalse(new AndroidAddStringResourceAction().isAvailable(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile())); + } + + public void testFromManifest() { + final VirtualFile file = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "AndroidManifest.xml"); + myFixture.configureFromExistingVirtualFile(file); + assertFalse(new AndroidAddStringResourceAction().isAvailable(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile())); + } + + public void testFromManifest1() { + final VirtualFile file = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "AndroidManifest.xml"); + doExtractAndCheckStringsXml("strings.xml", null, true, "strings_after.xml", file); + myFixture.checkResultByFile(BASE_PATH + getTestName(true) + "_after.xml"); + } + + public void testFromManifest2() { + final VirtualFile file = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "AndroidManifest.xml"); + myFixture.configureFromExistingVirtualFile(file); + assertFalse(new AndroidAddStringResourceAction().isAvailable(myFixture.getProject(), myFixture.getEditor(), myFixture.getFile())); + } + + private void doTest() throws IOException { doTest(getTestName(false), "strings.xml", null, true); } - private void doTest(Runnable invokeAfterTemplate) { + private void doTest(Runnable invokeAfterTemplate) throws IOException { doTest(getTestName(false), "strings.xml", invokeAfterTemplate, false); } - private void doTest(String testName, String stringsXml, final Runnable invokeAfterTemplate, final boolean closePopup) { + private void doTest(String testName, String stringsXml, final Runnable invokeAfterTemplate, final boolean closePopup) throws IOException { doTest(testName, stringsXml, invokeAfterTemplate, closePopup, "strings_after.xml"); } @@ -143,7 +175,8 @@ public class AndroidAddStringResourceActionTest extends AndroidTestCase { String stringsXml, @Nullable final Runnable invokeAfterTemplate, final boolean closePopup, - String stringsAfter) { + String stringsAfter) throws IOException { + createManifest(); VirtualFile javaFile = myFixture.copyFileToProject(BASE_PATH + "Class" + testName + ".java", "src/p1/p2/Class.java"); doExtractAndCheckStringsXml(stringsXml, invokeAfterTemplate, closePopup, stringsAfter, javaFile); myFixture.checkResultByFile(BASE_PATH + "Class" + testName + "_after.java");