blob: 7c39d3ecb4c576d792c7faa9662384b7279f4865 [file] [log] [blame]
/*
* Copyright 2000-2014 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 com.intellij.util.xml;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/**
* If converter extends this class, the corresponding XML {@link com.intellij.psi.PsiReference}
* will take completion variants from {@link #getVariants(ConvertContext)} method.
*
* @author peter
*/
public abstract class ResolvingConverter<T> extends Converter<T> {
@Deprecated
public static final ResolvingConverter EMPTY_CONVERTER = new ResolvingConverter() {
@Override
@NotNull
public Collection getVariants(final ConvertContext context) {
return Collections.emptyList();
}
@Override
public Object fromString(final String s, final ConvertContext context) {
return s;
}
@Override
public String toString(final Object t, final ConvertContext context) {
return String.valueOf(t);
}
};
/** @see com.intellij.util.xml.converters.values.BooleanValueConverter */
@Deprecated
public static final Converter<Boolean> BOOLEAN_CONVERTER = new ResolvingConverter<Boolean>() {
@Override
public Boolean fromString(final String s, final ConvertContext context) {
if ("true".equalsIgnoreCase(s)) {
return Boolean.TRUE;
}
if ("false".equalsIgnoreCase(s)) {
return Boolean.FALSE;
}
return null;
}
@Override
public String toString(final Boolean t, final ConvertContext context) {
return t == null? null:t.toString();
}
@Override
@NotNull
public Collection<? extends Boolean> getVariants(final ConvertContext context) {
final DomElement element = context.getInvocationElement();
if (element instanceof GenericDomValue) {
final SubTag annotation = element.getAnnotation(SubTag.class);
if (annotation != null && annotation.indicator()) return Collections.emptyList();
}
return Arrays.asList(Boolean.FALSE, Boolean.TRUE);
}
};
@Override
public String getErrorMessage(@Nullable String s, final ConvertContext context) {
return CodeInsightBundle.message("error.cannot.resolve.default.message", s);
}
/**
* @param context context
* @return reference completion variants
*/
@NotNull
public abstract Collection<? extends T> getVariants(final ConvertContext context);
/**
* @return additional reference variants. They won't resolve to anywhere, but won't be highlighted as errors.
* They will also appear in the completion dropdown.
*/
@Deprecated
@NotNull
public Set<String> getAdditionalVariants() {
return Collections.emptySet();
}
/**
* @return additional reference variants. They won't resolve to anywhere, but won't be highlighted as errors.
* They will also appear in the completion dropdown.
*/
@NotNull
public Set<String> getAdditionalVariants(@NotNull final ConvertContext context) {
return getAdditionalVariants();
}
/**
* Delegate from {@link com.intellij.psi.PsiReference#handleElementRename(String)}
* @param genericValue generic value
* @param context context
* @param newElementName new element name
*/
public void handleElementRename(final GenericDomValue<T> genericValue, final ConvertContext context,
final String newElementName) {
genericValue.setStringValue(newElementName);
}
/**
* Delegate from {@link com.intellij.psi.PsiReference#bindToElement(com.intellij.psi.PsiElement)}
* @param genericValue generic value
* @param context context
* @param newTarget new target
*/
public void bindReference(final GenericDomValue<T> genericValue, final ConvertContext context, final PsiElement newTarget) {
if (newTarget instanceof XmlTag) {
DomElement domElement = genericValue.getManager().getDomElement((XmlTag) newTarget);
if (domElement != null) {
genericValue.setStringValue(ElementPresentationManager.getElementName(domElement));
}
}
}
/**
* @param resolvedValue {@link #fromString(String, ConvertContext)} result
* @return the PSI element to which the {@link com.intellij.psi.PsiReference} will resolve
*/
@Nullable
public PsiElement getPsiElement(@Nullable T resolvedValue) {
if (resolvedValue instanceof PsiElement) {
return (PsiElement)resolvedValue;
}
if (resolvedValue instanceof DomElement) {
return ((DomElement)resolvedValue).getXmlElement();
}
return null;
}
/**
* Delegate from {@link com.intellij.psi.PsiReference#isReferenceTo(com.intellij.psi.PsiElement)}
* @param element element
* @param stringValue string value
* @param resolveResult resolve result
* @param context context
* @return is reference to?
*/
public boolean isReferenceTo(@NotNull PsiElement element, final String stringValue, @Nullable T resolveResult,
final ConvertContext context) {
return resolveResult != null && element.getManager().areElementsEquivalent(element, getPsiElement(resolveResult));
}
/**
* Delegate from {@link com.intellij.psi.PsiReference#resolve()}
* @param o {@link #fromString(String, ConvertContext)} result
* @param context context
* @return PSI element to resolve to. By default calls {@link #getPsiElement(Object)} method
*/
@Nullable
public PsiElement resolve(final T o, final ConvertContext context) {
final PsiElement psiElement = getPsiElement(o);
return psiElement == null && o != null ? DomUtil.getValueElement((GenericDomValue)context.getInvocationElement()) : psiElement;
}
/**
* @param context context
* @return LocalQuickFix'es to correct non-resolved value (e.g. 'create from usage')
*/
public LocalQuickFix[] getQuickFixes(final ConvertContext context) {
return LocalQuickFix.EMPTY_ARRAY;
}
/**
* Override to provide custom lookup elements in completion.
* <p/>
* Default is {@code null} which will create lookup via
* {@link ElementPresentationManager#createVariant(java.lang.Object, java.lang.String, com.intellij.psi.PsiElement)}.
*
* @param t DOM to create lookup element for.
* @return Lookup element.
*/
@Nullable
public LookupElement createLookupElement(T t) {
return null;
}
/**
* Adds {@link #getVariants(ConvertContext)} functionality to a simple String value.
*/
public static abstract class StringConverter extends ResolvingConverter<String> {
@Override
public String fromString(final String s, final ConvertContext context) {
return s;
}
@Override
public String toString(final String s, final ConvertContext context) {
return s;
}
}
/**
* Adds {@link #getVariants(ConvertContext)} functionality to an existing converter.
*/
public static abstract class WrappedResolvingConverter<T> extends ResolvingConverter<T> {
private final Converter<T> myWrappedConverter;
public WrappedResolvingConverter(Converter<T> converter) {
myWrappedConverter = converter;
}
@Override
public T fromString(final String s, final ConvertContext context) {
return myWrappedConverter.fromString(s, context);
}
@Override
public String toString(final T t, final ConvertContext context) {
return myWrappedConverter.toString(t, context);
}
}
}