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
;
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
;
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
;
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
) {
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());
68 myTree
= createTree();
70 DuplicateMap targetEqualUsages
= new DuplicateMap();
72 final SliceTreeBuilder
[] builder
= {null};
73 final SliceNode rootNode
= new SliceRootNode(project
, targetEqualUsages
, scope
, root
){
75 protected SliceTreeBuilder
getTreeBuilder() {
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() {
87 if (isDisposed
|| builder
[0].isDisposed() || myProject
.isDisposed()) return;
88 builder
[0].expand(rootNode
, new Runnable() {
90 if (isDisposed
|| builder
[0].isDisposed() || myProject
.isDisposed()) return;
91 builder
[0].select(rootNode
.myCachedChildren
.get(0)); //first there is ony one child
94 treeSelectionChanged();
97 myBuilder
= builder
[0];
102 private void layoutPanel() {
103 if (myUsagePreviewPanel
!= null) {
104 Disposer
.dispose(myUsagePreviewPanel
);
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
);
116 add(ScrollPaneFactory
.createScrollPane(myTree
), BorderLayout
.CENTER
);
119 add(createToolbar().getComponent(), BorderLayout
.WEST
);
124 public void dispose() {
125 if (myUsagePreviewPanel
!= null) {
126 UsageViewSettings
.getInstance().PREVIEW_USAGES_SPLITTER_PROPORTIONS
= ((Splitter
)myUsagePreviewPanel
.getParent()).getProportion();
127 myUsagePreviewPanel
= null;
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();
195 private void treeSelectionChanged() {
196 SwingUtilities
.invokeLater(new Runnable() {
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;
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()]));
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
);
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
) {
265 public void setSelected(AnActionEvent e
, boolean state
) {
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
) {
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);
315 public SliceTreeBuilder
getBuilder() {