| /* |
| * Copyright 2000-2011 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.openapi.vcs.changes; |
| |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.progress.BackgroundTaskQueue; |
| import com.intellij.openapi.progress.ProgressIndicator; |
| import com.intellij.openapi.progress.Task; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.MessageType; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.vcs.*; |
| import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; |
| import com.intellij.util.Consumer; |
| import com.intellij.util.PairConsumer; |
| import com.intellij.util.Ticket; |
| import com.intellij.util.continuation.ModalityIgnorantBackgroundableTask; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| |
| /** |
| * For presentation, which is itself in GenericDetails (not necessarily) - shown from time to time, but cached, and |
| * which is a listener to some intensive changes (a group of invalidating changes should provoke a reload, but "outdated" (loaded but already not actual) results should be thrown away) |
| * |
| * |
| * User: Irina.Chernushina |
| * Date: 9/7/11 |
| * Time: 3:13 PM |
| */ |
| public abstract class AbstractRefreshablePanel<T> implements RefreshablePanel<Change> { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.AbstractRefreshablePanel"); |
| protected final Ticket myTicket; |
| private final DetailsPanel myDetailsPanel; |
| private final GenericDetailsLoader<Ticket, T> myDetailsLoader; |
| private final BackgroundTaskQueue myQueue; |
| private volatile boolean myDisposed; |
| |
| protected AbstractRefreshablePanel(final Project project, final String loadingTitle, final BackgroundTaskQueue queue) { |
| myQueue = queue; |
| myTicket = new Ticket(); |
| myDetailsPanel = new DetailsPanel(); |
| myDetailsPanel.loading(); |
| myDetailsPanel.layout(); |
| |
| myDetailsLoader = new GenericDetailsLoader<Ticket, T>(new Consumer<Ticket>() { |
| @Override |
| public void consume(Ticket ticket) { |
| final Loader loader = new Loader(project, loadingTitle, myTicket.copy()); |
| loader.runSteadily(new Consumer<Task.Backgroundable>() { |
| @Override |
| public void consume(Task.Backgroundable backgroundable) { |
| myQueue.run(backgroundable); |
| } |
| }); |
| } |
| }, new PairConsumer<Ticket, T>() { |
| @Override |
| public void consume(Ticket ticket, T t) { |
| acceptData(t); |
| } |
| }); |
| } |
| |
| @Override |
| public boolean refreshDataSynch() { |
| return false; |
| } |
| |
| @CalledInAwt |
| @Override |
| public void dataChanged() { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| myTicket.increment(); |
| } |
| |
| @CalledInAwt |
| @Override |
| public void refresh() { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| |
| if (! Comparing.equal(myDetailsLoader.getCurrentlySelected(), myTicket)) { |
| final Ticket copy = myTicket.copy(); |
| myDetailsLoader.updateSelection(copy, false); |
| myDetailsPanel.loading(); |
| myDetailsPanel.layout(); |
| } else { |
| refreshPresentation(); |
| } |
| } |
| |
| protected abstract void refreshPresentation(); |
| |
| @CalledInBackground |
| protected abstract T loadImpl() throws VcsException; |
| @CalledInAwt |
| protected abstract JPanel dataToPresentation(final T t); |
| protected abstract void disposeImpl(); |
| |
| @CalledInAwt |
| private void acceptData(final T t) { |
| final JPanel panel = dataToPresentation(t); |
| myDetailsPanel.data(panel); |
| myDetailsPanel.layout(); |
| } |
| |
| @Override |
| public JPanel getPanel() { |
| return myDetailsPanel.getPanel(); |
| } |
| |
| @Override |
| public boolean isStillValid(Change data) { |
| return true; |
| } |
| |
| private class Loader extends ModalityIgnorantBackgroundableTask { |
| private final Ticket myTicketCopy; |
| private T myT; |
| |
| private Loader(@Nullable Project project, @NotNull String title, final Ticket ticketCopy) { |
| super(project, title, false, BackgroundFromStartOption.getInstance()); |
| myTicketCopy = ticketCopy; |
| } |
| |
| @Override |
| protected void doInAwtIfFail(Exception e) { |
| final Exception cause; |
| if (e instanceof MyRuntime && e.getCause() != null) { |
| cause = (Exception) e.getCause(); |
| } else { |
| cause = e; |
| } |
| LOG.info(e); |
| String message = cause.getMessage() == null ? e.getMessage() : cause.getMessage(); |
| message = message == null ? "Unknown error" : message; |
| VcsBalloonProblemNotifier.showOverChangesView(myProject, message, MessageType.ERROR); |
| } |
| |
| @Override |
| protected void doInAwtIfCancel() { |
| } |
| |
| @Override |
| protected void doInAwtIfSuccess() { |
| if (myDisposed) return; |
| try { |
| myDetailsLoader.take(myTicketCopy, myT); |
| } |
| catch (Details.AlreadyDisposedException e) { |
| // t is not disposable |
| } |
| } |
| |
| @Override |
| protected void runImpl(@NotNull ProgressIndicator indicator) { |
| if (myDisposed) return; |
| try { |
| myT = loadImpl(); |
| } |
| catch (VcsException e) { |
| throw new MyRuntime(e); |
| } |
| } |
| } |
| |
| private static class MyRuntime extends RuntimeException { |
| private MyRuntime(Throwable cause) { |
| super(cause); |
| } |
| } |
| |
| @Override |
| public void dispose() { |
| myDisposed = true; |
| disposeImpl(); |
| } |
| } |