EA-33333 - NPE: HierarchyBrowserBase$CloseAction.actionPerformed
[idea/community.git] / platform / lang-impl / src / com / intellij / ide / hierarchy / HierarchyBrowserBase.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.hierarchy;
18
19 import com.intellij.ide.actions.CloseTabToolbarAction;
20 import com.intellij.ide.actions.ContextHelpAction;
21 import com.intellij.ide.util.treeView.AbstractTreeUi;
22 import com.intellij.openapi.Disposable;
23 import com.intellij.openapi.actionSystem.*;
24 import com.intellij.openapi.progress.ProgressIndicator;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.ui.SimpleToolWindowPanel;
27 import com.intellij.pom.Navigatable;
28 import com.intellij.psi.NavigatablePsiElement;
29 import com.intellij.psi.PsiElement;
30 import com.intellij.psi.util.PsiUtilBase;
31 import com.intellij.ui.AutoScrollToSourceHandler;
32 import com.intellij.ui.TreeSpeedSearch;
33 import com.intellij.ui.content.Content;
34 import com.intellij.ui.content.tabs.PinToolwindowTabAction;
35 import com.intellij.ui.treeStructure.Tree;
36 import com.intellij.util.ui.UIUtil;
37 import com.intellij.util.ui.tree.TreeUtil;
38 import org.jetbrains.annotations.NonNls;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import javax.swing.*;
43 import javax.swing.tree.DefaultMutableTreeNode;
44 import javax.swing.tree.TreePath;
45 import javax.swing.tree.TreeSelectionModel;
46 import java.util.ArrayList;
47
48 /**
49  * @author yole
50  */
51 public abstract class HierarchyBrowserBase extends SimpleToolWindowPanel implements HierarchyBrowser, Disposable, DataProvider {
52   private static final HierarchyNodeDescriptor[] EMPTY_DESCRIPTORS = new HierarchyNodeDescriptor[0];
53
54   protected Content myContent;
55   private final AutoScrollToSourceHandler myAutoScrollToSourceHandler;
56   protected final Project myProject;
57
58   protected HierarchyBrowserBase(Project project) {
59     super(true, true);
60     myProject = project;
61     myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() {
62
63       protected boolean isAutoScrollMode() {
64         return HierarchyBrowserManager.getInstance(myProject).getState().IS_AUTOSCROLL_TO_SOURCE;
65       }
66
67       protected void setAutoScrollMode(final boolean state) {
68         HierarchyBrowserManager.getInstance(myProject).getState().IS_AUTOSCROLL_TO_SOURCE = state;
69       }
70     };
71   }
72
73   public void setContent(final Content content) {
74     myContent = content;
75   }
76
77   protected void buildUi(JComponent toolbar, JComponent content) {
78     setToolbar(toolbar);
79     setContent(content);
80   }
81
82   public void dispose() {
83   }
84
85   protected ActionToolbar createToolbar(final String place, final String helpID) {
86     final DefaultActionGroup actionGroup = new DefaultActionGroup();
87     appendActions(actionGroup, helpID);
88     final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(place, actionGroup, true);
89     actionToolbar.setTargetComponent(this);
90     return actionToolbar;
91   }
92
93   protected void appendActions(@NotNull DefaultActionGroup actionGroup, @Nullable String helpID) {
94     actionGroup.add(myAutoScrollToSourceHandler.createToggleAction());
95     actionGroup.add(PinToolwindowTabAction.getPinAction());
96     actionGroup.add(new CloseAction());
97     if (helpID != null) {
98       actionGroup.add(new ContextHelpAction(helpID));
99     }
100   }
101
102   protected abstract JTree getCurrentTree();
103   protected abstract HierarchyTreeBuilder getCurrentBuilder();
104
105   @Nullable
106   protected abstract PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor);
107
108   @Nullable
109   protected DefaultMutableTreeNode getSelectedNode() {
110     final JTree tree = getCurrentTree();
111     if (tree == null) return null;
112     final TreePath path = tree.getSelectionPath();
113     if (path == null) return null;
114     final Object lastPathComponent = path.getLastPathComponent();
115     if (!(lastPathComponent instanceof DefaultMutableTreeNode)) return null;
116     return (DefaultMutableTreeNode)lastPathComponent;
117   }
118
119   @Nullable
120   protected final PsiElement getSelectedElement() {
121     final DefaultMutableTreeNode node = getSelectedNode();
122     final HierarchyNodeDescriptor descriptor = node != null ? getDescriptor(node) : null;
123     return descriptor != null ? getElementFromDescriptor(descriptor) : null;
124   }
125
126   @Nullable
127   protected HierarchyNodeDescriptor getDescriptor(DefaultMutableTreeNode node) {
128     final Object userObject = node != null ? node.getUserObject() : null;
129     if (userObject instanceof HierarchyNodeDescriptor) {
130       return (HierarchyNodeDescriptor)userObject;
131     }
132     return null;
133   }
134
135   public final HierarchyNodeDescriptor[] getSelectedDescriptors() {
136     final JTree tree = getCurrentTree();
137     if (tree == null) {
138       return EMPTY_DESCRIPTORS;
139     }
140     final TreePath[] paths = tree.getSelectionPaths();
141     if (paths == null || paths.length == 0) {
142       return EMPTY_DESCRIPTORS;
143     }
144     final ArrayList<HierarchyNodeDescriptor> list = new ArrayList<HierarchyNodeDescriptor>(paths.length);
145     for (final TreePath path : paths) {
146       final Object lastPathComponent = path.getLastPathComponent();
147       if (lastPathComponent instanceof DefaultMutableTreeNode) {
148         final DefaultMutableTreeNode node = (DefaultMutableTreeNode)lastPathComponent;
149         HierarchyNodeDescriptor descriptor = getDescriptor(node);
150         if (descriptor != null) {
151           list.add(descriptor);
152         }
153       }
154     }
155     return list.toArray(new HierarchyNodeDescriptor[list.size()]);
156   }
157
158   private PsiElement[] getSelectedElements() {
159     HierarchyNodeDescriptor[] descriptors = getSelectedDescriptors();
160     ArrayList<PsiElement> elements = new ArrayList<PsiElement>();
161     for (HierarchyNodeDescriptor descriptor : descriptors) {
162       PsiElement element = getElementFromDescriptor(descriptor);
163       if (element != null) elements.add(element);
164     }
165     return PsiUtilBase.toPsiElementArray(elements);
166   }
167
168
169   private Navigatable[] getNavigatables() {
170     final HierarchyNodeDescriptor[] selectedDescriptors = getSelectedDescriptors();
171     if (selectedDescriptors == null || selectedDescriptors.length == 0) return null;
172     final ArrayList<Navigatable> result = new ArrayList<Navigatable>();
173     for (HierarchyNodeDescriptor descriptor : selectedDescriptors) {
174       Navigatable navigatable = getNavigatable(descriptor);
175       if (navigatable != null) {
176         result.add(navigatable);
177       }
178     }
179     return result.toArray(new Navigatable[result.size()]);
180   }
181
182   private Navigatable getNavigatable(HierarchyNodeDescriptor descriptor) {
183     if (descriptor instanceof Navigatable && descriptor.isValid()) {
184       return (Navigatable)descriptor;
185     }
186
187     PsiElement element = getElementFromDescriptor(descriptor);
188     if (element instanceof NavigatablePsiElement && element.isValid()) {
189       return (NavigatablePsiElement)element;
190     }
191     return null;
192   }
193
194   @Nullable
195   public Object getData(@NonNls final String dataId) {
196       if (LangDataKeys.PSI_ELEMENT.is(dataId)) {
197       final PsiElement anElement = getSelectedElement();
198       return anElement != null && anElement.isValid() ? anElement : super.getData(dataId);
199     }
200     if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
201       return getSelectedElements();
202     }
203     if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
204       return null;
205     }
206     if (PlatformDataKeys.NAVIGATABLE.is(dataId)) {
207       final DefaultMutableTreeNode selectedNode = getSelectedNode();
208       if (selectedNode == null) return null;
209       final HierarchyNodeDescriptor descriptor = getDescriptor(selectedNode);
210       if (descriptor == null) return null;
211       return getNavigatable(descriptor);
212     }
213     if (PlatformDataKeys.NAVIGATABLE_ARRAY.is(dataId)) {
214       return getNavigatables();
215     }
216     return super.getData(dataId);
217   }
218
219   private final class CloseAction extends CloseTabToolbarAction {
220     public final void actionPerformed(final AnActionEvent e) {
221       final HierarchyTreeBuilder builder = getCurrentBuilder();
222       final AbstractTreeUi treeUi = builder != null ? builder.getUi() : null;
223       final ProgressIndicator progress = treeUi != null ? treeUi.getProgress() : null;
224       if (progress != null) {
225         progress.cancel();
226       }
227       myContent.getManager().removeContent(myContent, true);
228     }
229   }
230
231   protected void configureTree(Tree tree) {
232     tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
233     tree.setToggleClickCount(-1);
234     tree.setCellRenderer(new HierarchyNodeRenderer());
235     UIUtil.setLineStyleAngled(tree);
236     new TreeSpeedSearch(tree);
237     TreeUtil.installActions(tree);
238     myAutoScrollToSourceHandler.install(tree);
239   }
240
241 }