dom anchor openapi
[idea/community.git] / xml / dom-impl / src / com / intellij / util / xml / impl / DomAnchorImpl.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.util.xml.impl;
17
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.*;
22 import com.intellij.util.xml.reflect.AbstractDomChildrenDescription;
23 import com.intellij.openapi.diagnostic.Logger;
24 import org.jetbrains.annotations.Nullable;
25 import org.jetbrains.annotations.NotNull;
26
27 import java.util.List;
28
29 /**
30  * @author peter
31  */
32 public abstract class DomAnchorImpl<T extends DomElement> implements DomAnchor<T> {
33   private static final Logger LOG = Logger.getInstance("#com.intellij.util.xml.impl.DomAnchorImpl");
34
35   public static <T extends DomElement> DomAnchorImpl<T> createAnchor(@NotNull T t) {
36     final DomElement parent = t.getParent();
37     if (parent == null) {
38       LOG.error("Parent null: " + t);
39     }
40
41     if (parent instanceof DomFileElementImpl) {
42       final DomFileElementImpl fileElement = (DomFileElementImpl)parent;
43       return new RootAnchor<T>(fileElement.getFile(), fileElement.getRootElementClass());
44     }
45
46     final DomAnchorImpl<DomElement> parentAnchor = createAnchor(parent);
47     final String name = t.getGenericInfo().getElementName(t);
48     final AbstractDomChildrenDescription description = t.getChildDescription();
49     if (name != null) {
50       return new NamedAnchor<T>(parentAnchor, description, name);
51     }
52
53     final List<? extends DomElement> values = description.getValues(parent);
54     final int index = values.indexOf(t);
55     if (index < 0) {
56       final XmlTag parentTag = parent.getXmlTag();
57       StringBuilder diag = new StringBuilder("Index<0: description=" + description + "\nparent=" + parent + "\nt=" + t + "\nvalues=" + values + "\n");
58       if (parentTag != null) {
59         diag.append("Parent tag: ").append(parentTag.getName()).append("\n");
60         if (t instanceof GenericAttributeValue) {
61           for (XmlAttribute attribute : parentTag.getAttributes()) {
62             diag.append("attr: ").append(attribute.getName());
63           }
64           diag.append("\n");
65         } else {
66           for (XmlTag tag : parentTag.getSubTags()) {
67             diag.append("subtag: ").append(tag.getName());
68           }
69           diag.append("\n");
70         }
71       }
72       diag.append("Child name: ").append(t.getXmlElementName()).append(";").append(t.getXmlElementNamespaceKey());
73       LOG.error(diag);
74     }
75     return new IndexedAnchor<T>(parentAnchor, description, index);
76   }
77
78   @Nullable
79   public abstract T retrieveDomElement();
80
81   @NotNull
82   public abstract XmlFile getContainingFile();
83
84   private static class NamedAnchor<T extends DomElement> extends DomAnchorImpl<T> {
85     private final DomAnchorImpl myParent;
86     private final AbstractDomChildrenDescription myDescr;
87     private final String myIndex;
88
89     private NamedAnchor(final DomAnchorImpl parent, final AbstractDomChildrenDescription descr, final String id) {
90       myParent = parent;
91       myDescr = descr;
92       myIndex = id;
93     }
94
95     @Override
96     public boolean equals(final Object o) {
97       if (this == o) return true;
98       if (!(o instanceof NamedAnchor)) return false;
99
100       final NamedAnchor that = (NamedAnchor)o;
101
102       if (myDescr != null ? !myDescr.equals(that.myDescr) : that.myDescr != null) return false;
103       if (myIndex != null ? !myIndex.equals(that.myIndex) : that.myIndex != null) return false;
104       if (myParent != null ? !myParent.equals(that.myParent) : that.myParent != null) return false;
105
106       return true;
107     }
108
109     @Override
110     public int hashCode() {
111       int result;
112       result = (myParent != null ? myParent.hashCode() : 0);
113       result = 31 * result + (myDescr != null ? myDescr.hashCode() : 0);
114       result = 31 * result + (myIndex != null ? myIndex.hashCode() : 0);
115       return result;
116     }
117
118     public T retrieveDomElement() {
119       final DomElement parent = myParent.retrieveDomElement();
120       if (parent == null) return null;
121
122       final List<? extends DomElement> list = myDescr.getValues(parent);
123       for (final DomElement element : list) {
124         final String s = element.getGenericInfo().getElementName(element);
125         if (myIndex.equals(s)) {
126           return (T)element;
127         }
128       }
129       return null;
130     }
131
132     @NotNull
133     public XmlFile getContainingFile() {
134       return myParent.getContainingFile();
135     }
136   }
137   private static class IndexedAnchor<T extends DomElement> extends DomAnchorImpl<T> {
138     private final DomAnchorImpl myParent;
139     private final AbstractDomChildrenDescription myDescr;
140     private final int myIndex;
141
142     private IndexedAnchor(final DomAnchorImpl parent, final AbstractDomChildrenDescription descr, final int index) {
143       myParent = parent;
144       myDescr = descr;
145       myIndex = index;
146     }
147
148     @Override
149     public boolean equals(final Object o) {
150       if (this == o) return true;
151       if (!(o instanceof IndexedAnchor)) return false;
152
153       final IndexedAnchor that = (IndexedAnchor)o;
154
155       if (myIndex != that.myIndex) return false;
156       if (myDescr != null ? !myDescr.equals(that.myDescr) : that.myDescr != null) return false;
157       if (myParent != null ? !myParent.equals(that.myParent) : that.myParent != null) return false;
158
159       return true;
160     }
161
162     @Override
163     public int hashCode() {
164       int result;
165       result = (myParent != null ? myParent.hashCode() : 0);
166       result = 31 * result + (myDescr != null ? myDescr.hashCode() : 0);
167       result = 31 * result + myIndex;
168       return result;
169     }
170
171     public T retrieveDomElement() {
172       final DomElement parent = myParent.retrieveDomElement();
173       if (parent == null) return null;
174
175       final List<? extends DomElement> list = myDescr.getValues(parent);
176       if (myIndex < 0 || myIndex >= list.size()) return null;
177
178       return (T)list.get(myIndex);
179     }
180
181     @NotNull
182     public XmlFile getContainingFile() {
183       return myParent.getContainingFile();
184     }
185   }
186
187   private static class RootAnchor<T extends DomElement> extends DomAnchorImpl<T> {
188     private final XmlFile myFile;
189     private final Class<T> myClass;
190
191     private RootAnchor(final XmlFile file, final Class<T> aClass) {
192       myFile = file;
193       myClass = aClass;
194     }
195
196     @Override
197     public boolean equals(final Object o) {
198       if (this == o) return true;
199       if (!(o instanceof RootAnchor)) return false;
200
201       final RootAnchor that = (RootAnchor)o;
202
203       if (myClass != null ? !myClass.equals(that.myClass) : that.myClass != null) return false;
204       if (myFile != null ? !myFile.equals(that.myFile) : that.myFile != null) return false;
205
206       return true;
207     }
208
209     @Override
210     public int hashCode() {
211       int result;
212       result = (myFile != null ? myFile.hashCode() : 0);
213       result = 31 * result + (myClass != null ? myClass.hashCode() : 0);
214       return result;
215     }
216
217     public T retrieveDomElement() {
218       final DomFileElement<T> fileElement = DomManager.getDomManager(myFile.getProject()).getFileElement(myFile, myClass);
219       return fileElement == null ? null : fileElement.getRootElement();
220     }
221
222     @NotNull
223     public XmlFile getContainingFile() {
224       return myFile;
225     }
226   }
227
228
229 }