mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -173,6 +173,7 @@
|
||||
serviceImplementation="org.jetbrains.android.maven.AndroidExternalApklibDependenciesManager"/>
|
||||
<xml.xmlExtension implementation="org.jetbrains.android.dom.AndroidXmlExtension" order="first"/>
|
||||
<fileBasedIndex implementation="org.jetbrains.android.AndroidIdIndex"/>
|
||||
<fileBasedIndex implementation="org.jetbrains.android.AndroidValueResourcesIndex"/>
|
||||
<referencesSearch implementation="org.jetbrains.android.AndroidReferenceSearchExecutor"/>
|
||||
<projectService serviceInterface="org.jetbrains.android.compiler.AndroidDexCompilerConfiguration"
|
||||
serviceImplementation="org.jetbrains.android.compiler.AndroidDexCompilerConfiguration"/>
|
||||
|
||||
@@ -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<String> {
|
||||
|
||||
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<String, Void, FileContent> INDEXER = new DataIndexer<String, Void, FileContent>() {
|
||||
@NotNull
|
||||
public Map<String, Void> map(FileContent inputData) {
|
||||
PsiFile file = inputData.getPsiFile();
|
||||
if (file instanceof XmlFile) {
|
||||
final HashMap<String, Void> ids = new HashMap<String, Void>();
|
||||
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<String, Void> ids = new HashMap<String, Void>();
|
||||
|
||||
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<String, Void> getName() {
|
||||
return INDEX_ID;
|
||||
@@ -121,6 +106,6 @@ public class AndroidIdIndex extends ScalarIndexExtension<String> {
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider {
|
||||
Collection<Resources> 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<VirtualFile> 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<PsiElement>();
|
||||
if (resType.equals("id")) {
|
||||
AndroidResourceUtil.collectIdDeclarations(fieldName, manager.getModule(), targets);
|
||||
manager.collectIdDeclarations(fieldName, targets);
|
||||
}
|
||||
List<PsiElement> resources = resourceMap.get(new MyResourceEntry(fieldName, resType));
|
||||
if (resources != null) {
|
||||
|
||||
@@ -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<ResourceEntry, Set<ResourceEntry>> {
|
||||
public static final ID<ResourceEntry, Set<ResourceEntry>> 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<ResourceEntry, Set<ResourceEntry>, FileContent> myIndexer =
|
||||
new DataIndexer<ResourceEntry, Set<ResourceEntry>, FileContent>() {
|
||||
@NotNull
|
||||
public Map<ResourceEntry, Set<ResourceEntry>> map(FileContent inputData) {
|
||||
|
||||
if (CharArrayUtil.indexOf(inputData.getContentAsText(), "<resources", 0) < 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Map<ResourceEntry, Set<ResourceEntry>> result = new HashMap<ResourceEntry, Set<ResourceEntry>>();
|
||||
|
||||
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.<ResourceEntry>emptySet());
|
||||
|
||||
final ResourceEntry typeMarkerEntry = createTypeMarkerEntry(resType);
|
||||
Set<ResourceEntry> set = result.get(typeMarkerEntry);
|
||||
|
||||
if (set == null) {
|
||||
set = new HashSet<ResourceEntry>();
|
||||
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<ResourceEntry> myKeyDescriptor = new KeyDescriptor<ResourceEntry>() {
|
||||
@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<Set<ResourceEntry>> myValueExternalizer = new DataExternalizer<Set<ResourceEntry>>() {
|
||||
@Override
|
||||
public void save(DataOutput out, Set<ResourceEntry> value) throws IOException {
|
||||
out.writeInt(value.size());
|
||||
|
||||
for (ResourceEntry entry : value) {
|
||||
myKeyDescriptor.save(out, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<ResourceEntry> read(DataInput in) throws IOException {
|
||||
final int size = in.readInt();
|
||||
|
||||
if (size == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
final Set<ResourceEntry> result = new HashSet<ResourceEntry>(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
result.add(myKeyDescriptor.read(in));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ID<ResourceEntry, Set<ResourceEntry>> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataIndexer<ResourceEntry, Set<ResourceEntry>, FileContent> getIndexer() {
|
||||
return myIndexer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyDescriptor<ResourceEntry> getKeyDescriptor() {
|
||||
return myKeyDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataExternalizer<Set<ResourceEntry>> getValueExternalizer() {
|
||||
return myValueExternalizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileBasedIndex.InputFilter getInputFilter() {
|
||||
return myInputFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOnFileContent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+2
-74
@@ -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<Resources> getResourceElements() {
|
||||
return getResourceElements(getAllResourceFiles());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<VirtualFile> getAllResourceFiles() {
|
||||
final Set<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
|
||||
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<String> getValueResourceNames(@NotNull String resourceType) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
for (ResourceElement element : getValueResources(resourceType)) {
|
||||
final String name = element.getName().getValue();
|
||||
|
||||
if (name != null) {
|
||||
result.add(name);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ResourceElement> getValueResources(@NotNull final String resourceType) {
|
||||
return getValueResources(resourceType, getAllResourceFiles());
|
||||
return getValueResources(resourceType, null);
|
||||
}
|
||||
|
||||
private static void collectResourceDirs(Module module, Set<VirtualFile> result, Set<Module> visited) {
|
||||
@@ -193,43 +158,6 @@ public class LocalResourceManager extends ResourceManager {
|
||||
myAttrDefs = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<PsiElement> findIdDeclarations(@NotNull String id) {
|
||||
List<PsiElement> declarations = new ArrayList<PsiElement>();
|
||||
AndroidResourceUtil.collectIdDeclarations(id, myModule, declarations);
|
||||
return declarations;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getIds() {
|
||||
List<String> result = new ArrayList<String>();
|
||||
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<ResourceElement> findValueResources(@NotNull String resourceType,
|
||||
@NotNull String resourceName,
|
||||
boolean distinguishDelimetersInName) {
|
||||
List<ResourceElement> elements = new ArrayList<ResourceElement>();
|
||||
for (ResourceElement element : getValueResources(resourceType)) {
|
||||
GenericAttributeValue<String> name = element.getName();
|
||||
if (name != null && equal(resourceName, name.getValue(), distinguishDelimetersInName)) {
|
||||
elements.add(element);
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Attr> findAttrs(@NotNull String name) {
|
||||
List<Attr> list = new ArrayList<Attr>();
|
||||
|
||||
@@ -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<String> REFERABLE_RESOURCE_TYPES = new HashSet<String>();
|
||||
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<VirtualFile> getResourceSubdirs(@Nullable String resourceType) {
|
||||
List<VirtualFile> dirs = new ArrayList<VirtualFile>();
|
||||
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<Resources> getResourceElements(@NotNull Set<VirtualFile> files) {
|
||||
protected List<Resources> getResourceElements(@Nullable Set<VirtualFile> files) {
|
||||
return getRootDomElements(Resources.class, files);
|
||||
}
|
||||
|
||||
private <T extends DomElement> List<T> getRootDomElements(@NotNull Class<T> elementType,
|
||||
@NotNull Collection<VirtualFile> files) {
|
||||
@Nullable Set<VirtualFile> files) {
|
||||
final List<T> result = new ArrayList<T>();
|
||||
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<ResourceElement> getValueResources(final String resourceType, Set<VirtualFile> files) {
|
||||
@NotNull
|
||||
protected Set<VirtualFile> getAllValueResourceFiles() {
|
||||
final Set<VirtualFile> files = new HashSet<VirtualFile>();
|
||||
|
||||
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<ResourceElement> getValueResources(@NotNull final String resourceType, @Nullable Set<VirtualFile> files) {
|
||||
final List<ResourceElement> result = new ArrayList<ResourceElement>();
|
||||
Collection<Resources> 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<String> getValueResourceNames(@NotNull final String resourceType);
|
||||
public Collection<String> 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<VirtualFile, Set<ResourceEntry>> file2resourceSet = new HashMap<VirtualFile, Set<ResourceEntry>>();
|
||||
|
||||
for (Set<ResourceEntry> entrySet : index.getValues(AndroidValueResourcesIndex.INDEX_ID, typeMarkerEntry, scope)) {
|
||||
for (ResourceEntry entry : entrySet) {
|
||||
final Collection<VirtualFile> files = index.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, entry, scope);
|
||||
|
||||
for (VirtualFile file : files) {
|
||||
Set<ResourceEntry> resourcesInFile = file2resourceSet.get(file);
|
||||
|
||||
if (resourcesInFile == null) {
|
||||
resourcesInFile = new HashSet<ResourceEntry>();
|
||||
file2resourceSet.put(file, resourcesInFile);
|
||||
}
|
||||
resourcesInFile.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
final Set<String> result = new HashSet<String>();
|
||||
|
||||
for (VirtualFile file : getAllValueResourceFiles()) {
|
||||
final Set<ResourceEntry> entries = file2resourceSet.get(file);
|
||||
|
||||
if (entries != null) {
|
||||
for (ResourceEntry entry : entries) {
|
||||
result.add(entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<ResourceElement> getValueResources(@NotNull String resourceType, Resources resources) {
|
||||
public static List<ResourceElement> getValueResourcesFromElement(@NotNull String resourceType, Resources resources) {
|
||||
List<ResourceElement> result = new ArrayList<ResourceElement>();
|
||||
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<PsiElement> findIdDeclarations(@NotNull String id);
|
||||
public List<PsiElement> findIdDeclarations(@NotNull String id) {
|
||||
List<PsiElement> declarations = new ArrayList<PsiElement>();
|
||||
collectIdDeclarations(id, declarations);
|
||||
return declarations;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract Collection<String> getIds();
|
||||
public Collection<String> getIds() {
|
||||
final Project project = myModule.getProject();
|
||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(myModule.getProject());
|
||||
|
||||
final FileBasedIndex index = FileBasedIndex.getInstance();
|
||||
final Map<VirtualFile, Set<String>> file2ids = new HashMap<VirtualFile, Set<String>>();
|
||||
|
||||
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<String> ids = file2ids.get(file);
|
||||
|
||||
if (ids == null) {
|
||||
ids = new HashSet<String>();
|
||||
file2ids.put(file, ids);
|
||||
}
|
||||
ids.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Set<String> result = new HashSet<String>();
|
||||
|
||||
for (VirtualFile resSubdir : getResourceSubdirsToSearchIds()) {
|
||||
for (VirtualFile resFile : resSubdir.getChildren()) {
|
||||
final Set<String> ids = file2ids.get(resFile);
|
||||
|
||||
if (ids != null) {
|
||||
result.addAll(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected List<VirtualFile> getResourceSubdirsToSearchIds() {
|
||||
final List<VirtualFile> resSubdirs = new ArrayList<VirtualFile>();
|
||||
resSubdirs.addAll(getResourceSubdirs(ResourceType.LAYOUT.getName()));
|
||||
resSubdirs.addAll(getResourceSubdirs(ResourceType.MENU.getName()));
|
||||
return resSubdirs;
|
||||
}
|
||||
|
||||
public List<ResourceElement> findValueResources(@NotNull String resType, @NotNull String resName) {
|
||||
return findValueResources(resType, resName, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract List<ResourceElement> findValueResources(@NotNull String resourceType,
|
||||
@NotNull String resourceName,
|
||||
boolean distinguishDelimetersInName);
|
||||
public List<ResourceElement> 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<VirtualFile> files = FileBasedIndex.getInstance()
|
||||
.getContainingFiles(AndroidValueResourcesIndex.INDEX_ID, new ResourceEntry(resourceType, resourceName),
|
||||
GlobalSearchScope.allScope(myModule.getProject()));
|
||||
|
||||
if (files.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Set<VirtualFile> fileSet = new HashSet<VirtualFile>(files);
|
||||
final List<ResourceElement> result = new ArrayList<ResourceElement>();
|
||||
|
||||
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<PsiElement> targets) {
|
||||
final Collection<VirtualFile> files =
|
||||
FileBasedIndex.getInstance().getContainingFiles(AndroidIdIndex.INDEX_ID, id, GlobalSearchScope.allScope(myModule.getProject()));
|
||||
final Set<VirtualFile> fileSet = new HashSet<VirtualFile>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-225
@@ -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<String, List<SmartPsiElementPointer<? extends PsiElement>>> myIdMap;
|
||||
|
||||
private volatile Map<ResourceType, Map<String, Set<VirtualFile>>> 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<String> getValueResourceNames(@NotNull String resourceType) {
|
||||
final ResourceType type = ResourceType.getEnum(resourceType);
|
||||
|
||||
if (type == null) {
|
||||
LOG.error("Unknown resource type " + resourceType);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Map<String, Set<VirtualFile>> map = getValueResourcesMap().get(type);
|
||||
return map != null ? map.keySet() : Collections.<String>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<PsiElement> findIdDeclarations(@NotNull String id) {
|
||||
if (myIdMap == null) {
|
||||
myIdMap = createIdMap();
|
||||
return doFindIdDeclarations(id, false);
|
||||
}
|
||||
return doFindIdDeclarations(id, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private synchronized Map<ResourceType, Map<String, Set<VirtualFile>>> getValueResourcesMap() {
|
||||
if (myValueResourcesMap == null) {
|
||||
myValueResourcesMap = new HashMap<ResourceType, Map<String, Set<VirtualFile>>>();
|
||||
|
||||
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<String, Set<VirtualFile>> map = myValueResourcesMap.get(resType);
|
||||
|
||||
if (map == null) {
|
||||
map = new HashMap<String, Set<VirtualFile>>();
|
||||
myValueResourcesMap.put(resType, map);
|
||||
}
|
||||
|
||||
for (ResourceElement element : ResourceManager.getValueResources(resType.getName(), roots)) {
|
||||
final String name = element.getName().getValue();
|
||||
|
||||
if (name != null) {
|
||||
Set<VirtualFile> fileSet = map.get(name);
|
||||
|
||||
if (fileSet == null) {
|
||||
fileSet = new HashSet<VirtualFile>();
|
||||
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<PsiElement> doFindIdDeclarations(@NotNull String id, boolean recreateMapIfCannotResolve) {
|
||||
final List<SmartPsiElementPointer<? extends PsiElement>> pointers = myIdMap.get(id);
|
||||
|
||||
if (pointers == null || pointers.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<PsiElement> result = new ArrayList<PsiElement>();
|
||||
|
||||
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<String> getIds() {
|
||||
if (myIdMap == null) {
|
||||
myIdMap = createIdMap();
|
||||
}
|
||||
return myIdMap.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<ResourceElement> 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<String, Set<VirtualFile>> map = getValueResourcesMap().get(type);
|
||||
if (map == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Set<VirtualFile> fileSet = map.get(resourceName);
|
||||
if (fileSet == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<ResourceElement> result = new ArrayList<ResourceElement>();
|
||||
|
||||
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<String, List<SmartPsiElementPointer<? extends PsiElement>>> createIdMap() {
|
||||
Map<String, List<SmartPsiElementPointer<? extends PsiElement>>> result = new HashMap<String, List<SmartPsiElementPointer<? extends PsiElement>>>();
|
||||
fillIdMap(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void fillIdMap(@NotNull Map<String, List<SmartPsiElementPointer<? extends PsiElement>>> result) {
|
||||
for (String resType : AndroidIdIndex.RES_TYPES_CONTAINING_ID_DECLARATIONS) {
|
||||
List<PsiFile> resFiles = findResourceFiles(resType);
|
||||
for (PsiFile resFile : resFiles) {
|
||||
collectIdDeclarations(resFile, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static void collectIdDeclarations(PsiFile psiFile, Map<String, List<SmartPsiElementPointer<? extends PsiElement>>> 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<String, List<SmartPsiElementPointer<? extends PsiElement>>> 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<SmartPsiElementPointer<? extends PsiElement>> list = result.get(id);
|
||||
|
||||
if (list == null) {
|
||||
list = new ArrayList<SmartPsiElementPointer<? extends PsiElement>>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PsiElement> targets) {
|
||||
Collection<VirtualFile> 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<VirtualFile> getResourceSubdirs(@Nullable String resourceType, @NotNull VirtualFile[] resourceDirs) {
|
||||
List<VirtualFile> dirs = new ArrayList<VirtualFile>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="<error>@android:style/unknownStyle</error>">
|
||||
</LinearLayout>
|
||||
@@ -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"));
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user