| /* |
| * 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.dom.converters; |
| |
| import com.android.sdklib.IAndroidTarget; |
| import com.intellij.codeInsight.lookup.LookupElementBuilder; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.psi.*; |
| import com.intellij.psi.impl.source.resolve.ResolveCache; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.Processor; |
| import com.intellij.util.containers.HashSet; |
| import com.intellij.util.xml.*; |
| import org.jetbrains.android.dom.LookupClass; |
| import org.jetbrains.android.dom.LookupPrefix; |
| import org.jetbrains.android.dom.manifest.*; |
| import org.jetbrains.android.sdk.AndroidPlatform; |
| import org.jetbrains.android.sdk.AndroidTargetData; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * @author yole |
| */ |
| public class ConstantFieldConverter extends Converter<String> implements CustomReferenceConverter<String> { |
| @Override |
| public String fromString(@Nullable @NonNls String s, ConvertContext context) { |
| return s; |
| } |
| |
| @Override |
| public String toString(@Nullable String value, ConvertContext context) { |
| return value; |
| } |
| |
| @NotNull |
| @Override |
| public PsiReference[] createReferences(GenericDomValue<String> value, PsiElement element, ConvertContext context) { |
| final List<PsiReference> result = new ArrayList<PsiReference>(); |
| final DomElement domElement = context.getInvocationElement(); |
| final LookupClass lookupClass = domElement.getAnnotation(LookupClass.class); |
| final LookupPrefix lookupPrefix = domElement.getAnnotation(LookupPrefix.class); |
| |
| if (lookupClass != null && lookupPrefix != null) { |
| final Module module = context.getModule(); |
| final GlobalSearchScope scope = module != null ? |
| GlobalSearchScope.allScope(module.getProject()) : |
| domElement.getResolveScope(); |
| final PsiClass psiClass = JavaPsiFacade.getInstance(context.getPsiManager(). |
| getProject()).findClass(lookupClass.value(), scope); |
| |
| if (psiClass != null) { |
| final Set<String> filteringSet = getFilteringSet(context); |
| result.add(new MyReference(element, psiClass, lookupPrefix.value(), filteringSet)); |
| } |
| } |
| return result.toArray(new PsiReference[result.size()]); |
| } |
| |
| @Nullable |
| private static Set<String> getFilteringSet(@NotNull ConvertContext context) { |
| final Module module = context.getModule(); |
| |
| if (module == null) { |
| return null; |
| } |
| final AndroidPlatform platform = AndroidPlatform.getInstance(module); |
| |
| if (platform == null) { |
| return null; |
| } |
| final IAndroidTarget target = platform.getTarget(); |
| final AndroidTargetData targetData = platform.getSdkData().getTargetData(target); |
| DomElement element = context.getInvocationElement().getParent(); |
| |
| if (element instanceof Category) { |
| return targetData.getStaticConstantsData().getCategories(); |
| } |
| else if (element instanceof Action) { |
| element = element.getParent(); |
| |
| if (element instanceof IntentFilter) { |
| element = element.getParent(); |
| |
| if (element instanceof Activity) { |
| return targetData.getStaticConstantsData().getActivityActions(); |
| } |
| else if (element instanceof Service) { |
| return targetData.getStaticConstantsData().getServiceActions(); |
| } |
| else if (element instanceof Receiver) { |
| return targetData.getStaticConstantsData().getReceiverActions(); |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static class MyReference extends PsiReferenceBase<PsiElement> { |
| |
| private final PsiClass myClass; |
| private final String myLookupPrefix; |
| private final Set<String> myFilteringSet; |
| |
| public MyReference(@NotNull PsiElement element, |
| @NotNull PsiClass aClass, |
| @NotNull String lookupPrefix, |
| @Nullable Set<String> filteringSet) { |
| super(element, true); |
| myClass = aClass; |
| myLookupPrefix = lookupPrefix; |
| myFilteringSet = filteringSet; |
| } |
| |
| @Nullable |
| @Override |
| public PsiElement resolve() { |
| return ResolveCache.getInstance(myElement.getProject()).resolveWithCaching(this, new ResolveCache.Resolver() { |
| @Nullable |
| @Override |
| public PsiElement resolve(@NotNull PsiReference reference, boolean incompleteCode) { |
| return resolveInner(); |
| } |
| }, false, false); |
| } |
| |
| @Nullable |
| private PsiElement resolveInner() { |
| final String value = getValue(); |
| |
| if (value.isEmpty()) { |
| return null; |
| } |
| final Ref<PsiElement> ref = Ref.create(); |
| |
| processFields(new Processor<Pair<PsiField, String>>() { |
| @Override |
| public boolean process(Pair<PsiField, String> pair) { |
| if (value.equals(pair.getSecond())) { |
| ref.set(pair.getFirst()); |
| return false; |
| } |
| return true; |
| } |
| }); |
| return ref.get(); |
| } |
| |
| @NotNull |
| @Override |
| public Object[] getVariants() { |
| final List<Object> result = new ArrayList<Object>(); |
| final Set<String> added = new HashSet<String>(); |
| |
| processFields(new Processor<Pair<PsiField, String>>() { |
| @Override |
| public boolean process(Pair<PsiField, String> pair) { |
| final String s = pair.getSecond(); |
| |
| if (myFilteringSet != null && !myFilteringSet.contains(s)) { |
| return true; |
| } |
| if (added.add(s)) { |
| result.add(LookupElementBuilder.create(pair.getFirst(), s).withCaseSensitivity(false)); |
| } |
| return true; |
| } |
| }); |
| return ArrayUtil.toObjectArray(result); |
| } |
| |
| private void processFields(@NotNull Processor<Pair<PsiField, String>> processor) { |
| final PsiField[] psiFields = myClass.getFields(); |
| |
| for (PsiField field : psiFields) { |
| if (field.hasModifierProperty(PsiModifier.STATIC) && field.hasModifierProperty(PsiModifier.PUBLIC)) { |
| final PsiExpression initializer = field.getInitializer(); |
| |
| if (initializer instanceof PsiLiteralExpression) { |
| final PsiLiteralExpression literalExpression = (PsiLiteralExpression)initializer; |
| final Object o = literalExpression.getValue(); |
| |
| if (o instanceof String && o.toString().startsWith(myLookupPrefix)) { |
| if (!processor.process(Pair.create(field, o.toString()))) { |
| return; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |