blob: 18c97c2a839d5fcf5fe6a7f549ff429b82832f45 [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.impl;
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupValueFactory;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.PomTarget;
import com.intellij.pom.references.PomService;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.impl.PomTargetPsiElementImpl;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.xml.*;
import com.intellij.xml.util.XmlTagUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
*/
public class GenericDomValueReference<T> extends PsiReferenceBase<XmlElement> implements EmptyResolveMessageProvider {
private final GenericDomValue<T> myGenericValue;
public GenericDomValueReference(GenericDomValue<T> domValue) {
super(DomUtil.getValueElement(domValue));
myGenericValue = domValue;
assert DomUtil.hasXml(domValue);
setRangeInElement(createTextRange());
}
protected final PsiManager getPsiManager() {
return PsiManager.getInstance(myGenericValue.getManager().getProject());
}
protected TextRange createTextRange() {
if (myGenericValue instanceof GenericAttributeValue) {
final GenericAttributeValue genericAttributeValue = (GenericAttributeValue)myGenericValue;
final XmlAttributeValue attributeValue = genericAttributeValue.getXmlAttributeValue();
if (attributeValue == null) {
return TextRange.from(0, genericAttributeValue.getXmlAttribute().getTextLength());
}
final int length = attributeValue.getTextLength();
return length < 2 ? TextRange.from(0, length) : new TextRange(1, length - 1);
}
final XmlTag tag = myGenericValue.getXmlTag();
assert tag != null;
return XmlTagUtil.getTrimmedValueRange(tag);
}
protected final GenericDomValue<T> getGenericValue() {
return myGenericValue;
}
@Override
public boolean isSoft() {
return true;
}
@Nullable
protected PsiElement resolveInner(T o) {
final Converter<T> converter = getConverter();
if (converter instanceof ResolvingConverter) {
return ((ResolvingConverter<T>)converter).resolve(o, getConvertContext());
}
if (o instanceof PsiElement) {
return (PsiElement)o;
}
if (o instanceof DomElement) {
DomTarget target = DomTarget.getTarget((DomElement)o);
return target == null ? null : PomService.convertToPsi(target);
}
if (o instanceof MergedObject) {
final List<T> list = ((MergedObject<T>)o).getImplementations();
for (final T o1 : list) {
final PsiElement psiElement = resolveInner(o1);
if (psiElement != null) {
return psiElement;
}
}
}
return o != null ? getElement() : null;
}
@Override
public boolean isReferenceTo(final PsiElement element) {
final Converter<T> converter = getConverter();
if (converter instanceof ResolvingConverter) {
T value = myGenericValue.getValue();
if (value instanceof DomElement && element instanceof PomTargetPsiElementImpl) {
PomTarget target = ((PomTargetPsiElementImpl)element).getTarget();
if (target instanceof DomTarget) {
if (value.equals(((DomTarget)target).getDomElement())) {
return true;
}
}
}
return ((ResolvingConverter<T>)converter).isReferenceTo(element, getStringValue(), value, getConvertContext());
}
return super.isReferenceTo(element);
}
private String getStringValue() {
return myGenericValue.getStringValue();
}
public Converter<T> getConverter() {
return WrappingConverter.getDeepestConverter(myGenericValue.getConverter(), myGenericValue);
}
@Override
@Nullable
public PsiElement resolve() {
final T value = myGenericValue.getValue();
return value == null ? null : resolveInner(value);
}
@Override
@NotNull
public String getCanonicalText() {
return StringUtil.notNullize(getStringValue());
}
@Override
@NotNull
public String getUnresolvedMessagePattern() {
final ConvertContext context = getConvertContext();
return getConverter().getErrorMessage(getStringValue(), context);
}
public final ConvertContext getConvertContext() {
return ConvertContextFactory.createConvertContext(DomManagerImpl.getDomInvocationHandler(myGenericValue));
}
@Override
public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
final Converter<T> converter = getConverter();
if (converter instanceof ResolvingConverter) {
((ResolvingConverter)converter).handleElementRename(myGenericValue, getConvertContext(), newElementName);
return myGenericValue.getXmlTag();
}
return super.handleElementRename(newElementName);
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
final Converter<T> converter = getConverter();
if (converter instanceof ResolvingConverter) {
((ResolvingConverter)converter).bindReference(myGenericValue, getConvertContext(), element);
return myGenericValue.getXmlTag();
}
if (element instanceof XmlTag) {
DomElement domElement = myGenericValue.getManager().getDomElement((XmlTag) element);
if (domElement != null) {
myGenericValue.setValue((T)domElement);
} else {
myGenericValue.setStringValue(((XmlTag)element).getName());
}
return myGenericValue.getXmlTag();
}
return null;
}
@Override
@NotNull
public Object[] getVariants() {
final Converter<T> converter = getConverter();
if (converter instanceof EnumConverter || converter == ResolvingConverter.BOOLEAN_CONVERTER) {
if (DomCompletionContributor.isSchemaEnumerated(getElement())) return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
if (converter instanceof ResolvingConverter) {
final ResolvingConverter<T> resolvingConverter = (ResolvingConverter<T>)converter;
ArrayList<Object> result = new ArrayList<Object>();
final ConvertContext convertContext = getConvertContext();
for (T variant: resolvingConverter.getVariants(convertContext)) {
LookupElement lookupElement = resolvingConverter.createLookupElement(variant);
if (lookupElement != null) {
result.add(lookupElement);
continue;
}
String name = converter.toString(variant, convertContext);
if (name != null) {
result.add(ElementPresentationManager.getInstance().createVariant(variant, name, ((ResolvingConverter)converter).getPsiElement(variant)));
}
}
for (final String string : resolvingConverter.getAdditionalVariants(convertContext)) {
result.add(LookupValueFactory.createLookupValue(string, null));
}
return result.toArray();
}
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
}