blob: fe20806a8ed4c1822b3367ac5736b3a3d7ea7098 [file] [log] [blame]
/*
* 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();
}
}