| /* |
| * Copyright 2005 Sascha Weinreuter |
| * |
| * 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.intellij.lang.xpath.xslt.psi.impl; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.lang.Language; |
| import com.intellij.navigation.ItemPresentation; |
| import com.intellij.navigation.NavigationItem; |
| import com.intellij.navigation.PsiElementNavigationItem; |
| import com.intellij.openapi.util.Iconable; |
| import com.intellij.openapi.util.TextRange; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.PsiElementVisitor; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.PsiReference; |
| import com.intellij.psi.impl.light.LightElement; |
| import com.intellij.psi.xml.XmlAttribute; |
| import com.intellij.psi.xml.XmlAttributeValue; |
| import com.intellij.psi.xml.XmlTag; |
| import com.intellij.util.IncorrectOperationException; |
| import org.intellij.lang.xpath.completion.CompletionLists; |
| import org.intellij.lang.xpath.context.ContextProvider; |
| import org.intellij.lang.xpath.context.XPathVersion; |
| import org.intellij.lang.xpath.psi.XPathElement; |
| import org.intellij.lang.xpath.psi.XPathElementVisitor; |
| import org.intellij.lang.xpath.xslt.XsltSupport; |
| import org.intellij.lang.xpath.xslt.psi.XsltElement; |
| import org.intellij.lang.xpath.xslt.psi.XsltElementFactory; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.lang.reflect.*; |
| |
| abstract class XsltElementImpl extends LightElement implements Iconable, PsiElementNavigationItem, XsltElement, ItemPresentation { |
| |
| protected final @NotNull XmlTag myElement; |
| protected final XsltElementFactory myElementFactory; |
| |
| private final int myHashCode; |
| private PsiElement myNavigationElement; |
| |
| protected XsltElementImpl(XmlTag target) { |
| super(target.getManager(), XsltLanguage.INSTANCE); |
| myElement = target; |
| myHashCode = myElement.hashCode(); |
| myElementFactory = XsltElementFactory.getInstance(); |
| } |
| |
| public PsiElement copy() { |
| return myElementFactory.wrapElement((XmlTag)myElement.copy(), getClass()); |
| } |
| |
| public String getText() { |
| return myElement.getText(); |
| } |
| |
| public XmlTag getTag() { |
| return myElement; |
| } |
| |
| @Override |
| @Nullable |
| public final ItemPresentation getPresentation() { |
| return this; |
| } |
| |
| @Nullable |
| public Icon getIcon(boolean open) { |
| return getIcon(0); |
| } |
| |
| @Nullable |
| public String getLocationString() { |
| return "(in " + getContainingFile().getName() + ")"; |
| } |
| |
| @SuppressWarnings({"ConstantConditions"}) |
| public String getPresentableText() { |
| return getName(); |
| } |
| |
| @Override |
| public PsiElement getTargetElement() { |
| return myElement; |
| } |
| |
| @Nullable |
| public String getName() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getValue() : null; |
| } |
| |
| public PsiElement setName(@NotNull String name) throws IncorrectOperationException { |
| assert myElement.isValid(); |
| |
| myElement.setAttribute("name", name); |
| return this; |
| } |
| |
| @NotNull |
| @Override |
| @SuppressWarnings({ "RawUseOfParameterizedType" }) |
| public PsiElement getNavigationElement() { |
| if (myNavigationElement == null && myElement.isValid()) { |
| final Class[] allInterfaces = CompletionLists.getAllInterfaces(myElement.getClass()); |
| myNavigationElement = (PsiElement)Proxy.newProxyInstance(getClass().getClassLoader(), allInterfaces, new InvocationHandler() { |
| @Nullable |
| @SuppressWarnings({"StringEquality", "AutoBoxing", "AutoUnboxing"}) |
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| try { |
| final XmlAttributeValue nameElement = XsltElementImpl.this.getNameElement(); |
| if (method.getName() == "navigate") { |
| assert nameElement != null; |
| |
| ((NavigationItem)nameElement).navigate((Boolean)args[0]); |
| |
| return null; |
| } else if (method.getName() == "canNavigate") { |
| return nameElement != null && nameElement instanceof NavigationItem && ((NavigationItem)nameElement).canNavigate(); |
| } else if (method.getName() == "getTextOffset") { |
| return nameElement != null ? nameElement.getTextOffset() : myElement.getTextOffset(); |
| } |
| return method.invoke(myElement, args); |
| } catch (InvocationTargetException e1) { |
| throw e1.getTargetException(); |
| } |
| } |
| }); |
| } |
| return myElement.isValid() ? myNavigationElement : this; |
| } |
| |
| @Nullable |
| public XmlAttribute getNameAttribute() { |
| return myElement.getAttribute("name", null); |
| } |
| |
| @Nullable |
| public PsiElement getNameIdentifier() { |
| final XmlAttribute nameAttribute = getNameAttribute(); |
| return nameAttribute != null ? XsltSupport.getAttValueToken(nameAttribute) : null; |
| } |
| |
| @Nullable |
| private XmlAttributeValue getNameElement() { |
| final XmlAttribute attribute = getNameAttribute(); |
| if (attribute != null) { |
| final XmlAttributeValue valueElement = attribute.getValueElement(); |
| return valueElement != null ? valueElement : null; |
| } |
| return null; |
| } |
| |
| @Override |
| public PsiElement getOriginalElement() { |
| return myElement.getOriginalElement(); |
| } |
| |
| @Override |
| public boolean isValid() { |
| return myElement.isValid(); |
| } |
| |
| @Override |
| @NotNull |
| public Language getLanguage() { |
| return XsltLanguage.INSTANCE; |
| } |
| |
| @Override |
| public void navigate(boolean b) { |
| final XmlAttributeValue nameElement = getNameElement(); |
| assert nameElement != null; |
| ((NavigationItem)nameElement).navigate(b); |
| } |
| |
| @Override |
| public boolean canNavigate() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return myElement.isValid() && nameElement instanceof NavigationItem && ((NavigationItem)nameElement).canNavigate(); |
| } |
| |
| @Override |
| public boolean canNavigateToSource() { |
| return canNavigate(); |
| } |
| |
| public void accept(@NotNull XPathElementVisitor visitor) { |
| visitor.visitXPathElement((XPathElement)this); |
| } |
| |
| public void accept(@NotNull PsiElementVisitor visitor) { |
| if (visitor instanceof XPathElementVisitor && this instanceof XPathElement) { |
| accept((XPathElementVisitor)visitor); |
| } else { |
| myElement.accept(visitor); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return myHashCode; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| final XsltElementImpl that = (XsltElementImpl)o; |
| |
| return myElement.equals(that.myElement); |
| } |
| |
| @Override |
| public PsiFile getContainingFile() { |
| return myElement.getContainingFile(); |
| } |
| |
| @Override |
| public boolean isWritable() { |
| return myElement.isWritable(); |
| } |
| |
| @Override |
| public boolean isPhysical() { |
| return myElement.isPhysical(); |
| } |
| |
| @Override |
| public PsiElement getParent() { |
| // final XmlTag parent = PsiTreeUtil.getParentOfType(myElement.getParent(), XmlTag.class); |
| // return parent != null ? |
| // XsltSupport.isXsltTag(parent) ? myElementFactory.wrapElement(parent) : parent |
| // : null; |
| |
| return myElement.getParent(); // TODO: return XSLT object |
| } |
| |
| @Override |
| @NotNull |
| public PsiElement[] getChildren() { |
| return myElement.getChildren(); // TODO: return XSLT objects |
| } |
| |
| @Override |
| public TextRange getTextRange() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getTextRange() : myElement.getTextRange(); |
| } |
| |
| @Override |
| public int getStartOffsetInParent() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getStartOffsetInParent() : myElement.getStartOffsetInParent(); |
| } |
| |
| @Override |
| @NotNull |
| public char[] textToCharArray() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.textToCharArray() : myElement.textToCharArray(); |
| } |
| |
| @Override |
| public int getTextOffset() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getTextOffset() : myElement.getTextOffset(); |
| } |
| |
| @Override |
| public ASTNode getNode() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getNode() : myElement.getNode(); |
| } |
| |
| @Override |
| @NotNull |
| public PsiReference[] getReferences() { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.getReferences() : myElement.getReferences(); |
| } |
| |
| @Override |
| public boolean textMatches(@NotNull CharSequence charSequence) { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.textMatches(charSequence) : myElement.textMatches(charSequence); |
| } |
| |
| @Override |
| public boolean textMatches(@NotNull PsiElement psiElement) { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.textMatches(psiElement) : myElement.textMatches(psiElement); |
| } |
| |
| @Override |
| public PsiElement findElementAt(int i) { |
| final XmlAttributeValue nameElement = getNameElement(); |
| return nameElement != null ? nameElement.findElementAt(i) : myElement.findElementAt(i); |
| } |
| |
| @Override |
| public void delete() throws IncorrectOperationException { |
| myElement.delete(); |
| } |
| |
| protected static <S, T extends S> T[] convertArray(S[] elements, Class<T> aClass) { |
| //noinspection unchecked |
| final T[] t = (T[])Array.newInstance(aClass, elements.length); |
| //noinspection SuspiciousSystemArraycopy |
| System.arraycopy(elements, 0, t, 0, elements.length); |
| return t; |
| } |
| |
| public ContextProvider getXPathContext() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public XPathVersion getXPathVersion() { |
| throw new UnsupportedOperationException(); |
| } |
| } |