wait for intentions to load before show dialog
[fedora-idea.git] / platform / lang-impl / src / com / intellij / codeInsight / intention / impl / config / IntentionSettingsTree.java
blob452038a06e3c948c74cb1749ede1f6210667244a
1 /*
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.
17 /**
18 * @author cdr
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;
37 import javax.swing.*;
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;
43 import java.awt.*;
44 import java.util.*;
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() {
56 initTree();
59 public JTree getTree(){
60 return myTree;
63 public JComponent getComponent() {
64 return myComponent;
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);
73 if (text != null) {
74 SearchUtil.appendFragments(myFilter != null ? myFilter.getFilter() : null,
75 text,
76 attributes.getStyle(),
77 attributes.getFgColor(),
78 selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(),
79 getTextRenderer());
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);
90 });
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() {
102 public void run() {
103 myTree.setSelectionRow(0);
106 myFilter.reset();
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() {
118 return true;
121 public void collapseAll() {
122 TreeUtil.collapseAll(myTree, 3);
125 public boolean canCollapse() {
126 return true;
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);
145 public void reset(){
146 while (((IntentionManagerImpl)IntentionManager.getInstance()).hasActiveRequests()) {
147 try {
148 Thread.sleep(100);
150 catch (InterruptedException ignored) {
153 resetCheckStatus();
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);
175 if (child == null) {
176 CheckedTreeNode newChild = new CheckedTreeNode(name);
177 treeModel.insertNodeInto(newChild, node, node.getChildCount());
178 child = newChild;
180 node = child;
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);
197 if (result!= 0) {
198 return result;
200 return data1.getFamily().compareTo(data2.getFamily());
203 return copy;
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);
217 return enabled;
219 else {
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)) {
238 found.set(node);
242 return found.get();
245 private static String getNodeText(CheckedTreeNode node) {
246 final Object userObject = node.getUserObject();
247 String text;
248 if (userObject instanceof String) {
249 text = (String)userObject;
251 else if (userObject instanceof IntentionActionMetaData) {
252 text = ((IntentionActionMetaData)userObject).getFamily();
254 else {
255 text = "???";
257 return text;
260 public void apply() {
261 CheckedTreeNode root = getRoot();
262 apply(root);
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());
271 else {
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());
287 else {
288 visitChildren(root, new CheckedNodeVisitor() {
289 public void visit(CheckedTreeNode node) {
290 apply(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();
307 else {
308 final boolean[] modified = new boolean[] { false };
309 visitChildren(root, new CheckedNodeVisitor() {
310 public void visit(CheckedTreeNode node) {
311 modified[0] |= isModified(node);
314 return modified[0];
318 public void dispose() {
319 myFilter.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() {
362 public void run() {
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;