IDEA-52720: Property access highlighting in Groovy broken
[idea/community.git] / java / java-impl / src / com / intellij / ide / projectView / impl / ClassesTreeStructureProvider.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.ide.projectView.impl;
17
18 import com.intellij.ide.projectView.PresentationData;
19 import com.intellij.ide.projectView.ProjectViewNode;
20 import com.intellij.ide.projectView.SelectableTreeStructureProvider;
21 import com.intellij.ide.projectView.ViewSettings;
22 import com.intellij.ide.projectView.impl.nodes.ClassTreeNode;
23 import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
24 import com.intellij.ide.util.treeView.AbstractTreeNode;
25 import com.intellij.openapi.project.DumbAware;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.roots.ProjectFileIndex;
28 import com.intellij.openapi.roots.ProjectRootManager;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.psi.*;
31 import org.jetbrains.annotations.Nullable;
32
33 import java.util.ArrayList;
34 import java.util.Collection;
35
36 public class ClassesTreeStructureProvider implements SelectableTreeStructureProvider, DumbAware {
37   private final Project myProject;
38
39   public ClassesTreeStructureProvider(Project project) {
40     myProject = project;
41   }
42
43   public Collection<AbstractTreeNode> modify(AbstractTreeNode parent, Collection<AbstractTreeNode> children, ViewSettings settings) {
44     ArrayList<AbstractTreeNode> result = new ArrayList<AbstractTreeNode>();
45     for (final AbstractTreeNode child : children) {
46       Object o = child.getValue();
47       if (o instanceof PsiClassOwner) {
48         final ViewSettings settings1 = ((ProjectViewNode)parent).getSettings();
49         final PsiClassOwner classOwner = (PsiClassOwner)o;
50         PsiClass[] classes = classOwner.getClasses();
51         final VirtualFile file = classOwner.getVirtualFile();
52         if (fileInRoots(file)) {
53           if (classes.length == 1 && !(classes[0] instanceof SyntheticElement)) {
54             result.add(new ClassTreeNode(myProject, classes[0], settings1));
55           } else {
56             result.add(new PsiClassOwnerTreeNode(classOwner, settings1));
57           }
58           continue;
59         }
60       }
61       result.add(child);
62     }
63     return result;
64   }
65
66   private boolean fileInRoots(VirtualFile file) {
67     final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex();
68     return file != null &&
69         (index.isInSourceContent(file) || index.isInLibraryClasses(file) || index.isInLibrarySource(file));
70   }
71
72   public Object getData(Collection<AbstractTreeNode> selected, String dataName) {
73     return null;
74   }
75
76   public PsiElement getTopLevelElement(final PsiElement element) {
77     PsiFile baseRootFile = getBaseRootFile(element);
78     if (baseRootFile == null) return null;
79
80     if (!fileInRoots(baseRootFile.getVirtualFile())) return baseRootFile;
81
82     PsiElement current = element;
83     while (current != null) {
84       if (current instanceof PsiFileSystemItem) {
85         break;
86       }
87       if (isTopLevelClass(current, baseRootFile)) {
88         break;
89       }
90       current = current.getParent();
91     }
92
93     if (current instanceof PsiClassOwner) {
94       PsiClass[] classes = ((PsiClassOwner)current).getClasses();
95       if (classes.length == 1 && !(classes[0] instanceof SyntheticElement) && isTopLevelClass(classes[0], baseRootFile)) {
96         current = classes[0];
97       }
98     }
99     return current instanceof PsiClass ? current : baseRootFile;
100   }
101
102   @Nullable
103   private static PsiFile getBaseRootFile(PsiElement element) {
104     final PsiFile containingFile = element.getContainingFile();
105     if (containingFile == null) return null;
106
107     final FileViewProvider viewProvider = containingFile.getViewProvider();
108     return viewProvider.getPsi(viewProvider.getBaseLanguage());
109   }
110
111   private static boolean isTopLevelClass(final PsiElement element, PsiFile baseRootFile) {
112
113     if (!(element instanceof PsiClass)) {
114       return false;
115     }
116     final PsiFile parentFile = parentFileOf((PsiClass)element);
117                                         // do not select JspClass
118     return parentFile != null && parentFile.getLanguage() == baseRootFile.getLanguage();
119   }
120
121   @Nullable
122   private static PsiFile parentFileOf(final PsiClass psiClass) {
123     return psiClass.getContainingClass() == null ? psiClass.getContainingFile() : null;
124   }
125
126   private static class PsiClassOwnerTreeNode extends PsiFileNode {
127
128     public PsiClassOwnerTreeNode(PsiClassOwner classOwner, ViewSettings settings) {
129       super(classOwner.getProject(), classOwner, settings);
130     }
131
132     @Override
133     public Collection<AbstractTreeNode> getChildrenImpl() {
134       final ViewSettings settings = getSettings();
135       final ArrayList<AbstractTreeNode> result = new ArrayList<AbstractTreeNode>();
136       for (PsiClass aClass : ((PsiClassOwner)getValue()).getClasses()) {
137         if (!(aClass instanceof SyntheticElement)) {
138           result.add(new ClassTreeNode(myProject, aClass, settings));
139         }
140       }
141       return result;
142     }
143     
144     protected void updateImpl(PresentationData data) {
145       super.updateImpl(data);
146       data.setPresentableText(getValue().getName());
147       data.setIcons(getValue().getViewProvider().getVirtualFile().getIcon());
148     }
149
150   }
151 }