2 * Copyright (c) 2005 Your Corporation. All Rights Reserved.
4 package com
.intellij
.util
.xml
;
6 import com
.intellij
.openapi
.editor
.Editor
;
7 import com
.intellij
.psi
.PsiDocumentManager
;
8 import com
.intellij
.psi
.PsiElement
;
9 import com
.intellij
.psi
.PsiFile
;
10 import com
.intellij
.psi
.util
.PsiTreeUtil
;
11 import com
.intellij
.psi
.xml
.XmlAttributeValue
;
12 import com
.intellij
.psi
.xml
.XmlElement
;
13 import com
.intellij
.psi
.xml
.XmlFile
;
14 import com
.intellij
.psi
.xml
.XmlTag
;
15 import com
.intellij
.util
.ReflectionCache
;
16 import com
.intellij
.util
.ReflectionUtil
;
17 import com
.intellij
.util
.xml
.reflect
.DomAttributeChildDescription
;
18 import com
.intellij
.util
.xml
.reflect
.DomCollectionChildDescription
;
19 import com
.intellij
.util
.xml
.reflect
.DomFixedChildDescription
;
20 import com
.intellij
.util
.xml
.reflect
.DomGenericInfo
;
21 import org
.jetbrains
.annotations
.NonNls
;
22 import org
.jetbrains
.annotations
.NotNull
;
23 import org
.jetbrains
.annotations
.Nullable
;
25 import java
.lang
.reflect
.Method
;
26 import java
.lang
.reflect
.Type
;
27 import java
.lang
.reflect
.TypeVariable
;
33 public class DomUtil
{
34 public static final TypeVariable
<Class
<GenericValue
>> GENERIC_VALUE_TYPE_VARIABLE
= ReflectionCache
.getTypeParameters(GenericValue
.class)[0];
39 public static Class
extractParameterClassFromGenericType(Type type
) {
40 return getGenericValueParameter(type
);
43 public static boolean isGenericValueType(Type type
) {
44 return getGenericValueParameter(type
) != null;
48 public static <T
extends DomElement
> T
findByName(@NotNull Collection
<T
> list
, @NonNls @NotNull String name
) {
49 for (T element
: list
) {
50 String elementName
= element
.getGenericInfo().getElementName(element
);
51 if (elementName
!= null && elementName
.equals(name
)) {
59 public static String
[] getElementNames(@NotNull Collection
<?
extends DomElement
> list
) {
60 ArrayList
<String
> result
= new ArrayList
<String
>(list
.size());
61 if (list
.size() > 0) {
62 for (DomElement element
: list
) {
63 String name
= element
.getGenericInfo().getElementName(element
);
69 return result
.toArray(new String
[result
.size()]);
73 public static List
<XmlTag
> getElementTags(@NotNull Collection
<?
extends DomElement
> list
) {
74 ArrayList
<XmlTag
> result
= new ArrayList
<XmlTag
>(list
.size());
75 for (DomElement element
: list
) {
76 XmlTag tag
= element
.getXmlTag();
85 public static XmlTag
[] getElementTags(@NotNull DomElement
[] list
) {
86 XmlTag
[] result
= new XmlTag
[list
.length
];
88 for (DomElement element
: list
) {
89 XmlTag tag
= element
.getXmlTag();
98 public static List
<JavaMethod
> getFixedPath(DomElement element
) {
99 assert element
.isValid();
100 final LinkedList
<JavaMethod
> methods
= new LinkedList
<JavaMethod
>();
102 final DomElement parent
= element
.getParent();
103 if (parent
instanceof DomFileElement
) {
106 final JavaMethod method
= getGetterMethod(element
, parent
);
107 if (method
== null) {
110 methods
.addFirst(method
);
111 element
= element
.getParent();
117 private static JavaMethod
getGetterMethod(final DomElement element
, final DomElement parent
) {
118 final String xmlElementName
= element
.getXmlElementName();
119 final String namespace
= element
.getXmlElementNamespaceKey();
120 final DomGenericInfo genericInfo
= parent
.getGenericInfo();
122 if (element
instanceof GenericAttributeValue
) {
123 final DomAttributeChildDescription description
= genericInfo
.getAttributeChildDescription(xmlElementName
, namespace
);
124 assert description
!= null;
125 return description
.getGetterMethod();
128 final DomFixedChildDescription description
= genericInfo
.getFixedChildDescription(xmlElementName
, namespace
);
129 return description
!= null ? description
.getGetterMethod(description
.getValues(parent
).indexOf(element
)) : null;
132 public static Class
getGenericValueParameter(Type type
) {
133 return ReflectionUtil
.substituteGenericType(GENERIC_VALUE_TYPE_VARIABLE
, type
);
137 public static XmlElement
getValueElement(GenericDomValue domValue
) {
138 if (domValue
instanceof GenericAttributeValue
) {
139 final GenericAttributeValue value
= (GenericAttributeValue
)domValue
;
140 final XmlAttributeValue attributeValue
= value
.getXmlAttributeValue();
141 return attributeValue
== null ? value
.getXmlAttribute() : attributeValue
;
143 return domValue
.getXmlTag();
147 public static List
<?
extends DomElement
> getIdentitySiblings(DomElement element
) {
148 final Method nameValueMethod
= ElementPresentationManager
.findNameValueMethod(element
.getClass());
149 if (nameValueMethod
!= null) {
150 final NameValue nameValue
= DomReflectionUtil
.findAnnotationDFS(nameValueMethod
, NameValue
.class);
151 if (nameValue
== null || nameValue
.unique()) {
152 final String stringValue
= ElementPresentationManager
.getElementName(element
);
153 if (stringValue
!= null) {
154 final DomElement parent
= element
.getManager().getIdentityScope(element
);
155 final DomGenericInfo domGenericInfo
= parent
.getGenericInfo();
156 final String tagName
= element
.getXmlElementName();
157 final DomCollectionChildDescription childDescription
= domGenericInfo
.getCollectionChildDescription(tagName
, element
.getXmlElementNamespaceKey());
158 if (childDescription
!= null) {
159 final ArrayList
<DomElement
> list
= new ArrayList
<DomElement
>(childDescription
.getValues(parent
));
160 list
.remove(element
);
166 return Collections
.emptyList();
170 public static DomElement
findDuplicateNamedValue(DomElement element
, String newName
) {
171 return ElementPresentationManager
.findByName(getIdentitySiblings(element
), newName
);
174 public static boolean isAncestor(@NotNull DomElement ancestor
, @NotNull DomElement descendant
, boolean strict
) {
175 if (!strict
&& ancestor
.equals(descendant
)) return true;
176 final DomElement parent
= descendant
.getParent();
177 return parent
!= null && isAncestor(ancestor
, parent
, false);
180 public static void acceptAvailableChildren(final DomElement element
, final DomElementVisitor visitor
) {
181 final XmlTag tag
= element
.getXmlTag();
183 for (XmlTag xmlTag
: tag
.getSubTags()) {
184 final DomElement childElement
= element
.getManager().getDomElement(xmlTag
);
185 if (childElement
!= null) {
186 childElement
.accept(visitor
);
192 public static Collection
<Class
> getAllInterfaces(final Class aClass
, final Collection
<Class
> result
) {
193 final Class
[] interfaces
= ReflectionCache
.getInterfaces(aClass
);
194 result
.addAll(Arrays
.asList(interfaces
));
195 if (aClass
.getSuperclass() != null) {
196 getAllInterfaces(aClass
.getSuperclass(), result
);
198 for (Class anInterface
: interfaces
) {
199 getAllInterfaces(anInterface
, result
);
205 public static <T
> T
getParentOfType(final DomElement element
, final Class
<T
> requiredClass
, final boolean strict
) {
206 for (DomElement curElement
= strict
&& element
!= null? element
.getParent() : element
;
208 curElement
= curElement
.getParent()) {
209 if (requiredClass
.isInstance(curElement
)) {
210 return (T
)curElement
;
217 public static DomElement
getContextElement(@Nullable final Editor editor
) {
218 if(editor
== null) return null;
220 final PsiFile file
= PsiDocumentManager
.getInstance(editor
.getProject()).getPsiFile(editor
.getDocument());
221 if (!(file
instanceof XmlFile
)) {
225 int offset
= editor
.getCaretModel().getOffset();
226 PsiElement element
= file
.findElementAt(offset
);
227 if (element
== null) return null;
229 XmlTag tag
= PsiTreeUtil
.getParentOfType(element
, XmlTag
.class);
230 while (tag
!= null) {
231 final DomElement domElement
= DomManager
.getDomManager(file
.getProject()).getDomElement(tag
);
232 if(domElement
!= null) return domElement
;
234 tag
= PsiTreeUtil
.getParentOfType(tag
, XmlTag
.class, true);