| /* |
| * 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.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Factory; |
| import com.intellij.openapi.util.text.StringUtil; |
| 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 com.intellij.util.IncorrectOperationException; |
| import com.intellij.util.xml.DomElement; |
| import com.intellij.util.xml.DomElementVisitor; |
| import com.intellij.util.xml.EvaluatedXmlName; |
| import com.intellij.util.xml.GenericAttributeValue; |
| import com.intellij.util.xml.events.DomEvent; |
| import com.intellij.util.xml.stubs.AttributeStub; |
| import com.intellij.xml.util.XmlStringUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * @author peter |
| */ |
| public class AttributeChildInvocationHandler extends DomInvocationHandler<AttributeChildDescriptionImpl, AttributeStub> { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.AttributeChildInvocationHandler"); |
| |
| protected AttributeChildInvocationHandler(final EvaluatedXmlName attributeName, |
| final AttributeChildDescriptionImpl description, |
| final DomManagerImpl manager, |
| final DomParentStrategy strategy, |
| @Nullable AttributeStub stub) { |
| super(description.getType(), strategy, attributeName, description, manager, false, stub); |
| } |
| |
| @Override |
| public void acceptChildren(DomElementVisitor visitor) { |
| } |
| |
| @Override |
| protected final XmlTag setEmptyXmlTag() { |
| return ensureTagExists(); |
| } |
| |
| @Override |
| protected boolean isAttribute() { |
| return true; |
| } |
| |
| @Override |
| protected XmlElement recomputeXmlElement(@NotNull final DomInvocationHandler parent) { |
| if (!parent.isValid()) return null; |
| |
| final XmlTag tag = parent.getXmlTag(); |
| if (tag == null) return null; |
| |
| return tag.getAttribute(getXmlElementName(), getXmlApiCompatibleNamespace(parent)); |
| } |
| |
| @Nullable |
| private String getXmlApiCompatibleNamespace(DomInvocationHandler parent) { |
| final XmlTag tag = parent.getXmlTag(); |
| if (tag == null) { |
| return null; |
| } |
| |
| String ns = getXmlName().getNamespace(tag, parent.getFile()); |
| // TODO: this seems ugly |
| return tag.getNamespace().equals(ns) ? null : ns; |
| } |
| |
| @Override |
| public final XmlAttribute ensureXmlElementExists() { |
| XmlAttribute attribute = (XmlAttribute)getXmlElement(); |
| if (attribute != null) return attribute; |
| |
| final DomManagerImpl manager = getManager(); |
| final boolean b = manager.setChanging(true); |
| try { |
| attribute = ensureTagExists().setAttribute(getXmlElementName(), getXmlApiCompatibleNamespace(getParentHandler()), ""); |
| setXmlElement(attribute); |
| getManager().cacheHandler(DomManagerImpl.DOM_ATTRIBUTE_HANDLER_KEY, attribute, this); |
| final DomElement element = getProxy(); |
| manager.fireEvent(new DomEvent(element, true)); |
| return attribute; |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| return null; |
| } |
| finally { |
| manager.setChanging(b); |
| } |
| } |
| |
| @Override |
| public <T extends DomElement> T createStableCopy() { |
| final DomElement parentCopy = getParent().createStableCopy(); |
| return getManager().createStableValue(new Factory<T>() { |
| @Override |
| public T create() { |
| return parentCopy.isValid() ? (T) getChildDescription().getValues(parentCopy).get(0) : null; |
| } |
| }); |
| } |
| |
| @Override |
| public final void undefineInternal() { |
| final XmlTag tag = getXmlTag(); |
| if (tag != null) { |
| getManager().runChange(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| setXmlElement(null); |
| tag.setAttribute(getXmlElementName(), getXmlApiCompatibleNamespace(getParentHandler()), null); |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| } |
| } |
| }); |
| fireUndefinedEvent(); |
| } |
| } |
| |
| @Override |
| @Nullable |
| public final XmlTag getXmlTag() { |
| final DomInvocationHandler handler = getParentHandler(); |
| return handler == null ? null : handler.getXmlTag(); |
| } |
| |
| @Override |
| public final XmlTag ensureTagExists() { |
| final DomInvocationHandler parent = getParentHandler(); |
| assert parent != null : "write operations should be performed on the DOM having a parent, your DOM may be not very fresh"; |
| return parent.ensureTagExists(); |
| } |
| |
| @Override |
| @Nullable |
| protected String getValue() { |
| if (myStub != null) { |
| return myStub.getValue(); |
| } |
| final XmlAttribute attribute = (XmlAttribute)getXmlElement(); |
| if (attribute != null) { |
| final XmlAttributeValue value = attribute.getValueElement(); |
| if (value != null && value.getTextLength() >= 2) { |
| return attribute.getDisplayValue(); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void copyFrom(final DomElement other) { |
| setValue(((GenericAttributeValue) other).getStringValue()); |
| } |
| |
| @Override |
| protected void setValue(@Nullable final String value) { |
| final XmlTag tag = ensureTagExists(); |
| final String attributeName = getXmlElementName(); |
| final String namespace = getXmlApiCompatibleNamespace(getParentHandler()); |
| final String oldValue = StringUtil.unescapeXml(tag.getAttributeValue(attributeName, namespace)); |
| final String newValue = XmlStringUtil.escapeString(value); |
| if (Comparing.equal(oldValue, newValue, true)) return; |
| |
| getManager().runChange(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| XmlAttribute attribute = tag.setAttribute(attributeName, namespace, newValue); |
| setXmlElement(attribute); |
| getManager().cacheHandler(DomManagerImpl.DOM_ATTRIBUTE_HANDLER_KEY, attribute, AttributeChildInvocationHandler.this); |
| } |
| catch (IncorrectOperationException e) { |
| LOG.error(e); |
| } |
| } |
| }); |
| final DomElement proxy = getProxy(); |
| final DomElement element = proxy; |
| getManager().fireEvent(oldValue != null ? new DomEvent(proxy, false) : new DomEvent(element, true)); |
| } |
| |
| } |