blob: 7e56a80ed410809df7184a914b5bef51f1b7631a [file] [log] [blame]
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.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.dom.resources.DeclareStyleable;
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.FileResourceProcessor;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.android.util.ResourceFileData;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
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 Map<String, ResourceFileData> myResources = new HashMap<String, ResourceFileData>();
private final String myAndroidTargetHashString;
private final long myManifestTimestamp;
public ResourceNamesValidityState(@NotNull Module module) {
final AndroidFacet facet = AndroidFacet.getInstance(module);
assert facet != null;
final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform();
final IAndroidTarget target = platform != null ? platform.getTarget() : null;
myAndroidTargetHashString = target != null ? target.hashString() : "";
final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(facet);
myManifestTimestamp = manifestFile != null ? manifestFile.getTimeStamp() : -1;
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, "");
final List<DeclareStyleable> styleables = resources.getDeclareStyleables();
addValueResources(file, ResourceType.DECLARE_STYLEABLE, styleables, myResources, "");
for (DeclareStyleable styleable : styleables) {
final String styleableName = styleable.getName().getValue();
if (styleableName != null) {
addValueResources(file, ResourceType.DECLARE_STYLEABLE, styleable.getAttrs(), myResources, styleableName);
}
}
}
manager.processFileResources(null, new FileResourceProcessor() {
@Override
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
final ResourceType type = ResourceType.getEnum(resFolderType);
final boolean idProvidingResource = type != null && ArrayUtil.find(AndroidCommonUtils.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
ResourceFileData data = myResources.get(resFile.getPath());
if (data == null) {
data = new ResourceFileData();
myResources.put(resFile.getPath(), data);
}
if (idProvidingResource) {
data.setTimestamp(resFile.getTimeStamp());
}
return true;
}
});
}
private static void addValueResources(VirtualFile file,
ResourceType resType,
Collection<? extends ResourceElement> resourceElements,
Map<String, ResourceFileData> result,
String context) {
for (ResourceElement element : resourceElements) {
final String name = element.getName().getValue();
if (name != null) {
ResourceFileData data = result.get(file.getPath());
if (data == null) {
data = new ResourceFileData();
result.put(file.getPath(), data);
}
data.addValueResource(new ResourceEntry(resType.getName(), name, context));
}
}
}
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 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();
final String resContext = in.readUTF();
valueResources.add(new ResourceEntry(resType, resName, resContext));
}
final long fileTimestamp = in.readLong();
myResources.put(filePath, new ResourceFileData(valueResources, fileTimestamp));
}
}
@Override
public boolean equalsTo(ValidityState otherState) {
if (!(otherState instanceof ResourceNamesValidityState)) {
return false;
}
final ResourceNamesValidityState other = (ResourceNamesValidityState)otherState;
return other.myAndroidTargetHashString.equals(myAndroidTargetHashString) &&
other.myManifestTimestamp == myManifestTimestamp &&
other.myResources.equals(myResources);
}
@Override
public void save(DataOutput out) throws IOException {
out.writeUTF(myAndroidTargetHashString);
out.writeLong(myManifestTimestamp);
out.writeInt(myResources.size());
for (Map.Entry<String, ResourceFileData> entry : myResources.entrySet()) {
out.writeUTF(entry.getKey());
final ResourceFileData 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.writeUTF(resource.getContext());
}
out.writeLong(data.getTimestamp());
}
}
}