run tests on module classpath: Inspection Gadgets
[idea/community.git] / platform / lang-impl / src / com / intellij / ide / projectView / impl / nodes / AbstractPsiBasedNode.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
17 package com.intellij.ide.projectView.impl.nodes;
18
19 import com.intellij.codeInsight.navigation.NavigationUtil;
20 import com.intellij.ide.projectView.PresentationData;
21 import com.intellij.ide.projectView.ProjectViewNode;
22 import com.intellij.ide.projectView.ProjectViewNodeDecorator;
23 import com.intellij.ide.projectView.ViewSettings;
24 import com.intellij.ide.util.treeView.AbstractTreeNode;
25 import com.intellij.ide.util.treeView.ValidateableNode;
26 import com.intellij.navigation.NavigationItem;
27 import com.intellij.openapi.diagnostic.Logger;
28 import com.intellij.openapi.editor.colors.CodeInsightColors;
29 import com.intellij.openapi.extensions.Extensions;
30 import com.intellij.openapi.module.Module;
31 import com.intellij.openapi.project.IndexNotReadyException;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.util.Iconable;
34 import com.intellij.openapi.util.UserDataHolderBase;
35 import com.intellij.openapi.vcs.FileStatus;
36 import com.intellij.openapi.vcs.FileStatusManager;
37 import com.intellij.openapi.vfs.VirtualFile;
38 import com.intellij.psi.PsiDirectory;
39 import com.intellij.psi.PsiElement;
40 import com.intellij.psi.PsiFile;
41 import com.intellij.psi.util.PsiUtilBase;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
44
45 import javax.swing.*;
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.Collections;
49
50 /**
51  * Class for node descriptors based on PsiElements. Subclasses should define
52  * method that extract PsiElement from Value.
53  * @param <Value> Value of node descriptor
54  */
55 public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value> implements ValidateableNode {
56   private static final Logger LOG = Logger.getInstance(AbstractPsiBasedNode.class.getName());
57
58   protected AbstractPsiBasedNode(final Project project,
59                                 final Value value,
60                                 final ViewSettings viewSettings) {
61     super(project, value, viewSettings);
62   }
63
64   @Nullable
65   protected abstract PsiElement extractPsiFromValue();
66   @Nullable
67   protected abstract Collection<AbstractTreeNode> getChildrenImpl();
68   protected abstract void updateImpl(final PresentationData data);
69
70   @NotNull
71   public final Collection<AbstractTreeNode> getChildren() {
72     final PsiElement psiElement = extractPsiFromValue();
73     if (psiElement == null) {
74       return new ArrayList<AbstractTreeNode>();
75     }
76     final boolean valid = psiElement.isValid();
77     if (!LOG.assertTrue(valid)) {
78       return Collections.emptyList();
79     }
80
81     final Collection<AbstractTreeNode> children = getChildrenImpl();
82     return children != null ? children : Collections.<AbstractTreeNode>emptyList();
83   }
84
85   public boolean isValid() {
86     final PsiElement psiElement = extractPsiFromValue();
87     return psiElement != null && psiElement.isValid();
88   }
89
90   protected boolean isMarkReadOnly() {
91     final AbstractTreeNode parent = getParent();
92     if (parent == null) {
93       return false;
94     }
95     if (parent instanceof AbstractPsiBasedNode) {
96       final PsiElement psiElement = ((AbstractPsiBasedNode)parent).extractPsiFromValue();
97       return psiElement instanceof PsiDirectory;
98     }
99
100     final Object parentValue = parent.getValue();
101     return parentValue instanceof PsiDirectory || parentValue instanceof Module;
102   }
103
104
105   public FileStatus getFileStatus() {
106     VirtualFile file = getVirtualFileForValue();
107     if (file == null) {
108       return FileStatus.NOT_CHANGED;
109     }
110     else {
111       return FileStatusManager.getInstance(getProject()).getStatus(file);
112     }
113   }
114
115   @Nullable
116   private VirtualFile getVirtualFileForValue() {
117     PsiElement psiElement = extractPsiFromValue();
118     if (psiElement == null) {
119       return null;
120     }
121     return PsiUtilBase.getVirtualFile(psiElement);
122   }
123
124   // Should be called in atomic action
125
126   public void update(final PresentationData data) {
127     if (!validate()) {
128       return;
129     }
130
131     final PsiElement value = extractPsiFromValue();
132     LOG.assertTrue(value.isValid());
133
134     int flags = getIconableFlags();
135
136     try {
137       Icon icon = value.getIcon(flags);
138       data.setClosedIcon(icon);
139       data.setOpenIcon(icon);
140     }
141     catch (IndexNotReadyException ignored) {
142     }
143     data.setPresentableText(myName);
144
145     try {
146       if (isDeprecated()) {
147         data.setAttributesKey(CodeInsightColors.DEPRECATED_ATTRIBUTES);
148       }
149     }
150     catch (IndexNotReadyException ignored) {
151     }
152     updateImpl(data);
153     for(ProjectViewNodeDecorator decorator: Extensions.getExtensions(ProjectViewNodeDecorator.EP_NAME, myProject)) {
154       decorator.decorate(this, data);
155     }
156
157     value.putUserData(Iconable.LAST_COMPUTED_ICON, data.getIcon(false));
158   }
159
160   protected int getIconableFlags() {
161     int flags = Iconable.ICON_FLAG_VISIBILITY;
162     if (isMarkReadOnly()) {
163       flags |= Iconable.ICON_FLAG_READ_STATUS;
164     }
165     return flags;
166   }
167
168   protected boolean isDeprecated() {
169     return false;
170   }
171
172   public boolean contains(@NotNull final VirtualFile file) {
173     final PsiElement psiElement = extractPsiFromValue();
174     if (psiElement == null || !psiElement.isValid()) {
175       return false;
176     }
177
178     final PsiFile containingFile = psiElement.getContainingFile();
179     if (containingFile == null) {
180       return false;
181     }
182     final VirtualFile valueFile = containingFile.getVirtualFile();
183     return valueFile != null && file.equals(valueFile);
184   }
185
186   @Nullable
187   public NavigationItem getNavigationItem() {
188     final PsiElement psiElement = extractPsiFromValue();
189     return (psiElement instanceof NavigationItem) ? (NavigationItem) psiElement : null;
190   }
191
192   public void navigate(boolean requestFocus) {
193     if (canNavigate()) {
194       if (requestFocus) {
195         NavigationUtil.activateFileWithPsiElement(extractPsiFromValue());
196       }
197       else {
198         getNavigationItem().navigate(requestFocus);
199       }
200     }
201   }
202
203   public boolean canNavigate() {
204     final NavigationItem item = getNavigationItem();
205     return item != null && item.canNavigate();
206   }
207
208   public boolean canNavigateToSource() {
209     final NavigationItem item = getNavigationItem();
210     return item != null && item.canNavigateToSource();
211   }
212
213   @Nullable
214   protected String calcTooltip() {
215     return null;
216   }
217
218   @Override
219   public boolean validate() {
220     final PsiElement psiElement = extractPsiFromValue();
221     if (psiElement == null || !psiElement.isValid()) {
222       setValue(null);
223     }
224
225     return getValue() != null;
226   }
227 }