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.
17 package com
.intellij
.util
.xml
.tree
;
19 import com
.intellij
.lang
.annotation
.HighlightSeverity
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.util
.Key
;
22 import com
.intellij
.psi
.xml
.XmlFile
;
23 import com
.intellij
.psi
.xml
.XmlTag
;
24 import com
.intellij
.ui
.SimpleTextAttributes
;
25 import com
.intellij
.ui
.treeStructure
.SimpleNode
;
26 import com
.intellij
.ui
.treeStructure
.SimpleTree
;
27 import com
.intellij
.util
.ReflectionUtil
;
28 import com
.intellij
.util
.xml
.*;
29 import com
.intellij
.util
.xml
.highlighting
.DomElementAnnotationsManager
;
30 import com
.intellij
.util
.xml
.highlighting
.DomElementProblemDescriptor
;
31 import com
.intellij
.util
.xml
.highlighting
.DomElementsProblemsHolder
;
32 import com
.intellij
.util
.xml
.reflect
.DomCollectionChildDescription
;
33 import com
.intellij
.util
.xml
.reflect
.DomFixedChildDescription
;
34 import com
.intellij
.util
.xml
.ui
.TooltipUtils
;
35 import com
.intellij
.xml
.XmlElementDescriptor
;
36 import org
.jetbrains
.annotations
.NotNull
;
37 import org
.jetbrains
.annotations
.Nullable
;
39 import java
.awt
.event
.InputEvent
;
40 import java
.awt
.event
.MouseEvent
;
41 import java
.lang
.reflect
.Type
;
45 public class BaseDomElementNode
extends AbstractDomElementNode
{
46 public static final Key
<Comparator
<AbstractDomElementNode
>> COMPARATOR_KEY
= Key
.create("COMPARATOR_KEY");
47 public static final Key
<List
<Class
>> CONSOLIDATED_NODES_KEY
= Key
.create("CONSOLIDATED_NODES_KEY");
48 public static final Key
<List
<Class
>> FOLDER_NODES_KEY
= Key
.create("FOLDER_NODES_KEY");
50 private final DomElement myRootDomElement
;
51 private final DomElement myDomElement
;
52 private final String myTagName
;
53 private final boolean folder
;
55 public BaseDomElementNode(final DomElement modelElement
) {
56 this(modelElement
, modelElement
, null);
59 public BaseDomElementNode(final DomElement modelElement
, final DomElement modelRootElement
, SimpleNode parent
) {
60 super(modelElement
, parent
);
62 myDomElement
= modelElement
;
63 myRootDomElement
= modelRootElement
;
64 myTagName
= modelElement
.getXmlElementName();
65 folder
= isMarkedType(modelElement
.getDomElementType(), FOLDER_NODES_KEY
);
68 public SimpleNode
[] getChildren() {
69 return doGetChildren(myDomElement
);
72 public void handleDoubleClickOrEnter(SimpleTree tree
, InputEvent inputEvent
) {
73 if (inputEvent
instanceof MouseEvent
) {
76 final DomElement domElement
= getDomElement();
77 if (domElement
.isValid()) {
78 final DomElementNavigationProvider provider
= DomElementsNavigationManager
.getManager(domElement
.getManager().getProject())
79 .getDomElementsNavigateProvider(DomElementsNavigationManager
.DEFAULT_PROVIDER_NAME
);
81 provider
.navigate(domElement
, true);
85 protected final SimpleNode
[] doGetChildren(final DomElement element
) {
86 if (!element
.isValid()) return NO_CHILDREN
;
88 List
<SimpleNode
> children
= new ArrayList
<SimpleNode
>();
89 final XmlTag tag
= element
.getXmlTag();
91 if (tag
!= null && !(tag
.getContainingFile() instanceof XmlFile
)) return NO_CHILDREN
;
92 final XmlElementDescriptor xmlElementDescriptor
= tag
== null ?
null : tag
.getDescriptor();
93 final XmlElementDescriptor
[] xmlDescriptors
= xmlElementDescriptor
== null ?
null : xmlElementDescriptor
.getElementsDescriptors(tag
);
95 for (DomFixedChildDescription description
: element
.getGenericInfo().getFixedChildrenDescriptions()) {
96 String childName
= description
.getXmlElementName();
97 if (xmlDescriptors
!= null) {
98 if (findDescriptor(xmlDescriptors
, childName
) == -1) continue;
100 final List
<?
extends DomElement
> values
= description
.getStableValues(element
);
101 if (shouldBeShown(description
.getType())) {
102 if (DomUtil
.isGenericValueType(description
.getType())) {
103 for (DomElement value
: values
) {
104 children
.add(new GenericValueNode((GenericDomValue
)value
, this));
108 for (DomElement domElement
: values
) {
109 children
.add(new BaseDomElementNode(domElement
, myRootDomElement
, this));
115 for (DomCollectionChildDescription description
: element
.getGenericInfo().getCollectionChildrenDescriptions()) {
116 if (shouldBeShown(description
.getType())) {
117 DomElementsGroupNode groupNode
= new DomElementsGroupNode(element
, description
, this, myRootDomElement
);
118 if (isMarkedType(description
.getType(), CONSOLIDATED_NODES_KEY
)) {
119 Collections
.addAll(children
, groupNode
.getChildren());
122 children
.add(groupNode
);
127 AbstractDomElementNode
[] childrenNodes
= children
.toArray(new AbstractDomElementNode
[children
.size()]);
129 Comparator
<AbstractDomElementNode
> comparator
= DomUtil
.getFile(myDomElement
).getUserData(COMPARATOR_KEY
);
130 if (comparator
== null) {
131 comparator
= getDefaultComparator(element
);
133 if (comparator
!= null) {
134 Arrays
.sort(childrenNodes
, comparator
);
137 return childrenNodes
;
141 protected Comparator
<AbstractDomElementNode
> getDefaultComparator(DomElement element
) {
142 final XmlTag tag
= element
.getXmlTag();
144 final XmlElementDescriptor descriptor
= tag
.getDescriptor();
145 if (descriptor
!= null) {
146 final XmlElementDescriptor
[] childDescriptors
= descriptor
.getElementsDescriptors(tag
);
147 if (childDescriptors
!= null && childDescriptors
.length
> 1) {
148 return new Comparator
<AbstractDomElementNode
>() {
149 public int compare(final AbstractDomElementNode o1
, final AbstractDomElementNode o2
) {
150 return findDescriptor(childDescriptors
, o1
.getTagName()) - findDescriptor(childDescriptors
, o2
.getTagName());
159 protected static int findDescriptor(XmlElementDescriptor
[] descriptors
, String name
) {
160 for (int i
= 0; i
< descriptors
.length
; i
++) {
161 if (descriptors
[i
].getDefaultName().equals(name
)) {
169 public List
<DomCollectionChildDescription
> getConsolidatedChildrenDescriptions() {
170 if (!myDomElement
.isValid()) return Collections
.emptyList();
172 final List
<DomCollectionChildDescription
> consolidated
= new ArrayList
<DomCollectionChildDescription
>();
173 for (DomCollectionChildDescription description
: myDomElement
.getGenericInfo().getCollectionChildrenDescriptions()) {
174 if (isMarkedType(description
.getType(), CONSOLIDATED_NODES_KEY
)) {
175 consolidated
.add(description
);
181 public Object
[] getEqualityObjects() {
182 return new Object
[]{myDomElement
};
185 protected void doUpdate() {
186 if (!myDomElement
.isValid()) return;
187 final Project project
= myDomElement
.getManager().getProject();
188 if (project
.isDisposed()) return;
190 setUniformIcon(getNodeIcon());
193 final DomElementAnnotationsManager manager
= DomElementAnnotationsManager
.getInstance(project
);
194 final DomElementsProblemsHolder holder
= manager
.getCachedProblemHolder(myDomElement
);
195 final List
<DomElementProblemDescriptor
> problems
=
196 holder
.getProblems(myDomElement
, highlightIfChildrenHaveProblems(), HighlightSeverity
.ERROR
);
198 if (problems
.size() > 0) {
199 final String toolTip
= TooltipUtils
.getTooltipText(problems
);
200 addColoredFragment(getNodeName(), toolTip
, getWavedAttributes(SimpleTextAttributes
.STYLE_PLAIN
));
201 if (isShowContainingFileInfo()) {
202 addColoredFragment(" (" + DomUtil
.getFile(myDomElement
).getName() + ")", toolTip
, SimpleTextAttributes
.GRAY_ATTRIBUTES
);
205 else if (myDomElement
.getXmlTag() == null && !(myDomElement
instanceof DomFileElement
)) {
206 addColoredFragment(getNodeName(), folder ? SimpleTextAttributes
.GRAYED_BOLD_ATTRIBUTES
: SimpleTextAttributes
.GRAYED_ATTRIBUTES
);
209 addColoredFragment(getNodeName(), SimpleTextAttributes
.REGULAR_BOLD_ATTRIBUTES
);
210 final int childrenCount
= getChildren().length
;
211 addColoredFragment(" (" + childrenCount
+ ')', SimpleTextAttributes
.GRAY_ATTRIBUTES
);
214 addColoredFragment(getNodeName(), SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
216 if (isShowContainingFileInfo()) {
217 addColoredFragment(" (" + DomUtil
.getFile(myDomElement
).getName() + ")", SimpleTextAttributes
.GRAY_ATTRIBUTES
);
222 protected boolean isMarkedType(Type type
, Key
<List
<Class
>> key
) {
226 final List
<Class
> classes
= DomUtil
.getFile(getDomElement()).getUserData(key
);
227 if (classes
!= null) {
228 Class clazz
= ReflectionUtil
.getRawType(type
);
229 return classes
.contains(clazz
);
234 protected boolean highlightIfChildrenHaveProblems() {
238 public String
getNodeName() {
239 if (!myDomElement
.isValid()) return "";
241 final String name
= myDomElement
.getPresentation().getElementName();
242 return name
!= null && name
.trim().length() > 0 ? name
: getPropertyName();
245 public String
getTagName() {
249 public DomElement
getDomElement() {
253 public boolean isAutoExpandNode() {
254 return getParent() == null;
257 public boolean expandOnDoubleClick() {
261 public boolean isShowContainingFileInfo() {
262 if (!myRootDomElement
.isValid()) return false;
263 DomElement root
= myRootDomElement
;
264 while (root
instanceof StableElement
) {
265 root
= ((StableElement
<DomElement
>) root
).getWrappedElement();
267 return root
instanceof MergedObject
&& ((MergedObject
)root
).getImplementations().size() > 1;