2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.util.xml.impl;
18 import com.intellij.psi.xml.XmlAttribute;
19 import com.intellij.psi.xml.XmlFile;
20 import com.intellij.psi.xml.XmlTag;
21 import com.intellij.util.xml.DomElement;
22 import com.intellij.util.xml.DomManager;
23 import com.intellij.util.xml.DomFileElement;
24 import com.intellij.util.xml.GenericAttributeValue;
25 import com.intellij.util.xml.reflect.AbstractDomChildrenDescription;
26 import com.intellij.openapi.diagnostic.Logger;
27 import org.jetbrains.annotations.Nullable;
28 import org.jetbrains.annotations.NotNull;
30 import java.util.List;
35 public abstract class DomAnchorImpl<T extends DomElement> {
36 private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.DomAnchorImpl");
38 public static <T extends DomElement> DomAnchorImpl<T> createAnchor(@NotNull T t) {
39 final DomElement parent = t.getParent();
41 LOG.error("Parent null: " + t);
44 if (parent instanceof DomFileElementImpl) {
45 final DomFileElementImpl fileElement = (DomFileElementImpl)parent;
46 return new RootAnchor<T>(fileElement.getFile(), fileElement.getRootElementClass());
49 final DomAnchorImpl<DomElement> parentAnchor = createAnchor(parent);
50 final String name = t.getGenericInfo().getElementName(t);
51 final AbstractDomChildrenDescription description = t.getChildDescription();
53 return new NamedAnchor<T>(parentAnchor, description, name);
56 final List<? extends DomElement> values = description.getValues(parent);
57 final int index = values.indexOf(t);
59 final XmlTag parentTag = parent.getXmlTag();
60 StringBuilder diag = new StringBuilder("Index<0: description=" + description + "\nparent=" + parent + "\nt=" + t + "\nvalues=" + values + "\n");
61 if (parentTag != null) {
62 diag.append("Parent tag: ").append(parentTag.getName()).append("\n");
63 if (t instanceof GenericAttributeValue) {
64 for (XmlAttribute attribute : parentTag.getAttributes()) {
65 diag.append("attr: ").append(attribute.getName());
69 for (XmlTag tag : parentTag.getSubTags()) {
70 diag.append("subtag: ").append(tag.getName());
75 diag.append("Child name: ").append(t.getXmlElementName()).append(";").append(t.getXmlElementNamespaceKey());
78 return new IndexedAnchor<T>(parentAnchor, description, index);
82 public abstract T retrieveDomElement();
85 public abstract XmlFile getContainingFile();
87 private static class NamedAnchor<T extends DomElement> extends DomAnchorImpl<T> {
88 private final DomAnchorImpl myParent;
89 private final AbstractDomChildrenDescription myDescr;
90 private final String myIndex;
92 private NamedAnchor(final DomAnchorImpl parent, final AbstractDomChildrenDescription descr, final String id) {
99 public boolean equals(final Object o) {
100 if (this == o) return true;
101 if (!(o instanceof NamedAnchor)) return false;
103 final NamedAnchor that = (NamedAnchor)o;
105 if (myDescr != null ? !myDescr.equals(that.myDescr) : that.myDescr != null) return false;
106 if (myIndex != null ? !myIndex.equals(that.myIndex) : that.myIndex != null) return false;
107 if (myParent != null ? !myParent.equals(that.myParent) : that.myParent != null) return false;
113 public int hashCode() {
115 result = (myParent != null ? myParent.hashCode() : 0);
116 result = 31 * result + (myDescr != null ? myDescr.hashCode() : 0);
117 result = 31 * result + (myIndex != null ? myIndex.hashCode() : 0);
121 public T retrieveDomElement() {
122 final DomElement parent = myParent.retrieveDomElement();
123 if (parent == null) return null;
125 final List<? extends DomElement> list = myDescr.getValues(parent);
126 for (final DomElement element : list) {
127 final String s = element.getGenericInfo().getElementName(element);
128 if (myIndex.equals(s)) {
136 public XmlFile getContainingFile() {
137 return myParent.getContainingFile();
140 private static class IndexedAnchor<T extends DomElement> extends DomAnchorImpl<T> {
141 private final DomAnchorImpl myParent;
142 private final AbstractDomChildrenDescription myDescr;
143 private final int myIndex;
145 private IndexedAnchor(final DomAnchorImpl parent, final AbstractDomChildrenDescription descr, final int index) {
152 public boolean equals(final Object o) {
153 if (this == o) return true;
154 if (!(o instanceof IndexedAnchor)) return false;
156 final IndexedAnchor that = (IndexedAnchor)o;
158 if (myIndex != that.myIndex) return false;
159 if (myDescr != null ? !myDescr.equals(that.myDescr) : that.myDescr != null) return false;
160 if (myParent != null ? !myParent.equals(that.myParent) : that.myParent != null) return false;
166 public int hashCode() {
168 result = (myParent != null ? myParent.hashCode() : 0);
169 result = 31 * result + (myDescr != null ? myDescr.hashCode() : 0);
170 result = 31 * result + myIndex;
174 public T retrieveDomElement() {
175 final DomElement parent = myParent.retrieveDomElement();
176 if (parent == null) return null;
178 final List<? extends DomElement> list = myDescr.getValues(parent);
179 if (myIndex < 0 || myIndex >= list.size()) return null;
181 return (T)list.get(myIndex);
185 public XmlFile getContainingFile() {
186 return myParent.getContainingFile();
190 private static class RootAnchor<T extends DomElement> extends DomAnchorImpl<T> {
191 private final XmlFile myFile;
192 private final Class<T> myClass;
194 private RootAnchor(final XmlFile file, final Class<T> aClass) {
200 public boolean equals(final Object o) {
201 if (this == o) return true;
202 if (!(o instanceof RootAnchor)) return false;
204 final RootAnchor that = (RootAnchor)o;
206 if (myClass != null ? !myClass.equals(that.myClass) : that.myClass != null) return false;
207 if (myFile != null ? !myFile.equals(that.myFile) : that.myFile != null) return false;
213 public int hashCode() {
215 result = (myFile != null ? myFile.hashCode() : 0);
216 result = 31 * result + (myClass != null ? myClass.hashCode() : 0);
220 public T retrieveDomElement() {
221 final DomFileElement<T> fileElement = DomManager.getDomManager(myFile.getProject()).getFileElement(myFile, myClass);
222 return fileElement == null ? null : fileElement.getRootElement();
226 public XmlFile getContainingFile() {