TreeUi: initial selection (on maybeReady handler)
[fedora-idea.git] / platform / platform-api / src / com / intellij / ide / util / treeView / AbstractTreeUpdater.java
blob820e8b44383702f190fe64be07864a76f9e6c733
1 /*
2 * Copyright 2000-2007 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.openapi.Disposable;
20 import com.intellij.openapi.application.Application;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.progress.ProcessCanceledException;
24 import com.intellij.openapi.util.ActionCallback;
25 import com.intellij.openapi.util.Disposer;
26 import com.intellij.util.ui.UIUtil;
27 import com.intellij.util.ui.update.Activatable;
28 import com.intellij.util.ui.update.MergingUpdateQueue;
29 import com.intellij.util.ui.update.UiNotifyConnector;
30 import com.intellij.util.ui.update.Update;
31 import com.intellij.util.Alarm;
32 import com.intellij.ui.treeStructure.treetable.TreeTableTree;
33 import org.jetbrains.annotations.NotNull;
35 import javax.swing.*;
36 import javax.swing.tree.DefaultMutableTreeNode;
37 import java.util.*;
39 public class AbstractTreeUpdater implements Disposable, Activatable {
40 private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.treeView.AbstractTreeUpdater");
42 private final LinkedList<TreeUpdatePass> myNodeQueue = new LinkedList<TreeUpdatePass>();
43 private final AbstractTreeBuilder myTreeBuilder;
44 private final List<Runnable> myRunAfterUpdate = new ArrayList<Runnable>();
45 private Runnable myRunBeforeUpdate;
46 private final MergingUpdateQueue myUpdateQueue;
48 private long myUpdateCount;
50 public AbstractTreeUpdater(AbstractTreeBuilder treeBuilder) {
51 myTreeBuilder = treeBuilder;
52 final JTree tree = myTreeBuilder.getTree();
53 final JComponent component = tree instanceof TreeTableTree? ((TreeTableTree)tree).getTreeTable() : tree;
54 myUpdateQueue = new MergingUpdateQueue("UpdateQueue", 300, component.isShowing(), component) {
55 @Override
56 protected Alarm createAlarm(Alarm.ThreadToUse thread, Disposable parent) {
57 return new Alarm(thread, parent) {
58 @Override
59 protected boolean isEdt() {
60 return AbstractTreeUpdater.this.isEdt();
65 final UiNotifyConnector uiNotifyConnector = new UiNotifyConnector(component, myUpdateQueue);
66 Disposer.register(this, myUpdateQueue);
67 Disposer.register(this, uiNotifyConnector);
70 /**
71 * @param delay update delay in milliseconds.
73 public void setDelay(int delay) {
74 myUpdateQueue.setMergingTimeSpan(delay);
77 public void setPassThroughMode(boolean passThroughMode) {
78 myUpdateQueue.setPassThrough(passThroughMode);
81 public void setModalityStateComponent(JComponent c) {
82 myUpdateQueue.setModalityStateComponent(c);
85 public boolean hasNodesToUpdate() {
86 return myNodeQueue.size() > 0 || !myUpdateQueue.isEmpty();
89 public void dispose() {
92 public synchronized void addSubtreeToUpdate(@NotNull DefaultMutableTreeNode rootNode) {
93 addSubtreeToUpdate(new TreeUpdatePass(rootNode).setUpdateStamp(-1));
96 public synchronized void addSubtreeToUpdate(@NotNull TreeUpdatePass toAdd) {
97 if (LOG.isDebugEnabled()) {
98 LOG.debug("addSubtreeToUpdate:" + toAdd.getNode());
102 assert !toAdd.isExpired();
104 for (Iterator<TreeUpdatePass> iterator = myNodeQueue.iterator(); iterator.hasNext();) {
105 final TreeUpdatePass passInQueue = iterator.next();
108 if (passInQueue == toAdd) {
109 return;
110 } else if (passInQueue.getNode() == toAdd.getNode()) {
111 toAdd.expire();
112 return;
113 } else if (toAdd.getNode().isNodeAncestor(passInQueue.getNode())) {
114 toAdd.expire();
115 return;
116 } else if (passInQueue.getNode().isNodeAncestor(toAdd.getNode())) {
117 iterator.remove();
118 passInQueue.expire();
122 long newUpdateCount = toAdd.getUpdateStamp() == -1 ? myUpdateCount : myUpdateCount + 1;
124 final AbstractTreeUi ui = myTreeBuilder.getUi();
125 final Collection<TreeUpdatePass> yielding = ui.getYeildingPasses();
126 for (Iterator<TreeUpdatePass> iterator = yielding.iterator(); iterator.hasNext();) {
127 TreeUpdatePass eachYielding = iterator.next();
129 final DefaultMutableTreeNode eachNode = eachYielding.getCurrentNode();
130 if (eachNode != null) {
131 if (eachNode.isNodeAncestor(toAdd.getNode())) {
132 toAdd.expire();
133 } else {
134 eachYielding.setUpdateStamp(newUpdateCount);
139 if (toAdd.isExpired()) return;
142 myNodeQueue.add(toAdd);
144 myUpdateCount = newUpdateCount;
145 toAdd.setUpdateStamp(myUpdateCount);
147 queue(new Update("ViewUpdate") {
148 public boolean isExpired() {
149 return myTreeBuilder.isDisposed();
152 public void run() {
153 if (myTreeBuilder.getTreeStructure().hasSomethingToCommit()) {
154 myTreeBuilder.getTreeStructure().commit();
155 queue(this);
156 return;
158 try {
159 performUpdate();
161 catch(ProcessCanceledException e) {
162 throw e;
163 } catch(RuntimeException e) {
164 LOG.error(myTreeBuilder.getClass().getName(), e);
170 private void queue(Update update) {
171 myUpdateQueue.queue(update);
175 * @deprecated use addSubtreeToUpdate instead
176 * @param node
178 protected void updateSubtree(DefaultMutableTreeNode node) {
179 myTreeBuilder.updateSubtree(node);
182 public synchronized void performUpdate() {
183 if (myRunBeforeUpdate != null){
184 myRunBeforeUpdate.run();
185 myRunBeforeUpdate = null;
189 while(!myNodeQueue.isEmpty()){
190 if (isInPostponeMode()) break;
193 final TreeUpdatePass eachPass = myNodeQueue.removeFirst();
195 beforeUpdate(eachPass).doWhenDone(new Runnable() {
196 public void run() {
197 myTreeBuilder.getUi().updateSubtreeNow(eachPass);
203 myTreeBuilder.getUi().maybeReady();
205 if (myRunAfterUpdate != null) {
206 final Runnable runnable = new Runnable() {
207 public void run() {
208 List<Runnable> runAfterUpdate = null;
209 synchronized (myRunAfterUpdate) {
210 if (!myRunAfterUpdate.isEmpty()) {
211 runAfterUpdate = new ArrayList<Runnable>(myRunAfterUpdate);
212 myRunAfterUpdate.clear();
215 if (runAfterUpdate != null) {
216 for (Runnable r : runAfterUpdate) {
217 r.run();
223 invokeLater(runnable);
227 protected void invokeLater(Runnable runnable) {
228 final Application app = ApplicationManager.getApplication();
229 if (app != null) {
230 app.invokeLater(runnable);
231 } else {
232 UIUtil.invokeAndWaitIfNeeded(runnable);
236 protected ActionCallback beforeUpdate(TreeUpdatePass pass) {
237 return new ActionCallback.Done();
240 public boolean addSubtreeToUpdateByElement(Object element) {
241 if (LOG.isDebugEnabled()) {
242 LOG.debug("addSubtreeToUpdateByElement:" + element);
245 DefaultMutableTreeNode node = myTreeBuilder.getNodeForElement(element);
246 if (node != null){
247 addSubtreeToUpdate(node);
248 return true;
250 else{
251 return false;
255 public void cancelAllRequests(){
256 myNodeQueue.clear();
257 myUpdateQueue.cancelAllUpdates();
260 public void runAfterUpdate(final Runnable runnable) {
261 if (runnable == null) return;
262 synchronized (myRunAfterUpdate) {
263 myRunAfterUpdate.add(runnable);
267 public synchronized void runBeforeUpdate(final Runnable runnable) {
268 myRunBeforeUpdate = runnable;
271 public long getUpdateCount() {
272 return myUpdateCount;
275 public boolean isRerunNeededFor(TreeUpdatePass pass) {
276 return pass.getUpdateStamp() < getUpdateCount();
279 public boolean isInPostponeMode() {
280 return !myUpdateQueue.isActive() && !myUpdateQueue.isPassThrough();
283 public void showNotify() {
284 myUpdateQueue.showNotify();
287 public void hideNotify() {
288 myUpdateQueue.hideNotify();
291 protected boolean isEdt() {
292 return Alarm.isEventDispatchThread();
295 @Override
296 public String toString() {
297 return "AbstractTreeUpdater updateCount=" + myUpdateCount + " queue=[" + myUpdateQueue.toString() + "] " + " nodeQueue=" + myNodeQueue;
300 public void flush() {
301 myUpdateQueue.sendFlush();