vcs: Inlined "GenericDetailsLoader" logic to "AbstractRefreshablePanel"
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / changes / AbstractRefreshablePanel.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.openapi.vcs.changes;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.progress.BackgroundTaskQueue;
21 import com.intellij.openapi.progress.ProgressIndicator;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.ui.MessageType;
24 import com.intellij.openapi.util.Comparing;
25 import com.intellij.openapi.vcs.VcsException;
26 import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
27 import com.intellij.util.continuation.ModalityIgnorantBackgroundableTask;
28 import org.jetbrains.annotations.CalledInAwt;
29 import org.jetbrains.annotations.CalledInBackground;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
32
33 import javax.swing.*;
34
35 /**
36  * For presentation, which is itself in GenericDetails (not necessarily) - shown from time to time, but cached, and
37  * which is a listener to some intensive changes (a group of invalidating changes should provoke a reload, but "outdated"
38  * (loaded but already not actual) results should be thrown away)
39  *
40  * @author Irina.Chernushina
41  * @since 7.09.2011
42  */
43 public abstract class AbstractRefreshablePanel<T> implements RefreshablePanel<Change> {
44   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.AbstractRefreshablePanel");
45
46   @NotNull private final Project myProject;
47   @NotNull private final String myLoadingTitle;
48   private Ticket myCurrentlySelected;
49   private Ticket mySetId;
50   private final Ticket myTicket;
51   private final DetailsPanel myDetailsPanel;
52   private final BackgroundTaskQueue myQueue;
53   private volatile boolean myDisposed;
54
55   protected AbstractRefreshablePanel(@NotNull Project project, @NotNull String loadingTitle, @NotNull BackgroundTaskQueue queue) {
56     myProject = project;
57     myLoadingTitle = loadingTitle;
58     myQueue = queue;
59     myTicket = new Ticket();
60     myDetailsPanel = new DetailsPanel();
61     myDetailsPanel.loading();
62     myDetailsPanel.layout();
63   }
64
65   @Override
66   public boolean refreshDataSynch() {
67     return false;
68   }
69
70   @CalledInAwt
71   @Override
72   public void dataChanged() {
73     ApplicationManager.getApplication().assertIsDispatchThread();
74     myTicket.increment();
75   }
76
77   @CalledInAwt
78   @Override
79   public void refresh() {
80     ApplicationManager.getApplication().assertIsDispatchThread();
81
82     if (!Comparing.equal(myCurrentlySelected, myTicket)) {
83       Ticket copy = myTicket.copy();
84       Ticket previousId = myCurrentlySelected;
85       myCurrentlySelected = copy;
86       mySetId = null;
87       if (!Comparing.equal(copy, previousId)) {
88         myQueue.run(new Loader(myProject, myLoadingTitle, copy));
89       }
90
91       myDetailsPanel.loading();
92       myDetailsPanel.layout();
93     } else {
94       refreshPresentation();
95     }
96   }
97
98   protected abstract void refreshPresentation();
99
100   @CalledInBackground
101   protected abstract T loadImpl() throws VcsException;
102   @CalledInAwt
103   protected abstract JPanel dataToPresentation(final T t);
104   protected abstract void disposeImpl();
105   
106   @CalledInAwt
107   private void acceptData(final T t) {
108     final JPanel panel = dataToPresentation(t);
109     myDetailsPanel.data(panel);
110     myDetailsPanel.layout();
111   }
112
113   @Override
114   public JPanel getPanel() {
115     return myDetailsPanel.getPanel();
116   }
117
118   @Override
119   public boolean isStillValid(Change data) {
120     return true;
121   }
122
123   private class Loader extends ModalityIgnorantBackgroundableTask {
124     private final Ticket myTicketCopy;
125     private T myT;
126
127     private Loader(@Nullable Project project, @NotNull String title, final Ticket ticketCopy) {
128       super(project, title, false);
129       myTicketCopy = ticketCopy;
130     }
131
132     @Override
133     protected void doInAwtIfFail(@NotNull Exception e) {
134       final Exception cause;
135       if (e instanceof RuntimeException && e.getCause() != null) {
136         cause = (Exception) e.getCause();
137       } else {
138         cause = e;
139       }
140       LOG.info(e);
141       String message = cause.getMessage() == null ? e.getMessage() : cause.getMessage();
142       message = message == null ? "Unknown error" : message;
143       VcsBalloonProblemNotifier.showOverChangesView(myProject, message, MessageType.ERROR);
144     }
145
146     @Override
147     protected void doInAwtIfCancel() {
148     }
149
150     @Override
151     protected void doInAwtIfSuccess() {
152       if (myDisposed) return;
153
154       if (!myTicketCopy.equals(mySetId) && myTicketCopy.equals(myCurrentlySelected)) {
155         mySetId = myTicketCopy;
156         acceptData(myT);
157       }
158     }
159
160     @Override
161     protected void runImpl(@NotNull ProgressIndicator indicator) {
162       if (myDisposed) return;
163       try {
164         myT = loadImpl();
165       }
166       catch (VcsException e) {
167         throw new RuntimeException(e);
168       }
169     }
170   }
171
172   @Override
173   public void dispose() {
174     myDisposed = true;
175     disposeImpl();
176   }
177
178   private static class Ticket {
179     private int myId;
180
181     public Ticket() {
182       myId = 0;
183     }
184
185     public Ticket(int id) {
186       myId = id;
187     }
188
189     public Ticket copy() {
190       return new Ticket(myId);
191     }
192
193     public void increment() {
194       ++ myId;
195     }
196
197     @Override
198     public boolean equals(Object o) {
199       if (this == o) return true;
200       if (o == null || getClass() != o.getClass()) return false;
201
202       Ticket ticket = (Ticket)o;
203
204       if (myId != ticket.myId) return false;
205
206       return true;
207     }
208
209     @Override
210     public int hashCode() {
211       return myId;
212     }
213   }
214 }