diff: improve javadoc for DiffRequestChain
[idea/community.git] / platform / diff-impl / src / com / intellij / diff / chains / AsyncDiffRequestChain.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.diff.chains;
3
4 import com.intellij.diff.chains.SimpleDiffRequestChain.DiffRequestProducerWrapper;
5 import com.intellij.diff.requests.ErrorDiffRequest;
6 import com.intellij.diff.requests.LoadingDiffRequest;
7 import com.intellij.openapi.Disposable;
8 import com.intellij.openapi.ListSelection;
9 import com.intellij.openapi.progress.ProgressIndicator;
10 import com.intellij.openapi.progress.util.BackgroundTaskUtil;
11 import com.intellij.openapi.util.UserDataHolderBase;
12 import com.intellij.util.EventDispatcher;
13 import com.intellij.util.concurrency.annotations.RequiresBackgroundThread;
14 import com.intellij.util.concurrency.annotations.RequiresEdt;
15 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.annotations.Nullable;
17
18 import java.util.EventListener;
19
20 /**
21  * Allows loading requests asynchronously after showing diff UI, without the need for modal progress
22  *
23  * @see com.intellij.openapi.vcs.changes.ui.ChangeDiffRequestChain.Async
24  */
25 public abstract class AsyncDiffRequestChain extends UserDataHolderBase implements DiffRequestSelectionChain {
26   private final EventDispatcher<Listener> myDispatcher = EventDispatcher.create(Listener.class);
27
28   private volatile ListSelection<? extends DiffRequestProducer> myRequests = null;
29
30   @Nullable private ProgressIndicator myIndicator;
31   private int myAssignments = 0;
32
33   public void addListener(@NotNull Listener listener, @NotNull Disposable disposable) {
34     myDispatcher.addListener(listener, disposable);
35   }
36
37   public void removeListener(@NotNull Listener listener) {
38     myDispatcher.removeListener(listener);
39   }
40
41   @Override
42   public @NotNull ListSelection<? extends DiffRequestProducer> getListSelection() {
43     ListSelection<? extends DiffRequestProducer> requests = myRequests;
44     if (requests == null) {
45       return ListSelection.createSingleton(new DiffRequestProducerWrapper(new LoadingDiffRequest()));
46     }
47     return requests;
48   }
49
50   @NotNull
51   @RequiresBackgroundThread
52   public ListSelection<? extends DiffRequestProducer> loadRequestsInBackground() {
53     try {
54       return loadRequestProducers();
55     }
56     catch (DiffRequestProducerException e) {
57       return ListSelection.createSingleton(new DiffRequestProducerWrapper(new ErrorDiffRequest(e)));
58     }
59   }
60
61   @RequiresEdt
62   public void onAssigned(boolean isAssigned) {
63     if (isAssigned) {
64       if (myAssignments == 0 && myIndicator == null) {
65         myIndicator = startLoading();
66       }
67       myAssignments++;
68     }
69     else {
70       myAssignments--;
71       if (myAssignments == 0 && myIndicator != null) {
72         myIndicator.cancel();
73         myIndicator = null;
74       }
75     }
76     assert myAssignments >= 0;
77   }
78
79   @Nullable
80   @RequiresEdt
81   private ProgressIndicator startLoading() {
82     if (myRequests != null) return null;
83
84     return BackgroundTaskUtil.executeAndTryWait(indicator -> {
85       ListSelection<? extends DiffRequestProducer> producers = loadRequestsInBackground();
86       return () -> {
87         indicator.checkCanceled();
88         applyLoadedChanges(producers);
89       };
90     }, null);
91   }
92
93   @RequiresEdt
94   private void applyLoadedChanges(@NotNull ListSelection<? extends DiffRequestProducer> producers) {
95     if (myRequests != null) return;
96
97     myRequests = producers;
98     myIndicator = null;
99
100     myDispatcher.getMulticaster().onRequestsLoaded();
101   }
102
103   @NotNull
104   @RequiresBackgroundThread
105   protected abstract ListSelection<? extends DiffRequestProducer> loadRequestProducers() throws DiffRequestProducerException;
106
107   public interface Listener extends EventListener {
108     @RequiresEdt
109     void onRequestsLoaded();
110   }
111 }