From fc28fcde972be5ccf4e4820649b4587bf44fdeec Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Wed, 1 Jul 2015 13:59:56 +0300 Subject: [PATCH] diff: show progress bar while loading annotations * add DiffViewer-independent progress bar --- .../src/com/intellij/diff/DiffContextEx.java | 5 ++ .../diff/impl/DiffRequestProcessor.java | 42 ++++++++++-- .../diff/util/BackgroundTaskUtil.java | 45 ++++++++++++ .../vcs/actions/AnnotateDiffViewerAction.java | 68 ++++++++++--------- 4 files changed, 121 insertions(+), 39 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java b/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java index a9369b9bfcac..21686c3cdfcb 100644 --- a/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java +++ b/platform/diff-impl/src/com/intellij/diff/DiffContextEx.java @@ -31,4 +31,9 @@ public abstract class DiffContextEx extends DiffContext { * this can be used, if some change in request or settings was made, and we need to reload DiffRequest to apply them. */ public abstract void reloadDiffRequest(); + + /* + * Show indeterminate progress near status panel. + */ + public abstract void showProgressBar(boolean enabled); } diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java index 56ebb04b01e5..a7b3912b8456 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java @@ -56,6 +56,7 @@ import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; import com.intellij.ui.ColorUtil; import com.intellij.ui.HintHint; import com.intellij.ui.JBColor; +import com.intellij.ui.JBProgressBar; import com.intellij.ui.LightweightHint; import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.containers.ContainerUtil; @@ -93,6 +94,7 @@ public abstract class DiffRequestProcessor implements Disposable { @NotNull private final Wrapper myContentPanel; @NotNull private final Wrapper myToolbarPanel; // TODO: allow to call 'updateToolbar' from Viewer ? @NotNull private final Wrapper myToolbarStatusPanel; + @NotNull private final MyProgressBar myProgressBar; @NotNull private DiffRequest myActiveRequest; @@ -119,19 +121,17 @@ public abstract class DiffRequestProcessor implements Disposable { // UI - myPanel = new JPanel(new BorderLayout()); myMainPanel = new MyPanel(); myContentPanel = new Wrapper(); myToolbarPanel = new Wrapper(); myToolbarPanel.setFocusable(true); myToolbarStatusPanel = new Wrapper(); + myProgressBar = new MyProgressBar(); - myPanel.add(myMainPanel, BorderLayout.CENTER); - - JPanel topPanel = new JPanel(new BorderLayout()); - topPanel.add(myToolbarPanel, BorderLayout.CENTER); - topPanel.add(myToolbarStatusPanel, BorderLayout.EAST); + myPanel = JBUI.Panels.simplePanel(myMainPanel); + JPanel statusPanel = JBUI.Panels.simplePanel(myToolbarStatusPanel).addToLeft(myProgressBar); + JPanel topPanel = JBUI.Panels.simplePanel(myToolbarPanel).addToRight(statusPanel); myMainPanel.add(topPanel, BorderLayout.NORTH); myMainPanel.add(myContentPanel, BorderLayout.CENTER); @@ -894,6 +894,26 @@ public abstract class DiffRequestProcessor implements Disposable { } } + private static class MyProgressBar extends JBProgressBar { + private int myProgressCount = 0; + + public MyProgressBar() { + setIndeterminate(true); + setVisible(false); + } + + public void startProgress() { + myProgressCount++; + setVisible(true); + } + + public void stopProgress() { + myProgressCount--; + LOG.assertTrue(myProgressCount >= 0); + if (myProgressCount == 0) setVisible(false); + } + } + private class MyFocusTraversalPolicy extends IdeFocusTraversalPolicy { @Override public final Component getDefaultComponentImpl(final Container focusCycleRoot) { @@ -920,6 +940,16 @@ public abstract class DiffRequestProcessor implements Disposable { reloadRequest(); } + @Override + public void showProgressBar(boolean enabled) { + if (enabled) { + myProgressBar.startProgress(); + } + else { + myProgressBar.stopProgress(); + } + } + @Nullable @Override public Project getProject() { diff --git a/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java index 52bb0a6d3409..6936cd40adcd 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.diff.util; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -22,8 +23,10 @@ import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Ref; +import com.intellij.util.Consumer; import com.intellij.util.Function; import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NotNull; @@ -162,4 +165,46 @@ public class BackgroundTaskUtil { return resultRef.get(); } + + @CalledInAwt + @NotNull + public static ProgressIndicator executeOnPooledThread(@NotNull final Consumer task, @NotNull Disposable parent) { + final ModalityState modalityState = ModalityState.current(); + final ProgressIndicator indicator = new EmptyProgressIndicator() { + @NotNull + @Override + public ModalityState getModalityState() { + return modalityState; + } + }; + indicator.start(); + + final Disposable disposable = new Disposable() { + @Override + public void dispose() { + if (indicator.isRunning()) indicator.cancel(); + } + }; + Disposer.register(parent, disposable); + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() { + @Override + public void run() { + try { + task.consume(indicator); + } + finally { + indicator.stop(); + Disposer.dispose(disposable); + } + } + }, indicator); + } + }); + + return indicator; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java index 018878f3a64d..3a6fae1d1331 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vcs.actions; import com.intellij.diff.DiffContext; +import com.intellij.diff.DiffContextEx; import com.intellij.diff.DiffExtension; import com.intellij.diff.FrameDiffTool.DiffViewer; import com.intellij.diff.contents.DiffContent; @@ -28,19 +29,16 @@ import com.intellij.diff.tools.util.base.DiffViewerBase; import com.intellij.diff.tools.util.base.DiffViewerListener; import com.intellij.diff.tools.util.side.OnesideTextDiffViewer; import com.intellij.diff.tools.util.side.TwosideTextDiffViewer; +import com.intellij.diff.util.BackgroundTaskUtil; import com.intellij.diff.util.Side; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.localVcs.UpToDateLineNumberProvider; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator; -import com.intellij.openapi.progress.impl.ProgressManagerImpl; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; @@ -48,7 +46,10 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.annotate.AnnotationProvider; import com.intellij.openapi.vcs.annotate.FileAnnotation; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangesUtil; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.CurrentContentRevision; import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer; import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsFileRevisionEx; @@ -59,6 +60,7 @@ import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl; import com.intellij.openapi.vcs.impl.UpToDateLineNumberProviderImpl; import com.intellij.openapi.vcs.impl.VcsBackgroundableActions; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; import com.intellij.util.ObjectUtils; import com.intellij.vcs.AnnotationProviderEx; import com.intellij.vcsUtil.VcsUtil; @@ -145,41 +147,41 @@ public class AnnotateDiffViewerAction extends DumbAwareAction { final FileAnnotationLoader loader = createAnnotationsLoader(project, viewer.getRequest(), side); assert loader != null; + final DiffContextEx diffContext = ObjectUtils.tryCast(viewer.getContext(), DiffContextEx.class); + markRunningProgress(viewer, side, true); + if (diffContext != null) diffContext.showProgressBar(true); - // TODO: show progress in diff viewer - // TODO: we can abort loading on DiffViewer.dispose(). But vcs can't stop gracefully anyway. - Task.Backgroundable task = new Task.Backgroundable(project, VcsBundle.message("retrieving.annotations"), true, - BackgroundFromStartOption.getInstance()) { - public void run(@NotNull ProgressIndicator indicator) { - loader.run(); - } - + BackgroundTaskUtil.executeOnPooledThread(new Consumer() { @Override - public void onCancel() { - onSuccess(); - } - - @Override - public void onSuccess() { - markRunningProgress(viewer, side, false); - - if (loader.getException() != null) { - AbstractVcsHelper.getInstance(myProject).showError(loader.getException(), VcsBundle.message("operation.name.annotate")); + public void consume(ProgressIndicator indicator) { + try { + loader.run(); } - if (loader.getResult() == null) return; - if (viewer.isDisposed()) return; + finally { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (diffContext != null) diffContext.showProgressBar(false); + markRunningProgress(viewer, side, false); - annotator.showAnnotation(viewer, side, loader.getResult()); + if (loader.getException() != null) { + AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(viewer.getProject()); + vcsHelper.showError(loader.getException(), VcsBundle.message("operation.name.annotate")); + } + if (loader.getResult() == null) return; + if (viewer.isDisposed()) return; - if (loader.shouldCache()) { - putDataToCache(viewer, side, loader.getResult()); + annotator.showAnnotation(viewer, side, loader.getResult()); + + if (loader.shouldCache()) { + putDataToCache(viewer, side, loader.getResult()); + } + } + }, indicator.getModalityState()); } } - }; - ProgressIndicator indicator = new BackgroundableProcessIndicator(task); - ProgressManagerImpl progressManager = (ProgressManagerImpl)ProgressManager.getInstance(); - progressManager.runProcessWithProgressAsynchronously(task, indicator, null, ModalityState.current()); + }, viewer); } @Nullable