From cb5d7002a6e4ea2633546cd97ae2356b0f502211 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Dec 2009 15:42:44 +0300 Subject: [PATCH 1/2] structure view is dumb-aware (IDEADEV-41813) --- .../impl/StructureViewToolWindowFactory.java | 9 ++++--- .../newStructureView/TreeActionWrapper.java | 3 ++- .../ui/AutoScrollFromSourceHandler.java | 25 ++++++++++++------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java b/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java index b3df9aae5674..79bc9b871934 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/impl/StructureViewToolWindowFactory.java @@ -16,15 +16,16 @@ package com.intellij.ide.structureView.impl; -import com.intellij.openapi.wm.ToolWindowFactory; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.project.Project; import com.intellij.ide.structureView.StructureViewFactory; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowFactory; /** * @author yole */ -public class StructureViewToolWindowFactory implements ToolWindowFactory { +public class StructureViewToolWindowFactory implements ToolWindowFactory, DumbAware { public void createToolWindowContent(Project project, ToolWindow toolWindow) { StructureViewFactoryImpl factory = (StructureViewFactoryImpl)StructureViewFactory.getInstance(project); factory.initToolWindow(toolWindow); diff --git a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/TreeActionWrapper.java b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/TreeActionWrapper.java index cca504bd7eb1..fd0d55138f6a 100644 --- a/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/TreeActionWrapper.java +++ b/platform/lang-impl/src/com/intellij/ide/structureView/newStructureView/TreeActionWrapper.java @@ -21,8 +21,9 @@ import com.intellij.ide.util.treeView.smartTree.TreeAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.project.DumbAware; -public class TreeActionWrapper extends ToggleAction{ +public class TreeActionWrapper extends ToggleAction implements DumbAware { private final TreeAction myAction; private final TreeActionsOwner myStructureView; diff --git a/platform/platform-api/src/com/intellij/ui/AutoScrollFromSourceHandler.java b/platform/platform-api/src/com/intellij/ui/AutoScrollFromSourceHandler.java index 2df46b8e3328..e479c489ad3f 100644 --- a/platform/platform-api/src/com/intellij/ui/AutoScrollFromSourceHandler.java +++ b/platform/platform-api/src/com/intellij/ui/AutoScrollFromSourceHandler.java @@ -19,6 +19,7 @@ package com.intellij.ui; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.IconLoader; @@ -42,16 +43,22 @@ public abstract class AutoScrollFromSourceHandler implements Disposable { public abstract void install(); public ToggleAction createToggleAction() { - return new ToggleAction(UIBundle.message("autoscroll.from.source.action.name"), - UIBundle.message("autoscroll.from.source.action.description"), IconLoader.getIcon("/general/autoscrollFromSource.png")) { - public boolean isSelected(AnActionEvent event) { - return isAutoScrollMode(); - } + return new AutoScrollFromSourceAction(); + } - public void setSelected(AnActionEvent event, boolean flag) { - setAutoScrollMode(flag); - } - }; + private class AutoScrollFromSourceAction extends ToggleAction implements DumbAware { + public AutoScrollFromSourceAction() { + super(UIBundle.message("autoscroll.from.source.action.name"), UIBundle.message("autoscroll.from.source.action.description"), + IconLoader.getIcon("/general/autoscrollFromSource.png")); + } + + public boolean isSelected(AnActionEvent event) { + return isAutoScrollMode(); + } + + public void setSelected(AnActionEvent event, boolean flag) { + setAutoScrollMode(flag); + } } } From 9e6b57aaddf9ca52a9d3ff5ab593e266d762827e Mon Sep 17 00:00:00 2001 From: Kirill Kalishev Date: Thu, 3 Dec 2009 15:44:30 +0300 Subject: [PATCH 2/2] TreeUi: correct dispose during building --- .../util/treeView/AbstractTreeBuilder.java | 7 +- .../ide/util/treeView/AbstractTreeUi.java | 139 ++++++++++++------ .../util/treeView/AbstractTreeUpdater.java | 16 +- 3 files changed, 108 insertions(+), 54 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java index f25b77f76091..22a024b18c2d 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeBuilder.java @@ -258,7 +258,7 @@ public class AbstractTreeBuilder implements Disposable { } public final boolean isDisposed() { - return getUi() == null || getUi().isReleased(); + return getUi() == null || getUi().isReleaseRequested(); } /** @@ -386,7 +386,10 @@ public class AbstractTreeBuilder implements Disposable { public void dispose() { if (isDisposed()) return; - myUi.release(); + myUi.requestRelease(); + } + + void releaseUi() { myUi = null; } diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java index e63ec8a1c7e5..893d91942275 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java @@ -110,6 +110,7 @@ public class AbstractTreeUi { private UpdaterTreeState myUpdaterState; private AbstractTreeBuilder myBuilder; + private boolean myReleaseRequested; private final Set myUpdatingChildren = new HashSet(); private long myJanitorPollPeriod = Time.SECOND * 10; @@ -187,14 +188,14 @@ public class AbstractTreeUi { public void showNotify() { myShowing = true; myWasEverShown = true; - if (!isReleased()) { + if (!isReleaseRequested()) { activate(true); } } public void hideNotify() { myShowing = false; - if (!isReleased()) { + if (!validateReleaseRequested()) { deactivate(); } } @@ -268,7 +269,7 @@ public class AbstractTreeUi { protected void doCleanUp() { Runnable cleanup = new Runnable() { public void run() { - if (!isReleased()) { + if (!isReleaseRequested()) { cleanUpNow(); } } @@ -323,10 +324,19 @@ public class AbstractTreeUi { } } + public void requestRelease() { + if (isReleaseRequested()) return; - public void release() { - if (isReleased()) return; + assertIsDispatchThread(); + myReleaseRequested = true; + + getUpdater().requestRelease(); + + maybeReady(); + } + + private void releaseNow() { myTree.removeTreeExpansionListener(myExpansionListener); myTree.removeTreeSelectionListener(mySelectionListener); myTree.removeFocusListener(myFocusListener); @@ -347,8 +357,8 @@ public class AbstractTreeUi { myTree = null; setUpdater(null); myWorker = null; -//todo [kirillk] afraid to do so just in release day, to uncomment -// myTreeStructure = null; + myTreeStructure = null; + myBuilder.releaseUi(); myBuilder = null; clearNodeActions(); @@ -358,6 +368,23 @@ public class AbstractTreeUi { myYeildingDoneRunnables.clear(); } + public boolean isReleaseRequested() { + return myReleaseRequested; + } + + public boolean validateReleaseRequested() { + if (isReleaseRequested()) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + maybeReady(); + } + }); + return true; + } else { + return false; + } + } + public boolean isReleased() { return myBuilder == null; } @@ -366,9 +393,13 @@ public class AbstractTreeUi { if (!myUnbuiltNodes.contains(node)) return; if (isLoadedInBackground(getElementFor(node))) return; - getTreeStructure().commit(); - addSubtreeToUpdate(node); - getUpdater().performUpdate(); + if (!isReleaseRequested()) { + getTreeStructure().commit(); + addSubtreeToUpdate(node); + getUpdater().performUpdate(); + } else { + processNodeActionsIfReady(node); + } } public final AbstractTreeStructure getTreeStructure() { @@ -710,7 +741,7 @@ public class AbstractTreeUi { else { UIUtil.invokeLaterIfNeeded(new Runnable() { public void run() { - if (!isReleased()) { + if (!validateReleaseRequested()) { result.setDone(_update(nodeDescriptor)); } else { @@ -1067,6 +1098,7 @@ public class AbstractTreeUi { .doWhenDone(new Runnable() { public void run() { if (isDisposed(node)) { + removeFromUpdating(node); return; } @@ -1106,10 +1138,17 @@ public class AbstractTreeUi { }).doWhenProcessed(new Runnable() { public void run() { myWillBeExpaned.remove(node); + removeFromUpdating(node); + processNodeActionsIfReady(node); } }); } - }); + }).doWhenRejected(new Runnable() { + public void run() { + removeFromUpdating(node); + processNodeActionsIfReady(node); + } + }); } private boolean isDisposed(DefaultMutableTreeNode node) { @@ -1343,9 +1382,17 @@ public class AbstractTreeUi { else { if (isToYieldUpdateFor(node)) { pass.setCurrentNode(node); - yieldAndRun(new Runnable() { + boolean wasRun = yieldAndRun(new Runnable() { public void run() { - if (pass.isExpired()) return; + if (validateReleaseRequested()) { + result.setRejected(); + return; + } + + if (pass.isExpired()) { + result.setRejected(); + return; + } if (isRerunNeeded(pass)) { runDone(new Runnable() { @@ -1362,6 +1409,9 @@ public class AbstractTreeUi { } } }, pass); + if (!wasRun) { + result.setRejected(); + } } else { processRunnable.run().notify(result); @@ -1371,25 +1421,22 @@ public class AbstractTreeUi { return result; } - private void yieldAndRun(final Runnable runnable, final TreeUpdatePass pass) { + private boolean yieldAndRun(final Runnable runnable, final TreeUpdatePass pass) { + if (validateReleaseRequested()) return false; + myYeildingPasses.add(pass); myYeildingNow = true; yield(new Runnable() { public void run() { - if (isReleased()) { - return; - } - runOnYieldingDone(new Runnable() { public void run() { - if (isReleased()) { - return; - } executeYieldingRequest(runnable, pass); } }); } }); + + return true; } public boolean isYeildingNow() { @@ -1433,6 +1480,11 @@ public class AbstractTreeUi { if (isReleased()) return; if (isReady()) { + if (isReleaseRequested()) { + releaseNow(); + return; + } + if (myTree.isShowing() || myUpdateIfInactive) { myInitialized.setDone(); } @@ -1785,6 +1837,8 @@ public class AbstractTreeUi { private boolean queueBackgroundUpdate(final UpdateInfo updateInfo, final DefaultMutableTreeNode node) { assertIsDispatchThread(); + if (validateReleaseRequested()) return false; + final Object oldElementFromDescriptor = getElementFromDescriptor(updateInfo.getDescriptor()); UpdateInfo loaded = getLoadedInBackground(oldElementFromDescriptor); @@ -1804,10 +1858,6 @@ public class AbstractTreeUi { final Ref elementFromDescriptor = new Ref(); Runnable buildRunnable = new Runnable() { public void run() { - if (isReleased()) { - return; - } - if (!updateInfo.isDescriptorIsUpToDate()) { update(updateInfo.getDescriptor(), true); } @@ -1834,7 +1884,6 @@ public class AbstractTreeUi { final DefaultMutableTreeNode[] nodeToProcessActions = new DefaultMutableTreeNode[1]; Runnable updateRunnable = new Runnable() { public void run() { - if (isReleased()) return; if (children.get() == null) return; if (isRerunNeeded(updateInfo.getPass())) { @@ -2418,37 +2467,27 @@ public class AbstractTreeUi { protected void queueToBackground(@NotNull final Runnable bgBuildAction, @Nullable final Runnable edtPostRunnable, @Nullable final Runnable finalizeEdtRunnable) { + if (validateReleaseRequested()) return; + registerWorkerTask(bgBuildAction); final Runnable pooledThreadWithProgressRunnable = new Runnable() { public void run() { - if (isReleased()) { - return; - } - final AbstractTreeBuilder builder = getBuilder(); builder.runBackgroundLoading(new Runnable() { public void run() { assertNotDispatchThread(); - if (isReleased()) { - return; - } - try { bgBuildAction.run(); - if (edtPostRunnable != null && !isReleased()) { + if (edtPostRunnable != null) { builder.updateAfterLoadedInBackground(new Runnable() { public void run() { try { assertIsDispatchThread(); - if (isReleased()) { - return; - } - edtPostRunnable.run(); } finally { @@ -2475,8 +2514,6 @@ public class AbstractTreeUi { Runnable pooledThreadRunnable = new Runnable() { public void run() { - if (isReleased()) return; - try { if (myProgress != null) { ProgressManager.getInstance().runProcess(pooledThreadWithProgressRunnable, myProgress); @@ -2690,8 +2727,12 @@ public class AbstractTreeUi { return false; } - getUpdater().runAfterUpdate(runAfterUpdate); - getUpdater().addSubtreeToUpdate(root); + if (isReleaseRequested()) { + processNodeActionsIfReady(root); + } else { + getUpdater().runAfterUpdate(runAfterUpdate); + getUpdater().addSubtreeToUpdate(root); + } return true; } @@ -3040,6 +3081,10 @@ public class AbstractTreeUi { public void run() { runDone(onDone); } + }).doWhenRejected(new Runnable() { + public void run() { + runDone(onDone); + } }); expandNext(element, 0, parentsOnly, checkIfInStructure, canSmartExpand, done); @@ -3078,7 +3123,6 @@ public class AbstractTreeUi { } private void runDone(@Nullable Runnable done) { - if (isReleased()) return; if (done == null) return; if (isYeildingNow()) { @@ -3171,7 +3215,6 @@ public class AbstractTreeUi { addNodeAction(element, new NodeAction() { public void onReady(final DefaultMutableTreeNode node) { - if (node.getChildCount() > 0 && !myTree.isExpanded(new TreePath(node.getPath()))) { if (!isAutoExpand(node)) { expand(node, canSmartExpand); @@ -3254,6 +3297,8 @@ public class AbstractTreeUi { } public final boolean isNodeBeingBuilt(Object node) { + if (isReleaseRequested()) return false; + return getParentBuiltNode(node) != null; } @@ -3456,7 +3501,7 @@ public class AbstractTreeUi { private void cleanUpNow() { - if (isReleased()) return; + if (isReleaseRequested()) return; final UpdaterTreeState state = new UpdaterTreeState(this); diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java index 8f3641809243..4b534ea6744c 100644 --- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java +++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUpdater.java @@ -46,6 +46,7 @@ public class AbstractTreeUpdater implements Disposable, Activatable { private final MergingUpdateQueue myUpdateQueue; private long myUpdateCount; + private boolean myReleaseRequested; public AbstractTreeUpdater(AbstractTreeBuilder treeBuilder) { myTreeBuilder = treeBuilder; @@ -96,13 +97,10 @@ public class AbstractTreeUpdater implements Disposable, Activatable { } public synchronized void addSubtreeToUpdate(@NotNull TreeUpdatePass toAdd) { - if (LOG.isDebugEnabled()) { - LOG.debug("addSubtreeToUpdate:" + toAdd.getNode()); - } + if (myReleaseRequested) return; assert !toAdd.isExpired(); - - + final AbstractTreeUi ui = myTreeBuilder.getUi(); if (ui.isUpdatingNow(toAdd.getNode())) { @@ -363,4 +361,12 @@ public class AbstractTreeUpdater implements Disposable, Activatable { } }); } + + public void requestRelease() { + myReleaseRequested = true; + + myNodeQueue.clear(); + myUpdateQueue.cancelAllUpdates(); + myUpdateQueue.deactivate(); + } }