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 package com
.intellij
.ide
.util
.treeView
;
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
.util
.ActionCallback
;
25 import com
.intellij
.util
.containers
.HashSet
;
26 import com
.intellij
.util
.ui
.UIUtil
;
27 import com
.intellij
.util
.ui
.update
.MergingUpdateQueue
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
32 import javax
.swing
.tree
.DefaultMutableTreeNode
;
33 import javax
.swing
.tree
.DefaultTreeModel
;
34 import javax
.swing
.tree
.TreeNode
;
35 import javax
.swing
.tree
.TreePath
;
36 import java
.lang
.ref
.WeakReference
;
39 public class AbstractTreeBuilder
implements Disposable
{
40 private AbstractTreeUi myUi
;
41 private static final String TREE_BUILDER
= "TreeBuilder";
42 public static final boolean DEFAULT_UPDATE_INACTIVE
= true;
44 public AbstractTreeBuilder(JTree tree
,
45 DefaultTreeModel treeModel
,
46 AbstractTreeStructure treeStructure
,
47 @Nullable Comparator
<NodeDescriptor
> comparator
) {
48 this(tree
, treeModel
, treeStructure
, comparator
, DEFAULT_UPDATE_INACTIVE
);
50 public AbstractTreeBuilder(JTree tree
,
51 DefaultTreeModel treeModel
,
52 AbstractTreeStructure treeStructure
,
53 @Nullable Comparator
<NodeDescriptor
> comparator
,
54 boolean updateIfInactive
) {
55 init(tree
, treeModel
, treeStructure
, comparator
, updateIfInactive
);
58 protected AbstractTreeBuilder() {
63 protected void init(final JTree tree
, final DefaultTreeModel treeModel
, final AbstractTreeStructure treeStructure
, final @Nullable Comparator
<NodeDescriptor
> comparator
,
64 final boolean updateIfInactive
) {
66 tree
.putClientProperty(TREE_BUILDER
, new WeakReference(this));
69 getUi().init(this, tree
, treeModel
, treeStructure
, comparator
, updateIfInactive
);
71 setPassthroughMode(isUnitTestingMode());
74 protected AbstractTreeUi
createUi() {
75 return new AbstractTreeUi();
78 public final void select(final Object element
) {
79 getUi().userSelect(new Object
[] {element
}, null, false, true);
82 public final void select(final Object element
, @Nullable final Runnable onDone
) {
83 getUi().userSelect(new Object
[] {element
}, onDone
, false, true);
86 public final void select(final Object element
, @Nullable final Runnable onDone
, boolean addToSelection
) {
87 getUi().userSelect(new Object
[] {element
}, onDone
, addToSelection
, true);
90 public final void select(final Object
[] elements
, @Nullable final Runnable onDone
) {
91 getUi().userSelect(elements
, onDone
, false, true);
94 public final void select(final Object
[] elements
, @Nullable final Runnable onDone
, boolean addToSelection
) {
95 getUi().userSelect(elements
, onDone
, addToSelection
, true);
98 public final void expand(Object element
, @Nullable Runnable onDone
) {
99 getUi().expand(element
, onDone
);
102 public final void expand(Object
[] element
, @Nullable Runnable onDone
) {
103 getUi().expand(element
, onDone
);
106 public final void collapseChildren(Object element
, @Nullable Runnable onDone
) {
107 getUi().collapseChildren(element
, onDone
);
111 protected AbstractTreeNode
createSearchingTreeNodeWrapper() {
112 return new AbstractTreeNodeWrapper();
115 public final AbstractTreeBuilder
setClearOnHideDelay(final long clearOnHideDelay
) {
116 getUi().setClearOnHideDelay(clearOnHideDelay
);
120 protected AbstractTreeUpdater
createUpdater() {
121 AbstractTreeUpdater updater
= new AbstractTreeUpdater(this);
122 updater
.setModalityStateComponent(MergingUpdateQueue
.ANY_COMPONENT
);
126 protected final AbstractTreeUpdater
getUpdater() {
127 return getUi().getUpdater();
130 public final boolean addSubtreeToUpdateByElement(Object element
) {
131 return getUpdater().addSubtreeToUpdateByElement(element
);
134 public final void addSubtreeToUpdate(DefaultMutableTreeNode node
) {
135 getUi().addSubtreeToUpdate(node
);
138 public final void addSubtreeToUpdate(DefaultMutableTreeNode node
, Runnable afterUpdate
) {
139 getUi().addSubtreeToUpdate(node
, afterUpdate
);
142 public final DefaultMutableTreeNode
getRootNode() {
143 return getUi().getRootNode();
146 public final void setNodeDescriptorComparator(Comparator
<NodeDescriptor
> nodeDescriptorComparator
) {
147 getUi().setNodeDescriptorComparator(nodeDescriptorComparator
);
151 * node descriptor getElement contract is as follows:
152 * 1.TreeStructure always returns & recieves "treestructure" element returned by getTreeStructureElement
153 * 2.Paths contain "model" element returned by getElement
156 protected Object
getTreeStructureElement(NodeDescriptor nodeDescriptor
) {
157 return nodeDescriptor
.getElement();
161 protected void updateNode(final DefaultMutableTreeNode node
) {
162 getUi().doUpdateNode(node
);
165 protected boolean validateNode(final Object child
) {
169 protected boolean isDisposeOnCollapsing(NodeDescriptor nodeDescriptor
) {
173 public final JTree
getTree() {
174 return getUi().getTree();
177 public final AbstractTreeStructure
getTreeStructure() {
178 return getUi().getTreeStructure();
181 public final void setTreeStructure(final AbstractTreeStructure structure
) {
182 getUi().setTreeStructure(structure
);
187 * @see #queueUpdateFrom
189 public void updateFromRoot() {
195 * @see #queueUpdateFrom
197 protected ActionCallback
updateFromRootCB() {
198 return queueUpdate();
201 public void initRootNode() {
202 getUi().initRootNode();
205 public final ActionCallback
queueUpdate() {
206 return queueUpdateFrom(getTreeStructure().getRootElement(), true);
209 public final ActionCallback
queueUpdateFrom(final Object element
, final boolean forceResort
) {
211 getUi().incComparatorStamp();
214 return getUi().queueUpdate(element
);
221 public void buildNodeForElement(Object element
) {
222 getUi().buildNodeForElement(element
);
231 public DefaultMutableTreeNode
getNodeForElement(Object element
) {
232 return getUi().getNodeForElement(element
, false);
235 public void cleanUp() {
240 protected ProgressIndicator
createProgressIndicator() {
244 protected void expandNodeChildren(final DefaultMutableTreeNode node
) {
245 getUi().doExpandNodeChildren(node
);
248 protected boolean isAutoExpandNode(final NodeDescriptor nodeDescriptor
) {
249 return getTreeStructure().getRootElement() == getTreeStructureElement(nodeDescriptor
);
252 protected boolean isAlwaysShowPlus(final NodeDescriptor descriptor
) {
258 protected boolean isSmartExpand() {
262 public final boolean isDisposed() {
263 return getUi() == null || getUi().isReleaseRequested();
270 public final void updateSubtree(final DefaultMutableTreeNode node
) {
271 getUi().updateSubtree(node
, true);
274 public final boolean wasRootNodeInitialized() {
275 return getUi().wasRootNodeInitialized();
278 public final boolean isNodeBeingBuilt(final TreePath path
) {
279 return getUi().isNodeBeingBuilt(path
);
286 public final void buildNodeForPath(final Object
[] path
) {
287 getUi().buildNodeForPath(path
);
293 public final DefaultMutableTreeNode
getNodeForPath(final Object
[] path
) {
294 return getUi().getNodeForPath(path
);
297 protected Object
findNodeByElement(final Object element
) {
298 return getUi().findNodeByElement(element
);
301 public static boolean isLoadingNode(final DefaultMutableTreeNode node
) {
302 return AbstractTreeUi
.isLoadingNode(node
);
305 public boolean isChildrenResortingNeeded(NodeDescriptor descriptor
) {
309 protected void runOnYeildingDone(Runnable onDone
) {
310 if (myUi
.isPassthroughMode()) {
313 UIUtil
.invokeLaterIfNeeded(onDone
);
317 protected void yield(Runnable runnable
) {
318 if (myUi
.isPassthroughMode()) {
321 SwingUtilities
.invokeLater(runnable
);
325 public boolean isToYieldUpdateFor(DefaultMutableTreeNode node
) {
329 public boolean isToEnsureSelectionOnFocusGained() {
333 protected void runBackgroundLoading(final Runnable runnable
) {
334 if (isDisposed()) return;
335 final Application app
= ApplicationManager
.getApplication();
337 app
.runReadAction(new Runnable() {
347 protected ProgressIndicator
getProgressIndicator() {
348 return getUi().getProgressIndicator();
351 protected void updateAfterLoadedInBackground(Runnable runnable
) {
352 if (myUi
.isPassthroughMode()) {
355 UIUtil
.invokeLaterIfNeeded(runnable
);
359 public final ActionCallback
getIntialized() {
360 return myUi
.getInitialized();
363 public final ActionCallback
getReady(Object requestor
) {
364 return myUi
.getReady(requestor
);
367 protected void sortChildren(Comparator
<TreeNode
> nodeComparator
, DefaultMutableTreeNode node
, ArrayList
<TreeNode
> children
) {
368 Collections
.sort(children
, nodeComparator
);
371 public void setPassthroughMode(boolean passthrough
) {
372 myUi
.setPassthroughMode(passthrough
);
375 public static class AbstractTreeNodeWrapper
extends AbstractTreeNode
<Object
> {
376 public AbstractTreeNodeWrapper() {
381 public Collection
<AbstractTreeNode
> getChildren() {
382 return Collections
.emptyList();
385 public void update(PresentationData presentation
) {
389 public final AbstractTreeUi
getUi() {
393 public void dispose() {
394 if (isDisposed()) return;
396 myUi
.requestRelease();
403 protected boolean updateNodeDescriptor(final NodeDescriptor descriptor
) {
404 return getUi().doUpdateNodeDescriptor(descriptor
);
407 public final DefaultTreeModel
getTreeModel() {
408 return (DefaultTreeModel
)getTree().getModel();
412 public final Set
<Object
> getSelectedElements() {
413 return getUi().getSelectedElements();
417 public final <T
> Set
<T
> getSelectedElements(Class
<T
> elementClass
) {
418 Set
<T
> result
= new HashSet
<T
>();
419 for (Object o
: getSelectedElements()) {
420 Object each
= transformElement(o
);
421 if (elementClass
.isInstance(each
)) {
422 //noinspection unchecked
423 result
.add((T
) each
);
429 protected Object
transformElement(Object object
) {
433 public final void setCanYieldUpdate(boolean yield
) {
434 getUi().setCanYield(yield
);
438 public static AbstractTreeBuilder
getBuilderFor(JTree tree
) {
439 final WeakReference ref
= (WeakReference
)tree
.getClientProperty(TREE_BUILDER
);
440 return ref
!= null ?
(AbstractTreeBuilder
)ref
.get() : null;
444 public final <T
> Object
accept(Class nodeClass
, TreeVisitor
<T
> visitor
) {
445 return accept(nodeClass
, getTreeStructure().getRootElement(), visitor
);
449 private <T
> Object
accept(Class nodeClass
, Object element
, TreeVisitor
<T
> visitor
) {
450 if (element
== null) return null;
452 if (nodeClass
.isAssignableFrom(element
.getClass())) {
453 if (visitor
.visit((T
)element
)) return element
;
456 final Object
[] children
= getTreeStructure().getChildElements(element
);
457 for (Object each
: children
) {
458 final Object childObject
= accept(nodeClass
, each
, visitor
);
459 if (childObject
!= null) return childObject
;
465 public <T
> boolean select(Class nodeClass
, TreeVisitor
<T
> visitor
, @Nullable Runnable onDone
, boolean addToSelection
) {
466 final Object element
= accept(nodeClass
, visitor
);
467 if (element
!= null) {
468 select(element
, onDone
, addToSelection
);
475 public void scrollSelectionToVisible(@Nullable Runnable onDone
, boolean shouldBeCentered
) {
476 myUi
.scrollSelectionToVisible(onDone
, shouldBeCentered
);
479 protected boolean isUnitTestingMode() {
480 Application app
= ApplicationManager
.getApplication();
481 return app
!= null && app
.isUnitTestMode();