blob: 9a90fbf0fcec8b6460027f4a3c92238ee71a5360 [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.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Factory;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.EvaluatedXmlName;
import com.intellij.util.xml.reflect.DomFixedChildDescription;
import com.intellij.util.xml.stubs.ElementStub;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* @author peter
*/
public class IndexedElementInvocationHandler extends DomInvocationHandler<FixedChildDescriptionImpl, ElementStub>{
private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.IndexedElementInvocationHandler");
private final int myIndex;
public IndexedElementInvocationHandler(final EvaluatedXmlName tagName,
final FixedChildDescriptionImpl description,
final int index,
final DomParentStrategy strategy,
final DomManagerImpl manager,
@Nullable ElementStub stub) {
super(description.getType(), strategy, tagName, description, manager, strategy.isPhysical(), stub);
myIndex = index;
}
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
public boolean equals(final Object obj) {
return super.equals(obj) && myIndex == ((IndexedElementInvocationHandler)obj).myIndex;
}
public int hashCode() {
return super.hashCode() * 239 + myIndex;
}
@Override
protected XmlElement recomputeXmlElement(@NotNull final DomInvocationHandler parentHandler) {
final XmlTag tag = parentHandler.getXmlTag();
if (tag == null) return null;
final List<XmlTag> tags = DomImplUtil.findSubTags(tag, getXmlName(), parentHandler.getFile());
if (tags.size() <= myIndex) return null;
return tags.get(myIndex);
}
@Override
protected XmlTag setEmptyXmlTag() {
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";
final FixedChildDescriptionImpl description = getChildDescription();
final XmlFile xmlFile = getFile();
parent.createFixedChildrenTags(getXmlName(), description, myIndex);
final List<XmlTag> tags = DomImplUtil.findSubTags(parent.getXmlTag(), getXmlName(), xmlFile);
if (tags.size() > myIndex) {
return tags.get(myIndex);
}
final XmlTag[] newTag = new XmlTag[1];
getManager().runChange(new Runnable() {
@Override
public void run() {
try {
final XmlTag parentTag = parent.getXmlTag();
newTag[0] = (XmlTag)parentTag.add(parent.createChildTag(getXmlName()));
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
});
return newTag[0];
}
@Override
public void undefineInternal() {
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";
final XmlTag parentTag = parent.getXmlTag();
if (parentTag == null) return;
final EvaluatedXmlName xmlElementName = getXmlName();
final FixedChildDescriptionImpl description = getChildDescription();
final int totalCount = description.getCount();
final List<XmlTag> subTags = DomImplUtil.findSubTags(parentTag, xmlElementName, getFile());
if (subTags.size() <= myIndex) {
return;
}
XmlTag tag = getXmlTag();
if (tag == null) return;
final boolean changing = getManager().setChanging(true);
try {
detach();
if (totalCount == myIndex + 1 && subTags.size() >= myIndex + 1) {
for (int i = myIndex; i < subTags.size(); i++) {
subTags.get(i).delete();
}
}
else if (subTags.size() == myIndex + 1) {
tag.delete();
} else {
setXmlElement((XmlTag) tag.replace(parent.createChildTag(getXmlName())));
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
} finally {
getManager().setChanging(changing);
}
fireUndefinedEvent();
}
@Override
public final <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
final T annotation = getChildDescription().getAnnotation(myIndex, annotationClass);
if (annotation != null) return annotation;
return getClassAnnotation(annotationClass);
}
@Override
public final DomElement createPathStableCopy() {
final DomFixedChildDescription description = getChildDescription();
final DomElement parentCopy = getParent().createStableCopy();
return getManager().createStableValue(new Factory<DomElement>() {
@Override
public DomElement create() {
return parentCopy.isValid() ? description.getValues(parentCopy).get(myIndex) : null;
}
});
}
}