IDEA-56769 Don't show preview on changing Groovy constructor signature if not...
[idea/community.git] / platform / platform-api / src / com / intellij / ide / util / treeView / AbstractTreeBuilder.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.util.treeView;
18
19 import com.intellij.ide.projectView.PresentationData;
20 import com.intellij.openapi.Disposable;
21 import com.intellij.openapi.application.Application;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.progress.ProgressIndicator;
24 import com.intellij.openapi.progress.Progressive;
25 import com.intellij.openapi.util.ActionCallback;
26 import com.intellij.openapi.util.AsyncResult;
27 import com.intellij.util.containers.HashSet;
28 import com.intellij.util.ui.UIUtil;
29 import com.intellij.util.ui.update.MergingUpdateQueue;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
32
33 import javax.swing.*;
34 import javax.swing.tree.DefaultMutableTreeNode;
35 import javax.swing.tree.DefaultTreeModel;
36 import javax.swing.tree.TreeNode;
37 import javax.swing.tree.TreePath;
38 import java.lang.ref.WeakReference;
39 import java.util.*;
40
41 public class AbstractTreeBuilder implements Disposable {
42   private AbstractTreeUi myUi;
43   private static final String TREE_BUILDER = "TreeBuilder";
44   public static final boolean DEFAULT_UPDATE_INACTIVE = true;
45
46   public AbstractTreeBuilder(JTree tree,
47                              DefaultTreeModel treeModel,
48                              AbstractTreeStructure treeStructure,
49                              @Nullable Comparator<NodeDescriptor> comparator) {
50     this(tree, treeModel, treeStructure, comparator, DEFAULT_UPDATE_INACTIVE);
51   }
52   public AbstractTreeBuilder(JTree tree,
53                              DefaultTreeModel treeModel,
54                              AbstractTreeStructure treeStructure,
55                              @Nullable Comparator<NodeDescriptor> comparator,
56                              boolean updateIfInactive) {
57     init(tree, treeModel, treeStructure, comparator, updateIfInactive);
58   }
59
60   protected AbstractTreeBuilder() {
61
62   }
63
64
65   protected void init(final JTree tree, final DefaultTreeModel treeModel, final AbstractTreeStructure treeStructure, final @Nullable Comparator<NodeDescriptor> comparator,
66                       final boolean updateIfInactive) {
67
68     tree.putClientProperty(TREE_BUILDER, new WeakReference(this));
69
70     myUi = createUi();
71     getUi().init(this, tree, treeModel, treeStructure, comparator, updateIfInactive);
72
73     setPassthroughMode(isUnitTestingMode());
74   }
75
76   protected AbstractTreeUi createUi() {
77     return new AbstractTreeUi();
78   }
79
80   public final void select(final Object element) {
81     getUi().userSelect(new Object[] {element}, null, false, true);
82   }
83
84   public final void select(final Object element, @Nullable final Runnable onDone) {
85     getUi().userSelect(new Object[] {element}, onDone, false, true);
86   }
87
88   public final void select(final Object element, @Nullable final Runnable onDone, boolean addToSelection) {
89     getUi().userSelect(new Object[] {element}, onDone, addToSelection, true);
90   }
91
92   public final void select(final Object[] elements, @Nullable final Runnable onDone) {
93     getUi().userSelect(elements, onDone, false, true);
94   }
95
96   public final void select(final Object[] elements, @Nullable final Runnable onDone, boolean addToSelection) {
97     getUi().userSelect(elements, onDone, addToSelection, true);
98   }
99
100   public final void expand(Object element, @Nullable Runnable onDone) {
101     getUi().expand(element, onDone);
102   }
103
104   public final void expand(Object[] element, @Nullable Runnable onDone) {
105     getUi().expand(element, onDone);
106   }
107
108   public final void collapseChildren(Object element, @Nullable Runnable onDone) {
109     getUi().collapseChildren(element, onDone);
110   }
111
112
113   protected AbstractTreeNode createSearchingTreeNodeWrapper() {
114     return new AbstractTreeNodeWrapper();
115   }
116
117   public final AbstractTreeBuilder setClearOnHideDelay(final long clearOnHideDelay) {
118     getUi().setClearOnHideDelay(clearOnHideDelay);
119     return this;
120   }
121
122   protected AbstractTreeUpdater createUpdater() {
123     AbstractTreeUpdater updater = new AbstractTreeUpdater(this);
124     updater.setModalityStateComponent(MergingUpdateQueue.ANY_COMPONENT);
125     return updater;
126   }
127
128   protected final AbstractTreeUpdater getUpdater() {
129     return getUi().getUpdater();
130   }
131
132   public final boolean addSubtreeToUpdateByElement(Object element) {
133     return getUpdater().addSubtreeToUpdateByElement(element);
134   }
135
136   public final void addSubtreeToUpdate(DefaultMutableTreeNode node) {
137     getUi().addSubtreeToUpdate(node);
138   }
139
140   public final void addSubtreeToUpdate(DefaultMutableTreeNode node, Runnable afterUpdate) {
141     getUi().addSubtreeToUpdate(node, afterUpdate);
142   }
143
144   public final DefaultMutableTreeNode getRootNode() {
145     return getUi().getRootNode();
146   }
147
148   public final void setNodeDescriptorComparator(Comparator<NodeDescriptor> nodeDescriptorComparator) {
149     getUi().setNodeDescriptorComparator(nodeDescriptorComparator);
150   }
151
152   /**
153   * node descriptor getElement contract is as follows:
154   * 1.TreeStructure always returns & recieves "treestructure" element returned by getTreeStructureElement
155   * 2.Paths contain "model" element returned by getElement
156   */
157
158   protected Object getTreeStructureElement(NodeDescriptor nodeDescriptor) {
159     return nodeDescriptor.getElement();
160   }
161
162
163   protected void updateNode(final DefaultMutableTreeNode node) {
164     getUi().doUpdateNode(node);
165   }
166
167   protected boolean validateNode(final Object child) {
168     return true;
169   }
170
171   protected boolean isDisposeOnCollapsing(NodeDescriptor nodeDescriptor) {
172     return true;
173   }
174
175   public final JTree getTree() {
176     return getUi().getTree();
177   }
178
179   public final AbstractTreeStructure getTreeStructure() {
180     return getUi().getTreeStructure();
181   }
182
183   public final void setTreeStructure(final AbstractTreeStructure structure) {
184     getUi().setTreeStructure(structure);
185   }
186
187   /**
188    * @deprecated
189    * @see #queueUpdateFrom
190    */
191   public void updateFromRoot() {
192     queueUpdate();
193   }
194
195   /**
196    * @deprecated
197    * @see #queueUpdateFrom
198    */
199   protected ActionCallback updateFromRootCB() {
200    return queueUpdate();
201   }
202
203   public void initRootNode() {
204     getUi().initRootNode();
205   }
206
207   public final ActionCallback queueUpdate() {
208     return queueUpdateFrom(getTreeStructure().getRootElement(), true);
209   }
210
211   public final ActionCallback queueUpdateFrom(final Object element, final boolean forceResort) {
212     if (forceResort) {
213       getUi().incComparatorStamp();
214     }
215
216     return getUi().queueUpdate(element);
217   }
218
219   /**
220    * @deprecated
221    * @param element
222    */
223   public void buildNodeForElement(Object element) {
224     getUi().buildNodeForElement(element);
225   }
226
227   /**
228    * @deprecated
229    * @param element
230    * @return
231    */
232   @Nullable
233   public DefaultMutableTreeNode getNodeForElement(Object element) {
234     return getUi().getNodeForElement(element, false);
235   }
236
237   public void cleanUp() {
238     getUi().doCleanUp();
239   }
240
241   @Nullable
242   protected ProgressIndicator createProgressIndicator() {
243     return null;
244   }
245
246   protected void expandNodeChildren(final DefaultMutableTreeNode node) {
247     getUi().doExpandNodeChildren(node);
248   }
249
250   protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor) {
251     return getTreeStructure().getRootElement() == getTreeStructureElement(nodeDescriptor);
252   }
253
254   protected boolean isAlwaysShowPlus(final NodeDescriptor descriptor) {
255     return false;
256   }
257
258
259
260   protected boolean isSmartExpand() {
261     return true;
262   }
263
264   public final boolean isDisposed() {
265     return getUi() == null || getUi().isReleaseRequested();
266   }
267
268   /**
269    * @deprecated
270    * @param node
271    */
272   public final void updateSubtree(final DefaultMutableTreeNode node) {
273     getUi().updateSubtree(node, true);
274   }
275
276   public final boolean wasRootNodeInitialized() {
277     return getUi().wasRootNodeInitialized();
278   }
279
280   public final boolean isNodeBeingBuilt(final TreePath path) {
281     return getUi().isNodeBeingBuilt(path);
282   }
283
284   /**
285    * @deprecated
286    * @param path
287    */
288   public final void buildNodeForPath(final Object[] path) {
289     getUi().buildNodeForPath(path);
290   }
291
292   /**
293    * @deprecated
294    */
295   public final DefaultMutableTreeNode getNodeForPath(final Object[] path) {
296     return getUi().getNodeForPath(path);
297   }
298
299   protected Object findNodeByElement(final Object element) {
300     return getUi().findNodeByElement(element);
301   }
302
303   public static boolean isLoadingNode(final DefaultMutableTreeNode node) {
304     return AbstractTreeUi.isLoadingNode(node);
305   }
306
307   public boolean isChildrenResortingNeeded(NodeDescriptor descriptor) {
308     return true;
309   }
310
311   protected void runOnYeildingDone(Runnable onDone) {
312     if (myUi.isPassthroughMode()) {
313       onDone.run();
314     } else {
315       UIUtil.invokeLaterIfNeeded(onDone);
316     }
317   }
318
319   protected void yield(Runnable runnable) {
320     if (myUi.isPassthroughMode()) {
321       runnable.run();
322     } else {
323       SwingUtilities.invokeLater(runnable);
324     }
325   }
326
327   public boolean isToYieldUpdateFor(DefaultMutableTreeNode node) {
328     return true;
329   }
330
331   public boolean isToEnsureSelectionOnFocusGained() {
332     return true;
333   }
334
335   protected void runBackgroundLoading(final Runnable runnable) {
336     if (isDisposed()) return;
337     final Application app = ApplicationManager.getApplication();
338     if (app != null) {
339       app.runReadAction(new Runnable() {
340         public void run() {
341           runnable.run();
342         }
343       });
344     } else {
345       runnable.run();
346     }
347   }
348
349   protected void updateAfterLoadedInBackground(Runnable runnable) {
350     if (myUi.isPassthroughMode()) {
351       runnable.run();
352     } else {
353       UIUtil.invokeLaterIfNeeded(runnable);
354     }
355   }
356
357   public final ActionCallback getIntialized() {
358     return myUi.getInitialized();
359   }
360
361   public final ActionCallback getReady(Object requestor) {
362     return myUi.getReady(requestor);
363   }
364
365   protected void sortChildren(Comparator<TreeNode> nodeComparator, DefaultMutableTreeNode node, ArrayList<TreeNode> children) {
366     Collections.sort(children, nodeComparator);
367   }
368
369   public void setPassthroughMode(boolean passthrough) {
370     myUi.setPassthroughMode(passthrough);
371   }
372
373   public void expandAll(@Nullable Runnable onDone) {
374     getUi().expandAll(onDone);
375   }
376
377   public ActionCallback cancelUpdate() {
378     return getUi().cancelUpdate();
379   }
380
381   public ActionCallback batch(Progressive progressive) {
382     return getUi().batch(progressive);
383   }
384
385   public AsyncResult<Object> revalidateElement(Object element) {
386     return getTreeStructure().revalidateElement(element);
387   }
388
389   public static class AbstractTreeNodeWrapper extends AbstractTreeNode<Object> {
390     public AbstractTreeNodeWrapper() {
391       super(null, null);
392     }
393
394     @NotNull
395     public Collection<AbstractTreeNode> getChildren() {
396       return Collections.emptyList();
397     }
398
399     public void update(PresentationData presentation) {
400     }
401   }
402
403   public final AbstractTreeUi getUi() {
404     return myUi;
405   }
406
407   public void dispose() {
408     if (isDisposed()) return;
409
410     myUi.requestRelease();
411   }
412
413   void releaseUi() {
414     myUi = null;
415   }
416
417   protected boolean updateNodeDescriptor(final NodeDescriptor descriptor) {
418     return getUi().doUpdateNodeDescriptor(descriptor);
419   }
420
421   public final DefaultTreeModel getTreeModel() {
422     return (DefaultTreeModel)getTree().getModel();
423   }
424
425   @NotNull
426   public final Set<Object> getSelectedElements() {
427     if (isDisposed()) return Collections.emptySet();
428     return getUi().getSelectedElements();
429   }
430
431   @NotNull
432   public final <T> Set<T> getSelectedElements(Class<T> elementClass) {
433     Set<T> result = new HashSet<T>();
434     for (Object o : getSelectedElements()) {
435       Object each = transformElement(o);
436       if (elementClass.isInstance(each)) {
437         //noinspection unchecked
438         result.add((T) each);
439       }
440     }
441     return result;
442   }
443
444   protected Object transformElement(Object object) {
445     return object;
446   }
447
448   public final void setCanYieldUpdate(boolean yield) {
449     getUi().setCanYield(yield);
450   }
451
452   @Nullable
453   public static AbstractTreeBuilder getBuilderFor(JTree tree) {
454     final WeakReference ref = (WeakReference)tree.getClientProperty(TREE_BUILDER);
455     return ref != null ? (AbstractTreeBuilder)ref.get() : null;
456   }
457
458   @Nullable
459   public final <T> Object accept(Class nodeClass, TreeVisitor<T> visitor) {
460     return accept(nodeClass, getTreeStructure().getRootElement(), visitor);
461   }
462
463   @Nullable
464   private <T> Object accept(Class nodeClass, Object element, TreeVisitor<T> visitor) {
465     if (element == null) return null;
466
467     if (nodeClass.isAssignableFrom(element.getClass())) {
468       if (visitor.visit((T)element)) return element;
469     }
470
471     final Object[] children = getTreeStructure().getChildElements(element);
472     for (Object each : children) {
473       final Object childObject = accept(nodeClass, each, visitor);
474       if (childObject != null) return childObject;
475     }
476
477     return null;
478   }
479
480   public <T> boolean select(Class nodeClass, TreeVisitor<T> visitor, @Nullable Runnable onDone, boolean addToSelection) {
481     final Object element = accept(nodeClass, visitor);
482     if (element != null) {
483       select(element, onDone, addToSelection);
484       return true;
485     }
486
487     return false;
488   }
489
490   public void scrollSelectionToVisible(@Nullable Runnable onDone, boolean shouldBeCentered) {
491     myUi.scrollSelectionToVisible(onDone, shouldBeCentered);
492   }
493
494   protected boolean isUnitTestingMode() {
495     Application app = ApplicationManager.getApplication();
496     return app != null && app.isUnitTestMode();
497   }
498
499   public static boolean isToPaintSelection(JTree tree) {
500     AbstractTreeBuilder builder = getBuilderFor(tree);
501     return builder != null && builder.getUi() != null ? builder.getUi().isToPaintSelection() : true;
502   }
503
504 }