Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Lobas
2012-04-10 19:25:43 +04:00
6 changed files with 199 additions and 39 deletions
@@ -24,6 +24,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -174,8 +175,9 @@ public class AndroidResourcesLineMarkerProvider implements LineMarkerProvider {
private static Map<MyResourceEntry, List<PsiElement>> buildLocalResourceMap(@NotNull Project project,
@NotNull final LocalResourceManager resManager) {
final Map<MyResourceEntry, List<PsiElement>> result = new HashMap<MyResourceEntry, List<PsiElement>>();
Collection<Resources> resourceFiles = resManager.getResourceElements();
for (Resources res : resourceFiles) {
List<Pair<Resources,VirtualFile>> resourceFiles = resManager.getResourceElements();
for (Pair<Resources, VirtualFile> pair : resourceFiles) {
final Resources res = pair.getFirst();
for (ResourceType valueResourceType : AndroidResourceUtil.VALUE_RESOURCE_TYPES) {
for (ResourceElement valueResource : AndroidResourceUtil.getValueResourcesFromElement(valueResourceType.getName(), res)) {
addResource(valueResourceType.getName(), valueResource, result);
@@ -729,8 +729,9 @@ public class AndroidCompileUtil {
}
}
for (final Resources resources : manager.getResourceElements()) {
waitForSmartMode(project);
for (final Pair<Resources, VirtualFile> pair : manager.getResourceElements()) {
final Resources resources = pair.getFirst();
waitForSmartMode(project);
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
@@ -1,29 +1,44 @@
package org.jetbrains.android.compiler;
import com.android.resources.ResourceType;
import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.compiler.ValidityState;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.impl.FileIndexImplUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.dom.resources.ResourceElement;
import org.jetbrains.android.dom.resources.Resources;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Set;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author Eugene.Kudelevsky
*/
public class ResourceNamesValidityState implements ValidityState {
private final Set<ResourceEntry> myResourcesSet = new HashSet<ResourceEntry>();
private final Map<String, MyResourceFileData> myResources = new HashMap<String, MyResourceFileData>();
private final String myAndroidTargetHashString;
private final long myManifestTimestamp;
public ResourceNamesValidityState(@NotNull Module module) {
final AndroidFacet facet = AndroidFacet.getInstance(module);
assert facet != null;
@@ -35,19 +50,83 @@ public class ResourceNamesValidityState implements ValidityState {
final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(facet);
myManifestTimestamp = manifestFile != null ? manifestFile.getModificationStamp() : -1;
AndroidCompileUtil.collectAllResources(facet, myResourcesSet);
final LocalResourceManager manager = facet.getLocalResourceManager();
for (final Pair<Resources, VirtualFile> pair : manager.getResourceElements()) {
final Resources resources = pair.getFirst();
final VirtualFile file = pair.getSecond();
for (final ResourceType resType : AndroidResourceUtil.VALUE_RESOURCE_TYPES) {
addValueResources(file, resType, AndroidResourceUtil.getValueResourcesFromElement(resType.getName(), resources), myResources);
}
addValueResources(file, ResourceType.ATTR, resources.getAttrs(), myResources);
addValueResources(file, ResourceType.DECLARE_STYLEABLE, resources.getDeclareStyleables(), myResources);
}
for (final VirtualFile subdir : manager.getResourceSubdirs(null)) {
final String subdirName = subdir.getName();
final int index = subdirName.indexOf('-');
final String typeName = index >= 0 ? subdirName.substring(0, index) : subdirName;
final ResourceType type = ResourceType.getEnum(typeName);
final boolean idProvidingResource = type != null && ArrayUtil.find(ResourceManager.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
FileIndexImplUtil.iterateRecursively(subdir, VirtualFileFilter.ALL, new ContentIterator() {
@Override
public boolean processFile(VirtualFile fileOrDir) {
if (!fileOrDir.isDirectory()) {
MyResourceFileData data = myResources.get(fileOrDir.getPath());
if (data == null) {
data = new MyResourceFileData();
myResources.put(fileOrDir.getPath(), data);
}
if (idProvidingResource) {
data.setTimestamp(fileOrDir.getTimeStamp());
}
}
return true;
}
});
}
}
private static void addValueResources(VirtualFile file,
ResourceType resType,
Collection<? extends ResourceElement> resourceElements,
Map<String, MyResourceFileData> result) {
for (ResourceElement element : resourceElements) {
final String name = element.getName().getValue();
if (name != null) {
MyResourceFileData data = result.get(file.getPath());
if (data == null) {
data = new MyResourceFileData();
result.put(file.getPath(), data);
}
data.addValueResource(new ResourceEntry(resType.getName(), name));
}
}
}
public ResourceNamesValidityState(@NotNull DataInput in) throws IOException {
myAndroidTargetHashString = in.readUTF();
myManifestTimestamp = in.readLong();
final int resourcesCount = in.readInt();
for (int i = 0; i < resourcesCount; i++) {
final String type = in.readUTF();
final String name = in.readUTF();
myResourcesSet.add(new ResourceEntry(type, name));
final String filePath = in.readUTF();
final int valueResourcesCount = in.readInt();
final List<ResourceEntry> valueResources = new ArrayList<ResourceEntry>(valueResourcesCount);
for (int j = 0; j < valueResourcesCount; j++) {
final String resType = in.readUTF();
final String resName = in.readUTF();
valueResources.add(new ResourceEntry(resType, resName));
}
final long fileTimestamp = in.readLong();
myResources.put(filePath, new MyResourceFileData(valueResources, fileTimestamp));
}
}
@@ -56,24 +135,86 @@ public class ResourceNamesValidityState implements ValidityState {
if (!(otherState instanceof ResourceNamesValidityState)) {
return false;
}
final ResourceNamesValidityState other = (ResourceNamesValidityState)otherState;
return other.myAndroidTargetHashString.equals(myAndroidTargetHashString) &&
other.myManifestTimestamp == myManifestTimestamp &&
other.myResourcesSet.equals(myResourcesSet);
other.myResources.equals(myResources);
}
@Override
public void save(DataOutput out) throws IOException {
out.writeUTF(myAndroidTargetHashString);
out.writeLong(myManifestTimestamp);
out.writeInt(myResourcesSet.size());
for (ResourceEntry resourceEntry : myResourcesSet) {
out.writeUTF(resourceEntry.getType());
out.writeUTF(resourceEntry.getName());
out.writeInt(myResources.size());
for (Map.Entry<String, MyResourceFileData> entry : myResources.entrySet()) {
out.writeUTF(entry.getKey());
final MyResourceFileData data = entry.getValue();
final List<ResourceEntry> valueResources = data.getValueResources();
out.writeInt(valueResources.size());
for (ResourceEntry resource : valueResources) {
out.writeUTF(resource.getType());
out.writeUTF(resource.getName());
}
out.writeLong(data.getTimestamp());
}
}
private static class MyResourceFileData {
// order matters because of id assigning in R.java
private final List<ResourceEntry> myValueResources;
private long myTimestamp;
MyResourceFileData() {
this(new ArrayList<ResourceEntry>(), 0);
}
private MyResourceFileData(@NotNull List<ResourceEntry> valueResources, long timestamp) {
myValueResources = valueResources;
myTimestamp = timestamp;
}
@NotNull
List<ResourceEntry> getValueResources() {
return myValueResources;
}
long getTimestamp() {
return myTimestamp;
}
public void setTimestamp(long timestamp) {
myTimestamp = timestamp;
}
public void addValueResource(@NotNull ResourceEntry entry) {
myValueResources.add(entry);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyResourceFileData data = (MyResourceFileData)o;
if (myTimestamp != data.myTimestamp) return false;
if (!myValueResources.equals(data.myValueResources)) return false;
return true;
}
@Override
public int hashCode() {
int result = myValueResources.hashCode();
result = 31 * result + (int)(myTimestamp ^ (myTimestamp >>> 32));
return result;
}
}
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -96,7 +97,7 @@ public class LocalResourceManager extends ResourceManager {
return AndroidRootUtil.getResourceDir(getFacet());
}
public List<Resources> getResourceElements() {
public List<Pair<Resources, VirtualFile>> getResourceElements() {
return getResourceElements(null);
}
@@ -200,7 +201,8 @@ public class LocalResourceManager extends ResourceManager {
@NotNull
public List<Attr> findAttrs(@NotNull String name) {
List<Attr> list = new ArrayList<Attr>();
for (Resources res : getResourceElements()) {
for (Pair<Resources, VirtualFile> pair : getResourceElements()) {
final Resources res = pair.getFirst();
for (Attr attr : res.getAttrs()) {
if (name.equals(attr.getName().getValue())) {
list.add(attr);
@@ -219,7 +221,8 @@ public class LocalResourceManager extends ResourceManager {
public List<DeclareStyleable> findStyleables(@NotNull String name) {
List<DeclareStyleable> list = new ArrayList<DeclareStyleable>();
for (Resources res : getResourceElements()) {
for (Pair<Resources, VirtualFile> pair : getResourceElements()) {
final Resources res = pair.getFirst();
for (DeclareStyleable styleable : res.getDeclareStyleables()) {
if (name.equals(styleable.getName().getValue())) {
list.add(styleable);
@@ -17,11 +17,11 @@ package org.jetbrains.android.resourceManagers;
import com.android.resources.ResourceType;
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.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
@@ -53,7 +53,9 @@ 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 ResourceType[] ID_PROVIDING_RESOURCE_TYPES = new ResourceType[] {
ResourceType.LAYOUT, ResourceType.MENU
};
protected final Module myModule;
protected final AndroidFacet myFacet;
@@ -130,17 +132,19 @@ public abstract class ResourceManager {
return findResourceFiles(resType, null, true);
}
protected List<Resources> getResourceElements(@Nullable Set<VirtualFile> files) {
protected List<Pair<Resources, VirtualFile>> getResourceElements(@Nullable Set<VirtualFile> files) {
return getRootDomElements(Resources.class, files);
}
private <T extends DomElement> List<T> getRootDomElements(@NotNull Class<T> elementType,
@Nullable Set<VirtualFile> files) {
final List<T> result = new ArrayList<T>();
private <T extends DomElement> List<Pair<T, VirtualFile>> getRootDomElements(@NotNull Class<T> elementType,
@Nullable Set<VirtualFile> files) {
final List<Pair<T, VirtualFile>> result = new ArrayList<Pair<T, VirtualFile>>();
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);
final T element = AndroidUtils.loadDomElement(myModule, file, elementType);
if (element != null) {
result.add(new Pair<T, VirtualFile>(element, file));
}
}
}
return result;
@@ -162,8 +166,9 @@ public abstract class ResourceManager {
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) {
List<Pair<Resources, VirtualFile>> resourceFiles = getResourceElements(files);
for (final Pair<Resources, VirtualFile> pair : resourceFiles) {
final Resources resources = pair.getFirst();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
@@ -337,10 +342,11 @@ public abstract class ResourceManager {
}
@NotNull
private List<VirtualFile> getResourceSubdirsToSearchIds() {
public List<VirtualFile> getResourceSubdirsToSearchIds() {
final List<VirtualFile> resSubdirs = new ArrayList<VirtualFile>();
resSubdirs.addAll(getResourceSubdirs(ResourceType.LAYOUT.getName()));
resSubdirs.addAll(getResourceSubdirs(ResourceType.MENU.getName()));
for (ResourceType type : ID_PROVIDING_RESOURCE_TYPES) {
resSubdirs.addAll(getResourceSubdirs(type.getName()));
}
return resSubdirs;
}
@@ -31,6 +31,7 @@ import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.htmlInspections.RequiredAttributesInspection;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
@@ -170,6 +171,12 @@ public class XmlTagInsertHandler implements InsertHandler<LookupElement> {
if (myAttrValueMarker == null) {
return;
}
final UndoManager manager = UndoManager.getInstance(project);
if (manager.isUndoInProgress() || manager.isRedoInProgress()) {
return;
}
if (chooseAttributeName) {
final int startOffset = myAttrValueMarker.getStartOffset();
final int endOffset = myAttrValueMarker.getEndOffset();