diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml
index bcbaf0fd30ca..e6e625de60e8 100644
--- a/plugins/android/src/META-INF/plugin.xml
+++ b/plugins/android/src/META-INF/plugin.xml
@@ -173,6 +173,7 @@
serviceImplementation="org.jetbrains.android.maven.AndroidExternalApklibDependenciesManager"/>
+
diff --git a/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java b/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java
index 0344676ae229..11ef3f940486 100644
--- a/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java
+++ b/plugins/android/src/org/jetbrains/android/AndroidIdIndex.java
@@ -21,19 +21,16 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.XmlRecursiveElementVisitor;
-import com.intellij.psi.xml.XmlAttributeValue;
-import com.intellij.psi.xml.XmlFile;
-import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.indexing.*;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
-import org.jetbrains.android.resourceManagers.ResourceManager;
+import com.intellij.util.text.CharArrayUtil;
+import com.intellij.util.xml.NanoXmlUtil;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NotNull;
+import java.io.ByteArrayInputStream;
import java.util.Collections;
import java.util.Map;
@@ -47,53 +44,41 @@ public class AndroidIdIndex extends ScalarIndexExtension {
private static final FileBasedIndex.InputFilter INPUT_FILTER = new FileBasedIndex.InputFilter() {
public boolean acceptInput(final VirtualFile file) {
- if ((file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
- file.getFileType() == StdFileTypes.XML) {
- VirtualFile parent = file.getParent();
- if (parent == null || !parent.isDirectory()) {
- return false;
- }
- final String resourceType = ResourceManager.getResourceTypeByDirName(parent.getName());
- if (resourceType == null || !canContainIdDeclaration(resourceType)) {
- return false;
- }
- parent = parent.getParent();
- return parent != null && SdkConstants.FD_RES.equals(parent.getName());
- }
- return false;
+ return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
+ file.getFileType() == StdFileTypes.XML;
}
};
private static final DataIndexer INDEXER = new DataIndexer() {
@NotNull
public Map map(FileContent inputData) {
- PsiFile file = inputData.getPsiFile();
- if (file instanceof XmlFile) {
- final HashMap ids = new HashMap();
- file.accept(new XmlRecursiveElementVisitor() {
- @Override
- public void visitXmlAttributeValue(XmlAttributeValue attributeValue) {
- if (AndroidResourceUtil.isIdDeclaration(attributeValue)) {
- String id = AndroidResourceUtil.getResourceNameByReferenceText(attributeValue.getValue());
- if (id != null) {
- if (ids.isEmpty()) {
- ids.put(MARKER, null);
- }
- ids.put(id, null);
+ final CharSequence content = inputData.getContentAsText();
+
+ if (content == null || CharArrayUtil.indexOf(content, SdkConstants.NS_RESOURCES, 0) == -1) {
+ return Collections.emptyMap();
+ }
+ final HashMap ids = new HashMap();
+
+ NanoXmlUtil.parse(new ByteArrayInputStream(inputData.getContent()), new NanoXmlUtil.IXMLBuilderAdapter() {
+ @Override
+ public void addAttribute(String key, String nsPrefix, String nsURI, String value, String type) throws Exception {
+ super.addAttribute(key, nsPrefix, nsURI, value, type);
+
+ if (AndroidResourceUtil.isIdDeclaration(value)) {
+ String id = AndroidResourceUtil.getResourceNameByReferenceText(value);
+ if (id != null) {
+ if (ids.isEmpty()) {
+ ids.put(MARKER, null);
}
+ ids.put(id, null);
}
}
- });
- return ids;
- }
- return Collections.emptyMap();
+ }
+ });
+ return ids;
}
};
- private static boolean canContainIdDeclaration(@NotNull String resType) {
- return ArrayUtil.find(RES_TYPES_CONTAINING_ID_DECLARATIONS, resType) >= 0;
- }
-
@Override
public ID getName() {
return INDEX_ID;
@@ -121,6 +106,6 @@ public class AndroidIdIndex extends ScalarIndexExtension {
@Override
public int getVersion() {
- return 1;
+ return 2;
}
}
diff --git a/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java b/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java
index 2f2db3646235..f2df753a4392 100644
--- a/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java
+++ b/plugins/android/src/org/jetbrains/android/AndroidResourcesLineMarkerProvider.java
@@ -171,7 +171,7 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider {
Collection resourceFiles = resManager.getResourceElements();
for (Resources res : resourceFiles) {
for (String valueResourceType : ResourceManager.VALUE_RESOURCE_TYPES) {
- for (ResourceElement valueResource : ResourceManager.getValueResources(valueResourceType, res)) {
+ for (ResourceElement valueResource : ResourceManager.getValueResourcesFromElement(valueResourceType, res)) {
addResource(valueResourceType, valueResource, result);
}
}
@@ -197,7 +197,7 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider {
public void run() {
List resourceSubdirs = resManager.getResourceSubdirs(null);
for (VirtualFile dir : resourceSubdirs) {
- String resType = ResourceManager.getResourceTypeByDirName(dir.getName());
+ String resType = AndroidResourceUtil.getResourceTypeByDirName(dir.getName());
if (resType != null) {
for (VirtualFile resourceFile : dir.getChildren()) {
if (!resourceFile.isDirectory()) {
@@ -264,7 +264,7 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider {
if (resourceMap != null) {
targets = new ArrayList();
if (resType.equals("id")) {
- AndroidResourceUtil.collectIdDeclarations(fieldName, manager.getModule(), targets);
+ manager.collectIdDeclarations(fieldName, targets);
}
List resources = resourceMap.get(new MyResourceEntry(fieldName, resType));
if (resources != null) {
diff --git a/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java b/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java
new file mode 100644
index 000000000000..0d0182593253
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/AndroidValueResourcesIndex.java
@@ -0,0 +1,203 @@
+package org.jetbrains.android;
+
+import com.android.resources.ResourceType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
+import com.intellij.util.containers.HashMap;
+import com.intellij.util.containers.HashSet;
+import com.intellij.util.indexing.*;
+import com.intellij.util.io.DataExternalizer;
+import com.intellij.util.io.KeyDescriptor;
+import com.intellij.util.text.CharArrayUtil;
+import com.intellij.util.xml.NanoXmlUtil;
+import org.jetbrains.android.util.AndroidResourceUtil;
+import org.jetbrains.android.util.ResourceEntry;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class AndroidValueResourcesIndex extends FileBasedIndexExtension> {
+ public static final ID> INDEX_ID = ID.create("android.value.resources.index");
+
+ private final FileBasedIndex.InputFilter myInputFilter = new FileBasedIndex.InputFilter() {
+ public boolean acceptInput(final VirtualFile file) {
+ return (file.getFileSystem() == LocalFileSystem.getInstance() || file.getFileSystem() instanceof TempFileSystem) &&
+ file.getFileType() == StdFileTypes.XML;
+ }
+ };
+
+ private final DataIndexer, FileContent> myIndexer =
+ new DataIndexer, FileContent>() {
+ @NotNull
+ public Map> map(FileContent inputData) {
+
+ if (CharArrayUtil.indexOf(inputData.getContentAsText(), "> result = new HashMap>();
+
+ NanoXmlUtil.parse(new ByteArrayInputStream(inputData.getContent()), new NanoXmlUtil.IXMLBuilderAdapter() {
+ private boolean mySeenResources = false;
+ private String myLastTypeAttr = null;
+ private String myLastNameAttr = null;
+
+ @Override
+ public void startElement(String name, String nsPrefix, String nsURI, String systemID, int lineNr) throws Exception {
+ super.startElement(name, nsPrefix, nsURI, systemID, lineNr);
+
+ if (!mySeenResources) {
+ if ("resources".equals(name)) {
+ mySeenResources = true;
+ }
+ else {
+ throw new NanoXmlUtil.ParserStoppedException();
+ }
+ }
+ myLastNameAttr = null;
+ myLastTypeAttr = null;
+ }
+
+ @Override
+ public void addAttribute(String key, String nsPrefix, String nsURI, String value, String type) throws Exception {
+ super.addAttribute(key, nsPrefix, nsURI, value, type);
+
+ if ("name".equals(key)) {
+ myLastNameAttr = value;
+ }
+ else if ("type".equals(key)) {
+ myLastTypeAttr = value;
+ }
+ }
+
+ @Override
+ public void elementAttributesProcessed(String name, String nsPrefix, String nsURI) throws Exception {
+ super.elementAttributesProcessed(name, nsPrefix, nsURI);
+
+ if (myLastNameAttr != null && name != null) {
+ final String resType = "item".equals(name)
+ ? myLastTypeAttr
+ : AndroidResourceUtil.getResourceTypeByTagName(name);
+ if (resType != null && ResourceType.getEnum(resType) != null) {
+ final ResourceEntry entry = new ResourceEntry(resType, myLastNameAttr);
+ result.put(entry, Collections.emptySet());
+
+ final ResourceEntry typeMarkerEntry = createTypeMarkerEntry(resType);
+ Set set = result.get(typeMarkerEntry);
+
+ if (set == null) {
+ set = new HashSet();
+ result.put(typeMarkerEntry, set);
+ }
+ set.add(entry);
+ }
+ }
+ }
+ });
+
+ return result;
+ }
+ };
+
+ public static ResourceEntry createTypeMarkerEntry(String type) {
+ return new ResourceEntry(type, "TYPE_MARKER_RESOURCE");
+ }
+
+ private final KeyDescriptor myKeyDescriptor = new KeyDescriptor() {
+ @Override
+ public void save(DataOutput out, ResourceEntry value) throws IOException {
+ out.writeUTF(value.getType());
+ out.writeUTF(value.getName());
+ }
+
+ @Override
+ public ResourceEntry read(DataInput in) throws IOException {
+ final String resType = in.readUTF();
+ final String resName = in.readUTF();
+ return new ResourceEntry(resType, resName);
+ }
+
+ @Override
+ public int getHashCode(ResourceEntry value) {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean isEqual(ResourceEntry val1, ResourceEntry val2) {
+ return val1.equals(val2);
+ }
+ };
+
+ private final DataExternalizer> myValueExternalizer = new DataExternalizer>() {
+ @Override
+ public void save(DataOutput out, Set value) throws IOException {
+ out.writeInt(value.size());
+
+ for (ResourceEntry entry : value) {
+ myKeyDescriptor.save(out, entry);
+ }
+ }
+
+ @Nullable
+ @Override
+ public Set read(DataInput in) throws IOException {
+ final int size = in.readInt();
+
+ if (size == 0) {
+ return Collections.emptySet();
+ }
+ final Set result = new HashSet(size);
+
+ for (int i = 0; i < size; i++) {
+ result.add(myKeyDescriptor.read(in));
+ }
+ return result;
+ }
+ };
+
+ @Override
+ public ID> getName() {
+ return INDEX_ID;
+ }
+
+ @Override
+ public DataIndexer, FileContent> getIndexer() {
+ return myIndexer;
+ }
+
+ @Override
+ public KeyDescriptor getKeyDescriptor() {
+ return myKeyDescriptor;
+ }
+
+ @Override
+ public DataExternalizer> getValueExternalizer() {
+ return myValueExternalizer;
+ }
+
+ @Override
+ public FileBasedIndex.InputFilter getInputFilter() {
+ return myInputFilter;
+ }
+
+ @Override
+ public boolean dependsOnFileContent() {
+ return true;
+ }
+
+ @Override
+ public int getVersion() {
+ return 0;
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/AndroidXmlSchemaProvider.java b/plugins/android/src/org/jetbrains/android/AndroidXmlSchemaProvider.java
index 9916c9cffec8..5652e9862fdb 100644
--- a/plugins/android/src/org/jetbrains/android/AndroidXmlSchemaProvider.java
+++ b/plugins/android/src/org/jetbrains/android/AndroidXmlSchemaProvider.java
@@ -36,6 +36,7 @@ import gnu.trove.THashMap;
import org.jetbrains.android.dom.manifest.ManifestDomFileDescription;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.ResourceManager;
+import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -107,7 +108,7 @@ public class AndroidXmlSchemaProvider extends XmlSchemaProvider {
return false;
}
- final String resType = ResourceManager.getResourceTypeByDirName(parent.getName());
+ final String resType = AndroidResourceUtil.getResourceTypeByDirName(parent.getName());
if (resType == null) {
return false;
}
diff --git a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java
index dae344b92ced..8bc1055a1fd6 100644
--- a/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java
+++ b/plugins/android/src/org/jetbrains/android/actions/CreateXmlResourceDialog.java
@@ -141,7 +141,7 @@ public class CreateXmlResourceDialog extends DialogWrapper {
return new ValidationInfo("specify module", myModuleCombo);
}
else if (!ResourceFolderType.VALUES.getName().equals(
- ResourceManager.getResourceTypeByDirName(directoryName))) {
+ AndroidResourceUtil.getResourceTypeByDirName(directoryName))) {
return new ValidationInfo("directory name is not appropriate for value resources");
}
@@ -196,7 +196,7 @@ public class CreateXmlResourceDialog extends DialogWrapper {
return new ValidationInfo(AndroidBundle.message("not.resource.file.error", FileUtil.toSystemDependentName(resFile.getPath())));
}
- for (ResourceElement element : ResourceManager.getValueResources(resourceType.getName(), resources)) {
+ for (ResourceElement element : ResourceManager.getValueResourcesFromElement(resourceType.getName(), resources)) {
if (resourceName.equals(element.getName().getValue())) {
return new ValidationInfo("resource '" + resourceName + "' already exists in " + FileUtil.toSystemDependentName(
resFile.getPath()));
diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
index d5cb5c5d389e..858500668f22 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
@@ -58,6 +58,7 @@ import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java
index e1aefdc3aa16..c1150a0226c6 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java
@@ -8,6 +8,7 @@ import com.intellij.util.containers.HashSet;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.sdk.AndroidPlatform;
+import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
index 3e3b8a51ac3b..371077fede8e 100644
--- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
+++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
@@ -80,6 +80,7 @@ import org.jetbrains.android.resourceManagers.SystemResourceManager;
import org.jetbrains.android.sdk.*;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
index 04208af7976a..27d7809494f8 100644
--- a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
+++ b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
@@ -32,6 +32,7 @@ import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.fileTypes.AndroidIdlFileType;
import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java
index 5369c0d85a21..5a7a1f8d265f 100644
--- a/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java
+++ b/plugins/android/src/org/jetbrains/android/resourceManagers/LocalResourceManager.java
@@ -20,7 +20,6 @@ import com.android.AndroidConstants;
import com.intellij.CommonBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
@@ -28,14 +27,10 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
-import com.intellij.util.indexing.FileBasedIndex;
-import com.intellij.util.xml.GenericAttributeValue;
import org.jetbrains.android.AndroidFileTemplateProvider;
-import org.jetbrains.android.AndroidIdIndex;
import org.jetbrains.android.actions.CreateResourceFileAction;
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
import org.jetbrains.android.dom.resources.Attr;
@@ -52,7 +47,6 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -101,21 +95,7 @@ public class LocalResourceManager extends ResourceManager {
}
public List getResourceElements() {
- return getResourceElements(getAllResourceFiles());
- }
-
- @NotNull
- private Set getAllResourceFiles() {
- final Set files = new HashSet();
-
- for (VirtualFile valueResourceDir : getResourceSubdirs("values")) {
- for (VirtualFile valueResourceFile : valueResourceDir.getChildren()) {
- if (!valueResourceFile.isDirectory() && valueResourceFile.getFileType().equals(StdFileTypes.XML)) {
- files.add(valueResourceFile);
- }
- }
- }
- return files;
+ return getResourceElements(null);
}
@NotNull
@@ -124,24 +104,9 @@ public class LocalResourceManager extends ResourceManager {
return AndroidRootUtil.getResourceOverlayDirs(getModule());
}
- @NotNull
- @Override
- public Collection getValueResourceNames(@NotNull String resourceType) {
- final List result = new ArrayList();
-
- for (ResourceElement element : getValueResources(resourceType)) {
- final String name = element.getName().getValue();
-
- if (name != null) {
- result.add(name);
- }
- }
- return result;
- }
-
@NotNull
public List getValueResources(@NotNull final String resourceType) {
- return getValueResources(resourceType, getAllResourceFiles());
+ return getValueResources(resourceType, null);
}
private static void collectResourceDirs(Module module, Set result, Set visited) {
@@ -193,43 +158,6 @@ public class LocalResourceManager extends ResourceManager {
myAttrDefs = null;
}
- @Nullable
- public List findIdDeclarations(@NotNull String id) {
- List declarations = new ArrayList();
- AndroidResourceUtil.collectIdDeclarations(id, myModule, declarations);
- return declarations;
- }
-
- @NotNull
- public Collection getIds() {
- List result = new ArrayList();
- Project project = myModule.getProject();
- GlobalSearchScope scope = GlobalSearchScope.projectScope(myModule.getProject());
- for (String key : FileBasedIndex.getInstance().getAllKeys(AndroidIdIndex.INDEX_ID, project)) {
- if (!AndroidIdIndex.MARKER.equals(key)) {
- if (FileBasedIndex.getInstance().getValues(AndroidIdIndex.INDEX_ID, key, scope).size() > 0) {
- result.add(key);
- }
- }
- }
- return result;
- }
-
- @NotNull
- @Override
- public List findValueResources(@NotNull String resourceType,
- @NotNull String resourceName,
- boolean distinguishDelimetersInName) {
- List elements = new ArrayList();
- for (ResourceElement element : getValueResources(resourceType)) {
- GenericAttributeValue name = element.getName();
- if (name != null && equal(resourceName, name.getValue(), distinguishDelimetersInName)) {
- elements.add(element);
- }
- }
- return elements;
- }
-
@NotNull
public List findAttrs(@NotNull String name) {
List list = new ArrayList();
diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
index d0bee9a74065..0c69c063e21c 100644
--- a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
+++ b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
@@ -15,28 +15,37 @@
*/
package org.jetbrains.android.resourceManagers;
+import com.android.resources.ResourceType;
import com.android.sdklib.SdkConstants;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
-import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.HashMap;
+import com.intellij.util.containers.HashSet;
+import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.xml.DomElement;
+import org.jetbrains.android.AndroidIdIndex;
+import org.jetbrains.android.AndroidValueResourcesIndex;
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
import org.jetbrains.android.dom.resources.Item;
import org.jetbrains.android.dom.resources.ResourceElement;
import org.jetbrains.android.dom.resources.Resources;
import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -48,6 +57,8 @@ import static java.util.Collections.addAll;
* @author coyote
*/
public abstract class ResourceManager {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.resourceManagers.LocalResourceManager");
+
public static final Set REFERABLE_RESOURCE_TYPES = new HashSet();
public static final String[] FILE_RESOURCE_TYPES = new String[]{"drawable", "anim", "layout", "values", "menu", "xml", "raw", "color"};
public static final String[] VALUE_RESOURCE_TYPES =
@@ -93,33 +104,9 @@ public abstract class ResourceManager {
return VirtualFile.EMPTY_ARRAY;
}
- @Nullable
- public static String getResourceTypeByDirName(@NotNull String name) {
- int index = name.indexOf('-');
- String type = index >= 0 ? name.substring(0, index) : name;
- return ArrayUtil.find(FILE_RESOURCE_TYPES, type) >= 0 ? type : null;
- }
-
@NotNull
public List getResourceSubdirs(@Nullable String resourceType) {
- List dirs = new ArrayList();
- if (ArrayUtil.find(FILE_RESOURCE_TYPES, resourceType) < 0 && resourceType != null) {
- return dirs;
- }
- VirtualFile[] resourcesDirs = getAllResourceDirs();
- for (VirtualFile resourcesDir : resourcesDirs) {
- if (resourcesDir == null) return dirs;
- if (resourceType == null) {
- ContainerUtil.addAll(dirs, resourcesDir.getChildren());
- }
- else {
- for (VirtualFile child : resourcesDir.getChildren()) {
- String type = getResourceTypeByDirName(child.getName());
- if (resourceType.equals(type)) dirs.add(child);
- }
- }
- }
- return dirs;
+ return AndroidResourceUtil.getResourceSubdirs(resourceType, getAllResourceDirs());
}
@NotNull
@@ -193,21 +180,37 @@ public abstract class ResourceManager {
return findResourceFiles(resType, null, true);
}
- protected List getResourceElements(@NotNull Set files) {
+ protected List getResourceElements(@Nullable Set files) {
return getRootDomElements(Resources.class, files);
}
private List getRootDomElements(@NotNull Class elementType,
- @NotNull Collection files) {
+ @Nullable Set files) {
final List result = new ArrayList();
- for (VirtualFile file : files) {
- T element = AndroidUtils.loadDomElement(myModule, file, elementType);
- if (element != null) result.add(element);
+ for (VirtualFile file : getAllValueResourceFiles()) {
+ if ((files == null || files.contains(file)) && file.isValid()) {
+ T element = AndroidUtils.loadDomElement(myModule, file, elementType);
+ if (element != null) result.add(element);
+ }
}
return result;
}
- protected List getValueResources(final String resourceType, Set files) {
+ @NotNull
+ protected Set getAllValueResourceFiles() {
+ final Set files = new HashSet();
+
+ for (VirtualFile valueResourceDir : getResourceSubdirs("values")) {
+ for (VirtualFile valueResourceFile : valueResourceDir.getChildren()) {
+ if (!valueResourceFile.isDirectory() && valueResourceFile.getFileType().equals(StdFileTypes.XML)) {
+ files.add(valueResourceFile);
+ }
+ }
+ }
+ return files;
+ }
+
+ protected List getValueResources(@NotNull final String resourceType, @Nullable Set files) {
final List result = new ArrayList();
Collection resourceFiles = getResourceElements(files);
for (final Resources resources : resourceFiles) {
@@ -217,7 +220,7 @@ public abstract class ResourceManager {
if (!resources.isValid() || myModule.isDisposed() || myModule.getProject().isDisposed()) {
return;
}
- result.addAll(getValueResources(resourceType, resources));
+ result.addAll(getValueResourcesFromElement(resourceType, resources));
}
});
}
@@ -245,7 +248,7 @@ public abstract class ResourceManager {
if (possibleResDir == null || !isResourceDir(possibleResDir.getVirtualFile())) {
return null;
}
- String type = getResourceTypeByDirName(dir.getName());
+ String type = AndroidResourceUtil.getResourceTypeByDirName(dir.getName());
if (type == null) return null;
return isCorrectFileName(type, file.getName()) ? type : null;
}
@@ -267,10 +270,51 @@ public abstract class ResourceManager {
}
@NotNull
- public abstract Collection getValueResourceNames(@NotNull final String resourceType);
+ public Collection getValueResourceNames(@NotNull final String resourceType) {
+ final ResourceType type = ResourceType.getEnum(resourceType);
+
+ if (type == null) {
+ LOG.error("Unknown resource type " + resourceType);
+ return Collections.emptyList();
+ }
+
+ final FileBasedIndex index = FileBasedIndex.getInstance();
+ final ResourceEntry typeMarkerEntry = AndroidValueResourcesIndex.createTypeMarkerEntry(resourceType);
+ final GlobalSearchScope scope = GlobalSearchScope.allScope(myModule.getProject());
+
+ final Map> file2resourceSet = new HashMap>();
+
+ for (Set entrySet : index.getValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, scope)) {
+ for (ResourceEntry entry : entrySet) {
+ final Collection files = index.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, entry, scope);
+
+ for (VirtualFile file : files) {
+ Set resourcesInFile = file2resourceSet.get(file);
+
+ if (resourcesInFile == null) {
+ resourcesInFile = new HashSet();
+ file2resourceSet.put(file, resourcesInFile);
+ }
+ resourcesInFile.add(entry);
+ }
+ }
+ }
+ final Set result = new HashSet();
+
+ for (VirtualFile file : getAllValueResourceFiles()) {
+ final Set entries = file2resourceSet.get(file);
+
+ if (entries != null) {
+ for (ResourceEntry entry : entries) {
+ result.add(entry.getName());
+ }
+ }
+ }
+ return result;
+ }
@NotNull
- public static List getValueResources(@NotNull String resourceType, Resources resources) {
+ public static List getValueResourcesFromElement(@NotNull String resourceType, Resources resources) {
List result = new ArrayList();
if (resourceType.equals("string")) {
result.addAll(resources.getStrings());
@@ -312,19 +356,91 @@ public abstract class ResourceManager {
// searches only declarations such as "@+id/..."
@Nullable
- public abstract List findIdDeclarations(@NotNull String id);
+ public List findIdDeclarations(@NotNull String id) {
+ List declarations = new ArrayList();
+ collectIdDeclarations(id, declarations);
+ return declarations;
+ }
@NotNull
- public abstract Collection getIds();
+ public Collection getIds() {
+ final Project project = myModule.getProject();
+ final GlobalSearchScope scope = GlobalSearchScope.allScope(myModule.getProject());
+
+ final FileBasedIndex index = FileBasedIndex.getInstance();
+ final Map> file2ids = new HashMap>();
+
+ for (String key : index.getAllKeys(AndroidIdIndex.INDEX_ID, project)) {
+ if (!AndroidIdIndex.MARKER.equals(key)) {
+ if (index.getValues(AndroidIdIndex.INDEX_ID, key, scope).size() > 0) {
+
+ for (VirtualFile file : index.getContainingFiles(AndroidIdIndex.INDEX_ID, key, scope)) {
+ Set ids = file2ids.get(file);
+
+ if (ids == null) {
+ ids = new HashSet();
+ file2ids.put(file, ids);
+ }
+ ids.add(key);
+ }
+ }
+ }
+ }
+ final Set result = new HashSet();
+
+ for (VirtualFile resSubdir : getResourceSubdirsToSearchIds()) {
+ for (VirtualFile resFile : resSubdir.getChildren()) {
+ final Set ids = file2ids.get(resFile);
+
+ if (ids != null) {
+ result.addAll(ids);
+ }
+ }
+ }
+ return result;
+ }
+
+ @NotNull
+ protected List getResourceSubdirsToSearchIds() {
+ final List resSubdirs = new ArrayList();
+ resSubdirs.addAll(getResourceSubdirs(ResourceType.LAYOUT.getName()));
+ resSubdirs.addAll(getResourceSubdirs(ResourceType.MENU.getName()));
+ return resSubdirs;
+ }
public List findValueResources(@NotNull String resType, @NotNull String resName) {
return findValueResources(resType, resName, true);
}
@NotNull
- public abstract List findValueResources(@NotNull String resourceType,
- @NotNull String resourceName,
- boolean distinguishDelimetersInName);
+ public List findValueResources(@NotNull String resourceType,
+ @NotNull String resourceName,
+ boolean distinguishDelimetersInName) {
+ final ResourceType type = ResourceType.getEnum(resourceType);
+ if (type == null) {
+ LOG.error("Unknown resource type " + resourceType);
+ return Collections.emptyList();
+ }
+
+ final Collection files = FileBasedIndex.getInstance()
+ .getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, new ResourceEntry(resourceType, resourceName),
+ GlobalSearchScope.allScope(myModule.getProject()));
+
+ if (files.size() == 0) {
+ return Collections.emptyList();
+ }
+ final Set fileSet = new HashSet(files);
+ final List result = new ArrayList();
+
+ for (ResourceElement element : getValueResources(resourceType, fileSet)) {
+ final String name = element.getName().getValue();
+
+ if (equal(resourceName, name, distinguishDelimetersInName)) {
+ result.add(element);
+ }
+ }
+ return result;
+ }
public static boolean isInResourceSubdirectory(@NotNull PsiFile file, @Nullable String resourceType) {
file = file.getOriginalFile();
@@ -382,4 +498,34 @@ public abstract class ResourceManager {
private static boolean containsAndroidJar(@NotNull PsiDirectory psiDirectory) {
return psiDirectory.findFile(SdkConstants.FN_FRAMEWORK_LIBRARY) != null;
}
+
+ public void collectIdDeclarations(@NotNull final String id, final List targets) {
+ final Collection files =
+ FileBasedIndex.getInstance().getContainingFiles(AndroidIdIndex.INDEX_ID, id, GlobalSearchScope.allScope(myModule.getProject()));
+ final Set fileSet = new HashSet(files);
+ final PsiManager psiManager = PsiManager.getInstance(myModule.getProject());
+
+ for (VirtualFile subdir : getResourceSubdirsToSearchIds()) {
+ for (VirtualFile file : subdir.getChildren()) {
+ if (fileSet.contains(file)) {
+ final PsiFile psiFile = psiManager.findFile(file);
+
+ if (psiFile instanceof XmlFile) {
+ psiFile.accept(new XmlRecursiveElementVisitor() {
+ @Override
+ public void visitXmlAttributeValue(XmlAttributeValue attributeValue) {
+ if (AndroidResourceUtil.isIdDeclaration(attributeValue)) {
+ final String idInAttr = AndroidResourceUtil.getResourceNameByReferenceText(attributeValue.getValue());
+
+ if (id.equals(idInAttr)) {
+ targets.add(attributeValue);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+ }
}
diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/SystemResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/SystemResourceManager.java
index 83604208d580..ac61347c3c8d 100644
--- a/plugins/android/src/org/jetbrains/android/resourceManagers/SystemResourceManager.java
+++ b/plugins/android/src/org/jetbrains/android/resourceManagers/SystemResourceManager.java
@@ -15,46 +15,22 @@
*/
package org.jetbrains.android.resourceManagers;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.SdkConstants;
-import com.intellij.lang.injection.InjectedLanguageManager;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.*;
-import com.intellij.psi.xml.*;
-import com.intellij.util.containers.HashMap;
-import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.ConvertContext;
-import org.jetbrains.android.AndroidIdIndex;
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
-import org.jetbrains.android.dom.resources.ResourceElement;
-import org.jetbrains.android.dom.resources.Resources;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.sdk.AndroidTargetData;
-import org.jetbrains.android.util.AndroidResourceUtil;
-import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
-
/**
* @author coyote
*/
public class SystemResourceManager extends ResourceManager {
- private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.resourceManagers.SystemResourceManager");
-
- private volatile Map>> myIdMap;
-
- private volatile Map>> myValueResourcesMap;
-
private final AndroidPlatform myPlatform;
public SystemResourceManager(@NotNull Module module, @NotNull AndroidPlatform androidPlatform) {
@@ -74,19 +50,6 @@ public class SystemResourceManager extends ResourceManager {
return LocalFileSystem.getInstance().findFileByPath(resPath);
}
- @NotNull
- @Override
- public Collection getValueResourceNames(@NotNull String resourceType) {
- final ResourceType type = ResourceType.getEnum(resourceType);
-
- if (type == null) {
- LOG.error("Unknown resource type " + resourceType);
- return Collections.emptyList();
- }
- final Map> map = getValueResourcesMap().get(type);
- return map != null ? map.keySet() : Collections.emptyList();
- }
-
@Nullable
public static SystemResourceManager getInstance(@NotNull ConvertContext context) {
AndroidFacet facet = AndroidFacet.getInstance(context);
@@ -96,193 +59,6 @@ public class SystemResourceManager extends ResourceManager {
@Nullable
public synchronized AttributeDefinitions getAttributeDefinitions() {
final AndroidTargetData targetData = myPlatform.getSdk().getTargetData(myPlatform.getTarget());
- return targetData.getAttrDefs(myModule.getProject());
- }
-
- @Nullable
- public List findIdDeclarations(@NotNull String id) {
- if (myIdMap == null) {
- myIdMap = createIdMap();
- return doFindIdDeclarations(id, false);
- }
- return doFindIdDeclarations(id, true);
- }
-
- @NotNull
- private synchronized Map>> getValueResourcesMap() {
- if (myValueResourcesMap == null) {
- myValueResourcesMap = new HashMap>>();
-
- for (VirtualFile valueResourceDir : getResourceSubdirs(ResourceFolderType.VALUES.getName())) {
- for (final VirtualFile valueResourceFile : valueResourceDir.getChildren()) {
- if (!valueResourceFile.isDirectory() && valueResourceFile.getFileType().equals(StdFileTypes.XML)) {
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- fillValueResourcesMap(valueResourceFile);
- }
- });
- }
- }
- }
- }
- return myValueResourcesMap;
- }
-
- private void fillValueResourcesMap(@NotNull VirtualFile valueResourceFile) {
- final Resources roots = AndroidUtils.loadDomElement(myModule, valueResourceFile, Resources.class);
- if (roots == null) {
- return;
- }
-
- for (ResourceType resType : ResourceType.values()) {
- Map> map = myValueResourcesMap.get(resType);
-
- if (map == null) {
- map = new HashMap>();
- myValueResourcesMap.put(resType, map);
- }
-
- for (ResourceElement element : ResourceManager.getValueResources(resType.getName(), roots)) {
- final String name = element.getName().getValue();
-
- if (name != null) {
- Set fileSet = map.get(name);
-
- if (fileSet == null) {
- fileSet = new HashSet();
- map.put(name, fileSet);
- }
- fileSet.add(valueResourceFile);
- }
- }
- }
-
- PsiManager.getInstance(myModule.getProject()).dropResolveCaches();
- final XmlElement element = roots.getXmlElement();
-
- if (element != null) {
- final PsiFile file = element.getContainingFile();
-
- if (file != null) {
- InjectedLanguageManager.getInstance(myModule.getProject()).dropFileCaches(file);
- }
- }
- }
-
- private List doFindIdDeclarations(@NotNull String id, boolean recreateMapIfCannotResolve) {
- final List> pointers = myIdMap.get(id);
-
- if (pointers == null || pointers.size() == 0) {
- return Collections.emptyList();
- }
- final List result = new ArrayList();
-
- for (SmartPsiElementPointer extends PsiElement> pointer : pointers) {
- final PsiElement element = pointer.getElement();
-
- if (element != null) {
- result.add(element);
- }
- else if (recreateMapIfCannotResolve) {
- myIdMap = createIdMap();
- return doFindIdDeclarations(id, false);
- }
- }
- return result;
- }
-
- @NotNull
- public Collection getIds() {
- if (myIdMap == null) {
- myIdMap = createIdMap();
- }
- return myIdMap.keySet();
- }
-
- @NotNull
- @Override
- public List findValueResources(@NotNull String resourceType,
- @NotNull String resourceName,
- boolean distinguishDelimetersInName) {
- final ResourceType type = ResourceType.getEnum(resourceType);
- if (type == null) {
- LOG.error("Unknown resource type " + resourceType);
- return Collections.emptyList();
- }
-
- final Map> map = getValueResourcesMap().get(type);
- if (map == null) {
- return Collections.emptyList();
- }
-
- final Set fileSet = map.get(resourceName);
- if (fileSet == null) {
- return Collections.emptyList();
- }
-
- final List result = new ArrayList();
-
- for (ResourceElement element : getValueResources(resourceType, fileSet)) {
- final String name = element.getName().getValue();
-
- if (equal(resourceName, name, distinguishDelimetersInName)) {
- result.add(element);
- }
- }
- return result;
- }
-
- @NotNull
- public Map>> createIdMap() {
- Map>> result = new HashMap>>();
- fillIdMap(result);
- return result;
- }
-
- protected void fillIdMap(@NotNull Map>> result) {
- for (String resType : AndroidIdIndex.RES_TYPES_CONTAINING_ID_DECLARATIONS) {
- List resFiles = findResourceFiles(resType);
- for (PsiFile resFile : resFiles) {
- collectIdDeclarations(resFile, result);
- }
- }
- }
-
- protected static void collectIdDeclarations(PsiFile psiFile, Map>> result) {
- if (psiFile instanceof XmlFile) {
- XmlDocument document = ((XmlFile)psiFile).getDocument();
- if (document != null) {
- XmlTag rootTag = document.getRootTag();
- if (rootTag != null) {
- fillMapRecursively(rootTag, result);
- }
- }
- }
- }
-
- private static void fillMapRecursively(@NotNull XmlTag tag, @NotNull Map>> result) {
- XmlAttribute idAttr = tag.getAttribute("id", SdkConstants.NS_RESOURCES);
- if (idAttr != null) {
- XmlAttributeValue idAttrValue = idAttr.getValueElement();
- if (idAttrValue != null) {
- if (AndroidResourceUtil.isIdDeclaration(idAttrValue)) {
- String id = AndroidResourceUtil.getResourceNameByReferenceText(idAttrValue.getValue());
- if (id != null) {
- List> list = result.get(id);
-
- if (list == null) {
- list = new ArrayList>();
- result.put(id, list);
- }
- final SmartPointerManager manager = SmartPointerManager.getInstance(tag.getProject());
- list.add(manager.createSmartPsiElementPointer(idAttr));
- }
- }
- }
- }
- for (XmlTag subtag : tag.getSubTags()) {
- fillMapRecursively(subtag, result);
- }
+ return targetData != null ? targetData.getAttrDefs(myModule.getProject()) : null;
}
}
diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
index 7f422a5134b1..766e05545306 100644
--- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
+++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
@@ -98,6 +98,16 @@ public class AndroidSdkUtils {
if (sdkDir != null) {
addJavaDocAndSources(result, sdkDir);
}
+
+ final String resFolderPath = target.getPath(IAndroidTarget.RESOURCES);
+
+ if (resFolderPath != null) {
+ final VirtualFile resFolder = LocalFileSystem.getInstance().findFileByPath(resFolderPath);
+
+ if (resFolder != null) {
+ result.add(new OrderRoot(resFolder, OrderRootType.CLASSES));
+ }
+ }
return result;
}
diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
index 4d95bb5dc5b1..553fb41e9c4a 100644
--- a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
+++ b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
@@ -24,16 +24,14 @@ import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
-import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
-import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
-import com.intellij.util.indexing.FileBasedIndex;
-import org.jetbrains.android.AndroidIdIndex;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.dom.resources.*;
import org.jetbrains.android.facet.AndroidFacet;
@@ -217,24 +215,34 @@ public class AndroidResourceUtil {
LocalResourceManager manager = facet.getLocalResourceManager();
String fileResType = manager.getFileResourceType(tag.getContainingFile());
if ("values".equals(fileResType)) {
- String resClassName = tag.getName();
- if (resClassName.equals("item")) {
- resClassName = tag.getAttributeValue("type", null);
- }
- else if (resClassName.equals("declare-styleable")) {
- resClassName = "styleable";
- }
- else if (resClassName.endsWith("-array")) {
- resClassName = "array";
- }
- if (resClassName != null) {
- String resourceName = tag.getAttributeValue("name");
- return resourceName != null ? resClassName : null;
- }
+ return getResourceTypeByValueResourceTag(tag);
}
return null;
}
+ @Nullable
+ public static String getResourceTypeByValueResourceTag(XmlTag tag) {
+ String resClassName = tag.getName();
+ resClassName = resClassName.equals("item")
+ ? tag.getAttributeValue("type", null)
+ : getResourceTypeByTagName(resClassName);
+ if (resClassName != null) {
+ final String resourceName = tag.getAttributeValue("name");
+ return resourceName != null ? resClassName : null;
+ }
+ return null;
+ }
+
+ public static String getResourceTypeByTagName(@NotNull String tagName) {
+ if (tagName.equals("declare-styleable")) {
+ tagName = "styleable";
+ }
+ else if (tagName.endsWith("-array")) {
+ tagName = "array";
+ }
+ return tagName;
+ }
+
@Nullable
public static String getResourceClassName(@NotNull PsiField field) {
PsiClass resourceClass = field.getContainingClass();
@@ -268,7 +276,7 @@ public class AndroidResourceUtil {
if (type != null) {
String name = field.getName();
if (type.equals("id")) {
- collectIdDeclarations(name, manager.getModule(), targets);
+ manager.collectIdDeclarations(name, targets);
}
for (PsiFile file : manager.findResourceFiles(type, name, false)) {
targets.add(file);
@@ -356,28 +364,6 @@ public class AndroidResourceUtil {
return null;
}
- public static void collectIdDeclarations(@NotNull final String id, Module module, final List targets) {
- Collection files =
- FileBasedIndex.getInstance().getContainingFiles(AndroidIdIndex.INDEX_ID, id, GlobalSearchScope.projectScope(module.getProject()));
- PsiManager psiManager = PsiManager.getInstance(module.getProject());
- for (VirtualFile file : files) {
- PsiFile psiFile = psiManager.findFile(file);
- if (psiFile instanceof XmlFile) {
- psiFile.accept(new XmlRecursiveElementVisitor() {
- @Override
- public void visitXmlAttributeValue(XmlAttributeValue attributeValue) {
- if (isIdDeclaration(attributeValue)) {
- String idInAttr = getResourceNameByReferenceText(attributeValue.getValue());
- if (id.equals(idInAttr)) {
- targets.add(attributeValue);
- }
- }
- }
- });
- }
- }
- }
-
public static boolean isRJavaField(@NotNull PsiFile file, @NotNull PsiField field) {
PsiClass aClass = field.getContainingClass();
if (aClass != null) {
@@ -435,4 +421,32 @@ public class AndroidResourceUtil {
}
throw new IllegalArgumentException("Incorrect resource type");
}
+
+ @Nullable
+ public static String getResourceTypeByDirName(@NotNull String name) {
+ int index = name.indexOf('-');
+ String type = index >= 0 ? name.substring(0, index) : name;
+ return ArrayUtil.find(ResourceManager.FILE_RESOURCE_TYPES, type) >= 0 ? type : null;
+ }
+
+ @NotNull
+ public static List getResourceSubdirs(@Nullable String resourceType, @NotNull VirtualFile[] resourceDirs) {
+ List dirs = new ArrayList();
+ if (ArrayUtil.find(ResourceManager.FILE_RESOURCE_TYPES, resourceType) < 0 && resourceType != null) {
+ return dirs;
+ }
+ for (VirtualFile resourcesDir : resourceDirs) {
+ if (resourcesDir == null) return dirs;
+ if (resourceType == null) {
+ ContainerUtil.addAll(dirs, resourcesDir.getChildren());
+ }
+ else {
+ for (VirtualFile child : resourcesDir.getChildren()) {
+ String type = getResourceTypeByDirName(child.getName());
+ if (resourceType.equals(type)) dirs.add(child);
+ }
+ }
+ }
+ return dirs;
+ }
}
diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java b/plugins/android/src/org/jetbrains/android/util/ResourceEntry.java
similarity index 88%
rename from plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java
rename to plugins/android/src/org/jetbrains/android/util/ResourceEntry.java
index 868e523eb3f2..c9fbe72541fa 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java
+++ b/plugins/android/src/org/jetbrains/android/util/ResourceEntry.java
@@ -1,4 +1,4 @@
-package org.jetbrains.android.compiler;
+package org.jetbrains.android.util;
import org.jetbrains.annotations.NotNull;
@@ -9,7 +9,7 @@ public class ResourceEntry {
private final String myType;
private final String myName;
- ResourceEntry(@NotNull String type, @NotNull String name) {
+ public ResourceEntry(@NotNull String type, @NotNull String name) {
myType = type;
myName = name;
}
diff --git a/plugins/android/testData/dom/layout/layoutAttrs3.xml b/plugins/android/testData/dom/layout/layoutAttrs3.xml
new file mode 100644
index 000000000000..d3f552d4ac25
--- /dev/null
+++ b/plugins/android/testData/dom/layout/layoutAttrs3.xml
@@ -0,0 +1,3 @@
+
+
\ No newline at end of file
diff --git a/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java b/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java
index 27721ed74b60..966daab2e5cd 100644
--- a/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java
+++ b/plugins/android/testSrc/org/jetbrains/android/AndroidTestCase.java
@@ -29,6 +29,7 @@ import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
@@ -151,6 +152,9 @@ public abstract class AndroidTestCase extends JavaCodeInsightFixtureTestCase {
VirtualFile androidJar = JarFileSystem.getInstance().findFileByPath(androidJarPath);
sdkModificator.addRoot(androidJar, OrderRootType.CLASSES);
+ VirtualFile resFolder = LocalFileSystem.getInstance().findFileByPath(sdkPath + "/platforms/android-1.5/data/res");
+ sdkModificator.addRoot(resFolder, OrderRootType.CLASSES);
+
AndroidSdkAdditionalData data = new AndroidSdkAdditionalData(sdk);
AndroidSdk sdkObject = AndroidSdk.parse(sdkPath, new EmptySdkLog());
data.setBuildTarget(sdkObject.findTargetByName("Android 1.5"));
diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
index bc2c6d48a911..ebf4b0d9ac74 100644
--- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
+++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
@@ -83,6 +83,10 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
doTestHighlighting("layoutAttrs2.xml");
}
+ public void testCheckLayoutAttrs3() throws Throwable {
+ doTestHighlighting("layoutAttrs3.xml");
+ }
+
public void testUnknownAttribute() throws Throwable {
doTestHighlighting("hl1.xml");
}