blob: 5ca750b928edfc5c1dfaa8a06f01df50c46ded5c [file] [log] [blame]
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.android;
import com.android.SdkConstants;
import com.android.resources.ResourceType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.xml.XmlFile;
import com.intellij.xml.XmlSchemaProvider;
import gnu.trove.THashMap;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.dom.manifest.ManifestDomFileDescription;
import org.jetbrains.android.dom.xml.XmlResourceDomFileDescription;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.android.SdkConstants.*;
/**
* Created by IntelliJ IDEA.
* User: Eugene.Kudelevsky
* Date: Aug 12, 2009
* Time: 6:49:18 PM
* To change this template use File | Settings | File Templates.
*/
public class AndroidXmlSchemaProvider extends XmlSchemaProvider {
private static final Key<Map<String, CachedValue<XmlFile>>> DESCRIPTORS_MAP_IN_MODULE = Key.create("ANDROID_DESCRIPTORS_MAP_IN_MODULE");
@Override
public XmlFile getSchema(@NotNull @NonNls String url, @Nullable final Module module, @NotNull PsiFile baseFile) {
if (module == null || AndroidFacet.getInstance(module) == null) return null;
Map<String, CachedValue<XmlFile>> descriptors = module.getUserData(DESCRIPTORS_MAP_IN_MODULE);
if (descriptors == null) {
descriptors = new THashMap<String, CachedValue<XmlFile>>();
module.putUserData(DESCRIPTORS_MAP_IN_MODULE, descriptors);
}
CachedValue<XmlFile> reference = descriptors.get(url);
if (reference != null) {
return reference.getValue();
}
CachedValuesManager manager = CachedValuesManager.getManager(module.getProject());
reference = manager.createCachedValue(new CachedValueProvider<XmlFile>() {
@Override
public Result<XmlFile> compute() {
final URL resource = AndroidXmlSchemaProvider.class.getResource("android.xsd");
final VirtualFile fileByURL = VfsUtil.findFileByURL(resource);
XmlFile result = (XmlFile)PsiManager.getInstance(module.getProject()).findFile(fileByURL).copy();
return new Result<XmlFile>(result, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
descriptors.put(url, reference);
return reference.getValue();
}
@Override
public boolean isAvailable(@NotNull final XmlFile file) {
final PsiFile f = file.getOriginalFile();
if (!(f instanceof XmlFile)) {
return false;
}
final XmlFile originalFile = (XmlFile)f;
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
if (isXmlResourceFile(originalFile) ||
ManifestDomFileDescription.isManifestFile(originalFile)) {
return AndroidFacet.getInstance(originalFile) != null;
}
return false;
}
});
}
private static boolean isXmlResourceFile(XmlFile file) {
if (!AndroidResourceUtil.isInResourceSubdirectory(file, null)) {
return false;
}
final PsiDirectory parent = file.getParent();
if (parent == null) {
return false;
}
final String resType = AndroidCommonUtils.getResourceTypeByDirName(parent.getName());
if (resType == null) {
return false;
}
if (resType.equals(ResourceType.XML.getName())) {
return XmlResourceDomFileDescription.isXmlResourceFile(file);
}
return !resType.equals("raw");
}
@NotNull
@Override
public Set<String> getAvailableNamespaces(@NotNull XmlFile file, @Nullable String tagName) {
Set<String> result = new HashSet<String>();
AndroidFacet facet = AndroidFacet.getInstance(file);
if (facet != null) {
result.add(SdkConstants.NS_RESOURCES);
String localNs = getLocalXmlNamespace(facet);
if (localNs != null) {
result.add(localNs);
}
result.add(SdkConstants.TOOLS_URI);
}
return result;
}
@Override
public String getDefaultPrefix(@NotNull @NonNls String namespace, @NotNull XmlFile context) {
if (ANDROID_URI.equals(namespace)) {
return ANDROID_NS_NAME;
}
else if (namespace.equals(TOOLS_URI)) {
return TOOLS_PREFIX;
}
else if (namespace.equals(AUTO_URI) || namespace.startsWith(URI_PREFIX)) {
return APP_PREFIX;
}
return null;
}
@Nullable
public static String getLocalXmlNamespace(@NotNull AndroidFacet facet) {
if (facet.isLibraryProject() || facet.requiresAndroidModel()) {
return SdkConstants.AUTO_URI;
}
final Manifest manifest = facet.getManifest();
if (manifest != null) {
String aPackage = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Override
@Nullable
public String compute() {
return manifest.getPackage().getValue();
}
});
if (aPackage != null && aPackage.length() != 0) {
return SdkConstants.URI_PREFIX + aPackage;
}
}
return null;
}
}