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