IDEADEV-39951
[fedora-idea.git] / source / com / intellij / slicer / SlicePanel.java
blobc372d8e34738a2f2714c8efd9288b0b997137db7
1 package com.intellij.slicer;
3 import com.intellij.analysis.AnalysisScope;
4 import com.intellij.ide.IdeBundle;
5 import com.intellij.ide.actions.CloseTabToolbarAction;
6 import com.intellij.ide.util.treeView.AbstractTreeNode;
7 import com.intellij.openapi.Disposable;
8 import com.intellij.openapi.actionSystem.*;
9 import com.intellij.openapi.application.ApplicationManager;
10 import com.intellij.openapi.project.Project;
11 import com.intellij.openapi.ui.Splitter;
12 import com.intellij.openapi.util.Disposer;
13 import com.intellij.openapi.util.IconLoader;
14 import com.intellij.pom.Navigatable;
15 import com.intellij.ui.AutoScrollToSourceHandler;
16 import com.intellij.ui.ScrollPaneFactory;
17 import com.intellij.ui.TreeSpeedSearch;
18 import com.intellij.ui.TreeToolTipHandler;
19 import com.intellij.ui.treeStructure.Tree;
20 import com.intellij.usageView.UsageInfo;
21 import com.intellij.usageView.UsageViewBundle;
22 import com.intellij.usages.Usage;
23 import com.intellij.usages.UsageViewSettings;
24 import com.intellij.usages.impl.UsagePreviewPanel;
25 import com.intellij.util.EditSourceOnDoubleClickHandler;
26 import com.intellij.util.ui.UIUtil;
27 import com.intellij.util.ui.tree.TreeUtil;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.TestOnly;
31 import javax.swing.*;
32 import javax.swing.event.TreeSelectionEvent;
33 import javax.swing.event.TreeSelectionListener;
34 import javax.swing.tree.DefaultMutableTreeNode;
35 import javax.swing.tree.DefaultTreeModel;
36 import javax.swing.tree.TreePath;
37 import javax.swing.tree.TreeSelectionModel;
38 import java.awt.*;
39 import java.awt.event.KeyAdapter;
40 import java.awt.event.KeyEvent;
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.List;
45 /**
46 * @author cdr
48 public abstract class SlicePanel extends JPanel implements TypeSafeDataProvider, Disposable {
49 private final SliceTreeBuilder myBuilder;
50 private final JTree myTree;
52 private final AutoScrollToSourceHandler myAutoScrollToSourceHandler = new AutoScrollToSourceHandler() {
53 protected boolean isAutoScrollMode() {
54 return isAutoScroll();
57 protected void setAutoScrollMode(final boolean state) {
58 setAutoScroll(state);
61 private UsagePreviewPanel myUsagePreviewPanel;
62 private final Project myProject;
63 private boolean isDisposed;
65 public SlicePanel(Project project, final SliceUsage root, AnalysisScope scope, boolean dataFlowToThis) {
66 super(new BorderLayout());
67 myProject = project;
68 myTree = createTree();
70 DuplicateMap targetEqualUsages = new DuplicateMap();
72 final SliceTreeBuilder[] builder = {null};
73 final SliceNode rootNode = new SliceRootNode(project, targetEqualUsages, scope, root){
74 @Override
75 protected SliceTreeBuilder getTreeBuilder() {
76 return builder[0];
80 builder[0] = new SliceTreeBuilder(myTree, project, dataFlowToThis, rootNode,targetEqualUsages);
81 builder[0].setCanYieldUpdate(!ApplicationManager.getApplication().isUnitTestMode());
83 Disposer.register(this, builder[0]);
85 builder[0].addSubtreeToUpdate((DefaultMutableTreeNode)myTree.getModel().getRoot(), new Runnable() {
86 public void run() {
87 if (isDisposed || builder[0].isDisposed() || myProject.isDisposed()) return;
88 builder[0].expand(rootNode, new Runnable() {
89 public void run() {
90 if (isDisposed || builder[0].isDisposed() || myProject.isDisposed()) return;
91 builder[0].select(rootNode.myCachedChildren.get(0)); //first there is ony one child
93 });
94 treeSelectionChanged();
96 });
97 myBuilder = builder[0];
99 layoutPanel();
102 private void layoutPanel() {
103 if (myUsagePreviewPanel != null) {
104 Disposer.dispose(myUsagePreviewPanel);
106 removeAll();
107 if (isPreview()) {
108 Splitter splitter = new Splitter(false, UsageViewSettings.getInstance().PREVIEW_USAGES_SPLITTER_PROPORTIONS);
109 splitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myTree));
110 myUsagePreviewPanel = new UsagePreviewPanel(myProject);
111 Disposer.register(this, myUsagePreviewPanel);
112 splitter.setSecondComponent(myUsagePreviewPanel);
113 add(splitter, BorderLayout.CENTER);
115 else {
116 add(ScrollPaneFactory.createScrollPane(myTree), BorderLayout.CENTER);
119 add(createToolbar().getComponent(), BorderLayout.WEST);
121 revalidate();
124 public void dispose() {
125 if (myUsagePreviewPanel != null) {
126 UsageViewSettings.getInstance().PREVIEW_USAGES_SPLITTER_PROPORTIONS = ((Splitter)myUsagePreviewPanel.getParent()).getProportion();
127 myUsagePreviewPanel = null;
130 isDisposed = true;
131 ToolTipManager.sharedInstance().unregisterComponent(myTree);
134 private JTree createTree() {
135 DefaultMutableTreeNode root = new DefaultMutableTreeNode();
136 final JTree tree = new Tree(new DefaultTreeModel(root)){
137 protected void paintComponent(Graphics g) {
138 DuplicateNodeRenderer.paintDuplicateNodesBackground(g, this);
139 super.paintComponent(g);
142 tree.setOpaque(false);
144 tree.setToggleClickCount(-1);
145 SliceUsageCellRenderer renderer = new SliceUsageCellRenderer();
146 renderer.setOpaque(false);
147 tree.setCellRenderer(renderer);
148 UIUtil.setLineStyleAngled(tree);
149 tree.setRootVisible(false);
151 tree.setShowsRootHandles(true);
152 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
153 tree.setSelectionPath(new TreePath(root.getPath()));
154 //ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_METHOD_HIERARCHY_POPUP);
155 //PopupHandler.installPopupHandler(tree, group, ActionPlaces.METHOD_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
156 EditSourceOnDoubleClickHandler.install(tree);
158 new TreeSpeedSearch(tree);
159 TreeUtil.installActions(tree);
160 TreeToolTipHandler.install(tree);
161 ToolTipManager.sharedInstance().registerComponent(tree);
163 myAutoScrollToSourceHandler.install(tree);
165 tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
166 public void valueChanged(final TreeSelectionEvent e) {
167 treeSelectionChanged();
171 tree.addKeyListener(new KeyAdapter() {
172 public void keyPressed(KeyEvent e) {
173 if (KeyEvent.VK_ENTER == e.getKeyCode()) {
174 List<Navigatable> navigatables = getNavigatables();
175 if (navigatables.isEmpty()) return;
176 for (Navigatable navigatable : navigatables) {
177 if (navigatable instanceof AbstractTreeNode && ((AbstractTreeNode)navigatable).getValue() instanceof Usage) {
178 navigatable = (Usage)((AbstractTreeNode)navigatable).getValue();
180 if (navigatable.canNavigateToSource()) {
181 navigatable.navigate(false);
182 if (navigatable instanceof Usage) {
183 ((Usage)navigatable).highlightInEditor();
187 e.consume();
192 return tree;
195 private void treeSelectionChanged() {
196 SwingUtilities.invokeLater(new Runnable() {
197 public void run() {
198 if (isDisposed) return;
199 List<UsageInfo> infos = getSelectedUsageInfos();
200 if (infos != null && myUsagePreviewPanel != null) {
201 myUsagePreviewPanel.updateLayout(infos);
207 private List<UsageInfo> getSelectedUsageInfos() {
208 TreePath[] paths = myTree.getSelectionPaths();
209 if (paths == null) return null;
210 final ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
211 for (TreePath path : paths) {
212 Object lastPathComponent = path.getLastPathComponent();
213 if (lastPathComponent instanceof DefaultMutableTreeNode) {
214 DefaultMutableTreeNode node = (DefaultMutableTreeNode)lastPathComponent;
215 Object userObject = node.getUserObject();
216 if (userObject instanceof SliceNode) {
217 result.add(((SliceNode)userObject).getValue().getUsageInfo());
221 if (result.isEmpty()) return null;
222 return result;
225 public void calcData(DataKey key, DataSink sink) {
226 if (key == PlatformDataKeys.NAVIGATABLE_ARRAY) {
227 List<Navigatable> navigatables = getNavigatables();
228 if (!navigatables.isEmpty()) {
229 sink.put(PlatformDataKeys.NAVIGATABLE_ARRAY, navigatables.toArray(new Navigatable[navigatables.size()]));
234 @NotNull
235 private List<Navigatable> getNavigatables() {
236 TreePath[] paths = myTree.getSelectionPaths();
237 if (paths == null) return Collections.emptyList();
238 final ArrayList<Navigatable> navigatables = new ArrayList<Navigatable>();
239 for (TreePath path : paths) {
240 Object lastPathComponent = path.getLastPathComponent();
241 if (lastPathComponent instanceof DefaultMutableTreeNode) {
242 DefaultMutableTreeNode node = (DefaultMutableTreeNode)lastPathComponent;
243 Object userObject = node.getUserObject();
244 if (userObject instanceof Navigatable) {
245 navigatables.add((Navigatable)userObject);
247 else if (node instanceof Navigatable) {
248 navigatables.add((Navigatable)node);
252 return navigatables;
255 private ActionToolbar createToolbar() {
256 final DefaultActionGroup actionGroup = new DefaultActionGroup();
257 actionGroup.add(new RefreshAction(myTree));
258 actionGroup.add(myAutoScrollToSourceHandler.createToggleAction());
259 actionGroup.add(new CloseAction());
260 actionGroup.add(new ToggleAction(UsageViewBundle.message("preview.usages.action.text"), "preview", IconLoader.getIcon("/actions/preview.png")) {
261 public boolean isSelected(AnActionEvent e) {
262 return isPreview();
265 public void setSelected(AnActionEvent e, boolean state) {
266 setPreview(state);
267 layoutPanel();
271 if (myBuilder.dataFlowToThis) {
272 actionGroup.add(new AnalyzeLeavesAction(myBuilder));
275 //actionGroup.add(new ContextHelpAction(HELP_ID));
277 return ActionManager.getInstance().createActionToolbar(ActionPlaces.TYPE_HIERARCHY_VIEW_TOOLBAR, actionGroup, false);
280 public abstract boolean isAutoScroll();
282 public abstract void setAutoScroll(boolean autoScroll);
284 public abstract boolean isPreview();
286 public abstract void setPreview(boolean preview);
288 private class CloseAction extends CloseTabToolbarAction {
289 public final void actionPerformed(final AnActionEvent e) {
290 close();
294 protected abstract void close();
296 private final class RefreshAction extends com.intellij.ide.actions.RefreshAction {
297 private RefreshAction(JComponent tree) {
298 super(IdeBundle.message("action.refresh"), IdeBundle.message("action.refresh"), IconLoader.getIcon("/actions/sync.png"));
299 registerShortcutOn(tree);
302 public final void actionPerformed(final AnActionEvent e) {
303 SliceNode rootNode = (SliceNode)myBuilder.getRootNode().getUserObject();
304 rootNode.setChanged();
305 myBuilder.addSubtreeToUpdate(myBuilder.getRootNode());
308 public final void update(final AnActionEvent event) {
309 final Presentation presentation = event.getPresentation();
310 presentation.setEnabled(true);
314 @TestOnly
315 public SliceTreeBuilder getBuilder() {
316 return myBuilder;