2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 package com
.intellij
.codeInsight
.intention
.impl
.config
;
22 import com
.intellij
.codeInsight
.intention
.IntentionManager
;
23 import com
.intellij
.ide
.CommonActionsManager
;
24 import com
.intellij
.ide
.TreeExpander
;
25 import com
.intellij
.ide
.ui
.search
.SearchUtil
;
26 import com
.intellij
.openapi
.actionSystem
.ActionManager
;
27 import com
.intellij
.openapi
.actionSystem
.ActionPlaces
;
28 import com
.intellij
.openapi
.actionSystem
.ActionToolbar
;
29 import com
.intellij
.openapi
.actionSystem
.DefaultActionGroup
;
30 import com
.intellij
.openapi
.util
.Ref
;
31 import com
.intellij
.packageDependencies
.ui
.TreeExpansionMonitor
;
32 import com
.intellij
.ui
.*;
33 import com
.intellij
.util
.ArrayUtil
;
34 import com
.intellij
.util
.ui
.UIUtil
;
35 import com
.intellij
.util
.ui
.tree
.TreeUtil
;
38 import javax
.swing
.event
.TreeSelectionEvent
;
39 import javax
.swing
.event
.TreeSelectionListener
;
40 import javax
.swing
.tree
.DefaultMutableTreeNode
;
41 import javax
.swing
.tree
.DefaultTreeModel
;
42 import javax
.swing
.tree
.TreePath
;
45 import java
.util
.List
;
47 public abstract class IntentionSettingsTree
{
48 private JComponent myComponent
;
49 private CheckboxTree myTree
;
50 private FilterComponent myFilter
;
51 private JPanel myToolbarPanel
;
53 private final Map
<IntentionActionMetaData
, Boolean
> myIntentionToCheckStatus
= new HashMap
<IntentionActionMetaData
, Boolean
>();
55 protected IntentionSettingsTree() {
59 public JTree
getTree(){
63 public JComponent
getComponent() {
67 private void initTree() {
68 myTree
= new CheckboxTree(new CheckboxTree
.CheckboxTreeCellRenderer(true) {
69 public void customizeCellRenderer(JTree tree
, Object value
, boolean selected
, boolean expanded
, boolean leaf
, int row
, boolean hasFocus
) {
70 CheckedTreeNode node
= (CheckedTreeNode
)value
;
71 SimpleTextAttributes attributes
= node
.getUserObject() instanceof IntentionActionMetaData ? SimpleTextAttributes
.REGULAR_ATTRIBUTES
: SimpleTextAttributes
.REGULAR_BOLD_ATTRIBUTES
;
72 final String text
= getNodeText(node
);
74 SearchUtil
.appendFragments(myFilter
!= null ? myFilter
.getFilter() : null,
76 attributes
.getStyle(),
77 attributes
.getFgColor(),
78 selected ? UIUtil
.getTreeSelectionBackground() : UIUtil
.getTreeTextBackground(),
82 }, new CheckedTreeNode(null));
84 myTree
.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
85 public void valueChanged(TreeSelectionEvent e
) {
86 TreePath path
= e
.getPath();
87 Object userObject
= ((DefaultMutableTreeNode
)path
.getLastPathComponent()).getUserObject();
88 selectionChanged(userObject
);
92 myFilter
= new MyFilterComponent();
93 myComponent
= new JPanel(new BorderLayout());
94 JScrollPane scrollPane
= new JScrollPane(myTree
);
95 myToolbarPanel
= new JPanel(new BorderLayout());
96 myToolbarPanel
.add(createTreeToolbarPanel().getComponent(), BorderLayout
.WEST
);
97 myToolbarPanel
.add(myFilter
, BorderLayout
.CENTER
);
98 myComponent
.add(myToolbarPanel
, BorderLayout
.NORTH
);
99 myComponent
.add(scrollPane
, BorderLayout
.CENTER
);
101 SwingUtilities
.invokeLater(new Runnable() {
103 myTree
.setSelectionRow(0);
109 private ActionToolbar
createTreeToolbarPanel() {
110 final CommonActionsManager actionManager
= CommonActionsManager
.getInstance();
112 TreeExpander treeExpander
= new TreeExpander() {
113 public void expandAll() {
114 TreeUtil
.expandAll(myTree
);
117 public boolean canExpand() {
121 public void collapseAll() {
122 TreeUtil
.collapseAll(myTree
, 3);
125 public boolean canCollapse() {
130 DefaultActionGroup actions
= new DefaultActionGroup();
131 actions
.add(actionManager
.createExpandAllAction(treeExpander
, myTree
));
132 actions
.add(actionManager
.createCollapseAllAction(treeExpander
, myTree
));
134 return ActionManager
.getInstance().createActionToolbar(ActionPlaces
.MAIN_TOOLBAR
, actions
, true);
137 protected abstract void selectionChanged(Object selected
);
138 protected abstract List
<IntentionActionMetaData
> filterModel(String filter
, final boolean force
);
140 public void filter(List
<IntentionActionMetaData
> intentionsToShow
) {
141 refreshCheckStatus((CheckedTreeNode
)myTree
.getModel().getRoot());
142 reset(intentionsToShow
);
146 while (((IntentionManagerImpl
)IntentionManager
.getInstance()).hasActiveRequests()) {
150 catch (InterruptedException ignored
) {
154 reset(IntentionManagerSettings
.getInstance().getMetaData());
157 private void resetCheckStatus() {
158 myIntentionToCheckStatus
.clear();
159 IntentionManagerSettings manager
= IntentionManagerSettings
.getInstance();
160 for (IntentionActionMetaData metaData
: manager
.getMetaData()) {
161 myIntentionToCheckStatus
.put(metaData
, manager
.isEnabled(metaData
));
165 private void reset(List
<IntentionActionMetaData
> intentionsToShow
) {
166 CheckedTreeNode root
= new CheckedTreeNode(null);
167 final DefaultTreeModel treeModel
= (DefaultTreeModel
)myTree
.getModel();
168 intentionsToShow
= sort(intentionsToShow
);
170 for (final IntentionActionMetaData metaData
: intentionsToShow
) {
171 String
[] category
= metaData
.myCategory
;
172 CheckedTreeNode node
= root
;
173 for (final String name
: category
) {
174 CheckedTreeNode child
= findChild(node
, name
);
176 CheckedTreeNode newChild
= new CheckedTreeNode(name
);
177 treeModel
.insertNodeInto(newChild
, node
, node
.getChildCount());
182 CheckedTreeNode newChild
= new CheckedTreeNode(metaData
);
183 treeModel
.insertNodeInto(newChild
, node
, node
.getChildCount());
185 resetCheckMark(root
);
186 treeModel
.setRoot(root
);
187 treeModel
.nodeChanged(root
);
190 private static List
<IntentionActionMetaData
> sort(final List
<IntentionActionMetaData
> intentionsToShow
) {
191 List
<IntentionActionMetaData
> copy
= new ArrayList
<IntentionActionMetaData
>(intentionsToShow
);
192 Collections
.sort(copy
, new Comparator
<IntentionActionMetaData
>() {
193 public int compare(final IntentionActionMetaData data1
, final IntentionActionMetaData data2
) {
194 String
[] category1
= data1
.myCategory
;
195 String
[] category2
= data2
.myCategory
;
196 int result
= ArrayUtil
.lexicographicCompare(category1
, category2
);
200 return data1
.getFamily().compareTo(data2
.getFamily());
206 private CheckedTreeNode
getRoot() {
207 return (CheckedTreeNode
)myTree
.getModel().getRoot();
210 private boolean resetCheckMark(final CheckedTreeNode root
) {
211 Object userObject
= root
.getUserObject();
212 if (userObject
instanceof IntentionActionMetaData
) {
213 IntentionActionMetaData metaData
= (IntentionActionMetaData
)userObject
;
214 Boolean b
= myIntentionToCheckStatus
.get(metaData
);
215 boolean enabled
= b
== null ?
false : b
.booleanValue();
216 root
.setChecked(enabled
);
220 root
.setChecked(false);
221 visitChildren(root
, new CheckedNodeVisitor() {
222 public void visit(CheckedTreeNode node
) {
223 if (resetCheckMark(node
)) {
224 root
.setChecked(true);
228 return root
.isChecked();
232 private static CheckedTreeNode
findChild(CheckedTreeNode node
, final String name
) {
233 final Ref
<CheckedTreeNode
> found
= new Ref
<CheckedTreeNode
>();
234 visitChildren(node
, new CheckedNodeVisitor() {
235 public void visit(CheckedTreeNode node
) {
236 String text
= getNodeText(node
);
237 if (name
.equals(text
)) {
245 private static String
getNodeText(CheckedTreeNode node
) {
246 final Object userObject
= node
.getUserObject();
248 if (userObject
instanceof String
) {
249 text
= (String
)userObject
;
251 else if (userObject
instanceof IntentionActionMetaData
) {
252 text
= ((IntentionActionMetaData
)userObject
).getFamily();
260 public void apply() {
261 CheckedTreeNode root
= getRoot();
265 private void refreshCheckStatus(final CheckedTreeNode root
) {
266 Object userObject
= root
.getUserObject();
267 if (userObject
instanceof IntentionActionMetaData
) {
268 IntentionActionMetaData actionMetaData
= (IntentionActionMetaData
)userObject
;
269 myIntentionToCheckStatus
.put(actionMetaData
, root
.isChecked());
272 visitChildren(root
, new CheckedNodeVisitor() {
273 public void visit(CheckedTreeNode node
) {
274 refreshCheckStatus(node
);
281 private static void apply(CheckedTreeNode root
) {
282 Object userObject
= root
.getUserObject();
283 if (userObject
instanceof IntentionActionMetaData
) {
284 IntentionActionMetaData actionMetaData
= (IntentionActionMetaData
)userObject
;
285 IntentionManagerSettings
.getInstance().setEnabled(actionMetaData
, root
.isChecked());
288 visitChildren(root
, new CheckedNodeVisitor() {
289 public void visit(CheckedTreeNode node
) {
296 public boolean isModified() {
297 return isModified(getRoot());
300 private static boolean isModified(CheckedTreeNode root
) {
301 Object userObject
= root
.getUserObject();
302 if (userObject
instanceof IntentionActionMetaData
) {
303 IntentionActionMetaData actionMetaData
= (IntentionActionMetaData
)userObject
;
304 boolean enabled
= IntentionManagerSettings
.getInstance().isEnabled(actionMetaData
);
305 return enabled
!= root
.isChecked();
308 final boolean[] modified
= new boolean[] { false };
309 visitChildren(root
, new CheckedNodeVisitor() {
310 public void visit(CheckedTreeNode node
) {
311 modified
[0] |= isModified(node
);
318 public void dispose() {
322 public void setFilter(String filter
){
323 myFilter
.setFilter(filter
);
326 public String
getFilter() {
327 return myFilter
.getFilter();
330 interface CheckedNodeVisitor
{
331 void visit(CheckedTreeNode node
);
333 private static void visitChildren(CheckedTreeNode node
, CheckedNodeVisitor visitor
) {
334 Enumeration children
= node
.children();
335 while (children
.hasMoreElements()) {
336 final CheckedTreeNode child
= (CheckedTreeNode
)children
.nextElement();
337 visitor
.visit(child
);
341 private class MyFilterComponent
extends FilterComponent
{
342 private final TreeExpansionMonitor
<DefaultMutableTreeNode
> myExpansionMonitor
= TreeExpansionMonitor
.install(myTree
);
344 public MyFilterComponent() {
345 super("INTENTION_FILTER_HISTORY", 10);
348 public void filter() {
349 final String filter
= getFilter();
350 if (filter
!= null && filter
.length() > 0) {
351 if (!myExpansionMonitor
.isFreeze()) {
352 myExpansionMonitor
.freeze();
355 IntentionSettingsTree
.this.filter(filterModel(filter
, true));
356 if (myTree
!= null) {
357 List
<TreePath
> expandedPaths
= TreeUtil
.collectExpandedPaths(myTree
);
358 ((DefaultTreeModel
)myTree
.getModel()).reload();
359 TreeUtil
.restoreExpandedPaths(myTree
, expandedPaths
);
361 SwingUtilities
.invokeLater(new Runnable() {
363 myTree
.setSelectionRow(0);
364 myTree
.requestFocus();
367 TreeUtil
.expandAll(myTree
);
368 if (filter
== null || filter
.length() == 0) {
369 TreeUtil
.collapseAll(myTree
, 0);
370 myExpansionMonitor
.restore();
374 protected void onlineFilter() {
375 final String filter
= getFilter();
376 if (filter
!= null && filter
.length() > 0) {
377 if (!myExpansionMonitor
.isFreeze()) {
378 myExpansionMonitor
.freeze();
381 IntentionSettingsTree
.this.filter(filterModel(filter
, true));
382 TreeUtil
.expandAll(myTree
);
383 if (filter
== null || filter
.length() == 0) {
384 TreeUtil
.collapseAll(myTree
, 0);
385 myExpansionMonitor
.restore();
390 public JPanel
getToolbarPanel() {
391 return myToolbarPanel
;