| /* |
| * Copyright 2006 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.plugins.intelliLang.inject.config; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.xml.XmlAttribute; |
| import com.intellij.psi.xml.XmlAttributeValue; |
| import com.intellij.psi.xml.XmlElement; |
| import com.intellij.psi.xml.XmlTag; |
| import org.intellij.plugins.intelliLang.inject.xml.XmlLanguageInjectionSupport; |
| import org.intellij.plugins.intelliLang.util.StringMatcher; |
| import org.jaxen.JaxenException; |
| import org.jaxen.XPath; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.Collections; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| /** |
| * Base class for XML-related injections (XML tags and attributes). |
| * Contains the tag's local name and namespace-uri, an optional value-pattern |
| * and an optional XPath expression (only valid if XPathView is installed) and |
| * the appropriate logic to determine if a tag matches those properties. |
| * |
| * @see org.intellij.plugins.intelliLang.inject.config.XPathSupportProxy |
| */ |
| public abstract class AbstractTagInjection extends BaseInjection { |
| |
| private static final Logger LOG = Logger.getInstance("org.intellij.plugins.intelliLang.inject.config.AbstractTagInjection"); |
| |
| @NotNull @NonNls |
| private StringMatcher myTagName = StringMatcher.ANY; |
| |
| @NotNull @NonNls |
| private Set<String> myTagNamespace = Collections.emptySet(); |
| @NotNull @NonNls |
| private String myXPathCondition = ""; |
| |
| private XPath myCompiledXPathCondition; |
| private boolean myApplyToSubTags; |
| |
| public AbstractTagInjection() { |
| super(XmlLanguageInjectionSupport.XML_SUPPORT_ID); |
| } |
| |
| @NotNull |
| public String getTagName() { |
| return myTagName.getPattern(); |
| } |
| |
| public void setTagName(@NotNull @NonNls String tagName) { |
| myTagName = StringMatcher.create(tagName); |
| } |
| |
| @Override |
| public boolean acceptsPsiElement(final PsiElement element) { |
| return super.acceptsPsiElement(element) && |
| (!(element instanceof XmlElement) || matchXPath((XmlElement)element)); |
| } |
| |
| @NotNull |
| public String getTagNamespace() { |
| return StringUtil.join(myTagNamespace, "|"); |
| } |
| |
| public void setTagNamespace(@NotNull @NonNls String tagNamespace) { |
| myTagNamespace = new TreeSet<String>(StringUtil.split(tagNamespace,"|")); |
| } |
| |
| @NotNull |
| public String getXPathCondition() { |
| return myXPathCondition; |
| } |
| |
| @Nullable |
| public XPath getCompiledXPathCondition() { |
| return myCompiledXPathCondition; |
| } |
| |
| public void setXPathCondition(@Nullable String condition) { |
| myXPathCondition = condition != null ? condition : ""; |
| if (StringUtil.isNotEmpty(myXPathCondition)) { |
| try { |
| final XPathSupportProxy xPathSupport = XPathSupportProxy.getInstance(); |
| if (xPathSupport != null) { |
| myCompiledXPathCondition = xPathSupport.createXPath(myXPathCondition); |
| } |
| else { |
| myCompiledXPathCondition = null; |
| } |
| } |
| catch (JaxenException e) { |
| myCompiledXPathCondition = null; |
| LOG.warn("Invalid XPath expression", e); |
| } |
| } |
| else { |
| myCompiledXPathCondition = null; |
| } |
| } |
| |
| @SuppressWarnings({"RedundantIfStatement"}) |
| protected boolean matches(@Nullable XmlTag tag) { |
| if (tag == null) { |
| return false; |
| } |
| if (!myTagName.matches(tag.getLocalName())) { |
| return false; |
| } |
| if (!myTagNamespace.contains(tag.getNamespace())) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public abstract AbstractTagInjection copy(); |
| |
| public AbstractTagInjection copyFrom(@NotNull BaseInjection o) { |
| super.copyFrom(o); |
| if (o instanceof AbstractTagInjection) { |
| final AbstractTagInjection other = (AbstractTagInjection)o; |
| myTagName = other.myTagName; |
| myTagNamespace = other.myTagNamespace; |
| setXPathCondition(other.getXPathCondition()); |
| |
| setApplyToSubTags(other.isApplyToSubTags()); |
| } |
| return this; |
| } |
| |
| protected void readExternalImpl(Element e) { |
| setXPathCondition(e.getChildText("xpath-condition")); |
| myApplyToSubTags = e.getChild("apply-to-subtags") != null; |
| } |
| |
| protected void writeExternalImpl(Element e) { |
| if (StringUtil.isNotEmpty(myXPathCondition)) { |
| e.addContent(new Element("xpath-condition").setText(myXPathCondition)); |
| } |
| if (myApplyToSubTags) { |
| e.addContent(new Element("apply-to-subtags")); |
| } |
| } |
| |
| @SuppressWarnings({"RedundantIfStatement"}) |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| if (!super.equals(o)) return false; |
| |
| final AbstractTagInjection that = (AbstractTagInjection)o; |
| |
| if (!myTagName.equals(that.myTagName)) return false; |
| if (!myTagNamespace.equals(that.myTagNamespace)) return false; |
| if (!myXPathCondition.equals(that.myXPathCondition)) return false; |
| |
| if (myApplyToSubTags != that.myApplyToSubTags) return false; |
| return true; |
| } |
| |
| public int hashCode() { |
| int result = super.hashCode(); |
| result = 31 * result + myTagName.hashCode(); |
| result = 31 * result + myTagNamespace.hashCode(); |
| result = 31 * result + myXPathCondition.hashCode(); |
| |
| result = 31 * result + (myApplyToSubTags ? 1 : 0); |
| return result; |
| } |
| |
| protected boolean matchXPath(XmlElement context) { |
| final XPath condition = getCompiledXPathCondition(); |
| if (condition != null) { |
| try { |
| return condition.booleanValueOf(context); |
| } |
| catch (JaxenException e) { |
| LOG.warn(e); |
| myCompiledXPathCondition = null; |
| return false; |
| } |
| } |
| return myXPathCondition.length() == 0; |
| } |
| |
| public boolean isApplyToSubTags() { |
| return myApplyToSubTags; |
| } |
| |
| public void setApplyToSubTags(final boolean applyToSubTagTexts) { |
| myApplyToSubTags = applyToSubTagTexts; |
| } |
| |
| @Override |
| public boolean acceptForReference(PsiElement element) { |
| if (element instanceof XmlAttributeValue) { |
| PsiElement parent = element.getParent(); |
| return parent instanceof XmlAttribute && acceptsPsiElement(parent); |
| } |
| else return element instanceof XmlTag && acceptsPsiElement(element); |
| } |
| } |