blob: 48631b48a34a203b8f8e2c917da5fb1c7a527902 [file] [log] [blame]
package org.jetbrains.android.dom.resources;
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
import com.intellij.openapi.module.Module;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.ResolveCache;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.*;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* @author Eugene.Kudelevsky
*/
public class DeclareStyleableNameConverter extends Converter<String> implements CustomReferenceConverter<String> {
@Override
public String fromString(@Nullable @NonNls String s, ConvertContext context) {
return s;
}
@Override
public String toString(@Nullable String s, ConvertContext context) {
return s;
}
@NotNull
@Override
public PsiReference[] createReferences(GenericDomValue<String> value, PsiElement element, ConvertContext context) {
final Module module = context.getModule();
if (module != null) {
final AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet != null) {
return new PsiReference[]{new MyReference(facet, value)};
}
}
return PsiReference.EMPTY_ARRAY;
}
private static class MyReference extends PsiPolyVariantReferenceBase<PsiElement> {
private final GenericDomValue<String> myValue;
private final AndroidFacet myFacet;
public MyReference(@NotNull AndroidFacet facet, @NotNull GenericDomValue<String> value) {
super(DomUtil.getValueElement(value), true);
myFacet = facet;
myValue = value;
}
@NotNull
@Override
public ResolveResult[] multiResolve(boolean incompleteCode) {
return ResolveCache.getInstance(myElement.getProject())
.resolveWithCaching(this, new ResolveCache.PolyVariantResolver<MyReference>() {
@NotNull
@Override
public ResolveResult[] resolve(@NotNull MyReference reference, boolean incompleteCode) {
return resolveInner();
}
}, false, incompleteCode);
}
private ResolveResult[] resolveInner() {
final String value = myValue.getStringValue();
if (value == null || value.length() <= 0) {
return ResolveResult.EMPTY_ARRAY;
}
// Search for custom views with the same name as the declare styleable, such that
// you can navigate from the XML styleable declaration to the corresponding custom view
final PsiClass[] classes = PsiShortNamesCache.getInstance(myElement.getProject())
.getClassesByName(value, myFacet.getModule().getModuleWithDependenciesAndLibrariesScope(false));
if (classes.length == 0) {
return ResolveResult.EMPTY_ARRAY;
}
final ResolveResult[] result = new ResolveResult[classes.length];
for (int i = 0; i < result.length; i++) {
result[i] = new PsiElementResolveResult(classes[i]);
}
return result;
}
@NotNull
@Override
public Object[] getVariants() {
final PsiClass viewClass = JavaPsiFacade.getInstance(myElement.getProject())
.findClass(AndroidUtils.VIEW_CLASS_NAME, myFacet.getModule().getModuleWithDependenciesAndLibrariesScope(false));
if (viewClass == null) {
return EMPTY_ARRAY;
}
final Set<Object> shortNames = new HashSet<Object>();
ClassInheritorsSearch.search(viewClass, myFacet.getModule().getModuleWithDependenciesScope(), true).
forEach(new Processor<PsiClass>() {
@Override
public boolean process(PsiClass aClass) {
final String name = aClass.getName();
if (name != null) {
shortNames.add(JavaLookupElementBuilder.forClass(aClass, name, true));
}
return true;
}
});
return shortNames.toArray();
}
}
}