blob: 77ef5d7f2536cb707a3a0ec19ce6e7e646f65362 [file] [log] [blame]
/*
* Copyright 2000-2014 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.impl;
import com.intellij.ide.actions.CloseTabToolbarAction;
import com.intellij.ide.errorTreeView.ErrorTreeElementKind;
import com.intellij.ide.errorTreeView.HotfixData;
import com.intellij.ide.errorTreeView.SimpleErrorData;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.actions.AnnotateToggleAction;
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.committed.*;
import com.intellij.openapi.vcs.changes.ui.*;
import com.intellij.openapi.vcs.history.*;
import com.intellij.openapi.vcs.merge.MergeDialogCustomizer;
import com.intellij.openapi.vcs.merge.MergeProvider;
import com.intellij.openapi.vcs.merge.MultipleFileMergeDialog;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.MessageView;
import com.intellij.util.ArrayUtil;
import com.intellij.util.AsynchConsumer;
import com.intellij.util.BufferedListConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.ui.ConfirmationDialog;
import com.intellij.util.ui.ErrorTreeView;
import com.intellij.util.ui.MessageCategory;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;
public class AbstractVcsHelperImpl extends AbstractVcsHelper {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.impl.AbstractVcsHelperImpl");
private Consumer<VcsException> myCustomHandler = null;
protected AbstractVcsHelperImpl(@NotNull Project project) {
super(project);
}
public void openMessagesView(final VcsErrorViewPanel errorTreeView, final String tabDisplayName) {
CommandProcessor commandProcessor = CommandProcessor.getInstance();
commandProcessor.executeCommand(myProject, new Runnable() {
public void run() {
final MessageView messageView = MessageView.SERVICE.getInstance(myProject);
messageView.runWhenInitialized(new Runnable() {
public void run() {
final Content content =
ContentFactory.SERVICE.getInstance().createContent(errorTreeView, tabDisplayName, true);
messageView.getContentManager().addContent(content);
Disposer.register(content, errorTreeView);
messageView.getContentManager().setSelectedContent(content);
removeContents(content, tabDisplayName);
ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.MESSAGES_WINDOW).activate(null);
}
});
}
}, VcsBundle.message("command.name.open.error.message.view"), null);
}
public void showFileHistory(final VcsHistoryProvider vcsHistoryProvider, final FilePath path, final AbstractVcs vcs,
final String repositoryPath) {
showFileHistory(vcsHistoryProvider, null, path, repositoryPath, vcs);
}
public void showFileHistory(final VcsHistoryProvider vcsHistoryProvider, final AnnotationProvider annotationProvider, final FilePath path,
final String repositoryPath, final AbstractVcs vcs) {
final FileHistoryRefresherI refresherI = new FileHistoryRefresher(vcsHistoryProvider, annotationProvider, path, repositoryPath, vcs);
refresherI.run(false, true);
}
public void showRollbackChangesDialog(List<Change> changes) {
RollbackChangesDialog.rollbackChanges(myProject, changes);
}
@Nullable
public Collection<VirtualFile> selectFilesToProcess(final List<VirtualFile> files,
final String title,
@Nullable final String prompt,
final String singleFileTitle,
final String singleFilePromptTemplate,
final VcsShowConfirmationOption confirmationOption) {
if (files == null || files.isEmpty()) {
return null;
}
if (files.size() == 1 && singleFilePromptTemplate != null) {
String filePrompt = MessageFormat.format(singleFilePromptTemplate, files.get(0).getPresentableUrl());
if (ConfirmationDialog
.requestForConfirmation(confirmationOption, myProject, filePrompt, singleFileTitle, Messages.getQuestionIcon())) {
return files;
}
return null;
}
SelectFilesDialog dlg = SelectFilesDialog.init(myProject, files, prompt, confirmationOption, true, true, false);
dlg.setTitle(title);
if (! confirmationOption.isPersistent()) {
dlg.setDoNotAskOption(null);
}
dlg.show();
if (dlg.isOK()) {
final Collection<VirtualFile> selection = dlg.getSelectedFiles();
// return items in the same order as they were passed to us
final List<VirtualFile> result = new ArrayList<VirtualFile>();
for(VirtualFile file: files) {
if (selection.contains(file)) {
result.add(file);
}
}
return result;
}
return null;
}
@Nullable
public Collection<FilePath> selectFilePathsToProcess(List<FilePath> files,
String title,
@Nullable String prompt,
String singleFileTitle,
String singleFilePromptTemplate,
VcsShowConfirmationOption confirmationOption,
@Nullable String okActionName,
@Nullable String cancelActionName) {
if (files.size() == 1 && singleFilePromptTemplate != null) {
final String filePrompt = MessageFormat.format(singleFilePromptTemplate, files.get(0).getPresentableUrl());
if (ConfirmationDialog.requestForConfirmation(confirmationOption, myProject, filePrompt, singleFileTitle,
Messages.getQuestionIcon(), okActionName, cancelActionName)) {
return files;
}
return null;
}
final SelectFilePathsDialog dlg =
new SelectFilePathsDialog(myProject, files, prompt, confirmationOption, okActionName, cancelActionName, true);
dlg.setTitle(title);
if (! confirmationOption.isPersistent()) {
dlg.setDoNotAskOption(null);
}
dlg.show();
return dlg.isOK() ? dlg.getSelectedFiles() : null;
}
@Nullable
public Collection<FilePath> selectFilePathsToProcess(final List<FilePath> files,
final String title,
@Nullable final String prompt,
final String singleFileTitle,
final String singleFilePromptTemplate,
final VcsShowConfirmationOption confirmationOption) {
return selectFilePathsToProcess(files, title, prompt, singleFileTitle, singleFilePromptTemplate, confirmationOption, null, null);
}
public void showErrors(final List<VcsException> abstractVcsExceptions, @NotNull final String tabDisplayName) {
showErrorsImpl(abstractVcsExceptions.isEmpty(), new Getter<VcsException>() {
public VcsException get() {
return abstractVcsExceptions.get(0);
}
}, tabDisplayName, new Consumer<VcsErrorViewPanel>() {
public void consume(VcsErrorViewPanel vcsErrorViewPanel) {
addDirectMessages(vcsErrorViewPanel, abstractVcsExceptions);
}
});
}
@Override
public boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) {
return CommitChangeListDialog.commitChanges(myProject, changes, initialChangeList,
CommitChangeListDialog.collectExecutors(myProject, changes), true, commitMessage,
customResultHandler);
}
private static void addDirectMessages(VcsErrorViewPanel vcsErrorViewPanel, List<VcsException> abstractVcsExceptions) {
for (final VcsException exception : abstractVcsExceptions) {
String[] messages = getExceptionMessages(exception);
vcsErrorViewPanel.addMessage(getErrorCategory(exception), messages, exception.getVirtualFile(), -1, -1, null);
}
}
private static String[] getExceptionMessages(VcsException exception) {
String[] messages = exception.getMessages();
if (messages.length == 0) messages = new String[]{VcsBundle.message("exception.text.unknown.error")};
final List<String> list = new ArrayList<String>();
for (String message : messages) {
list.addAll(StringUtil.split(StringUtil.convertLineSeparators(message), "\n"));
}
return ArrayUtil.toStringArray(list);
}
private void showErrorsImpl(final boolean isEmpty, final Getter<VcsException> firstGetter, @NotNull final String tabDisplayName,
final Consumer<VcsErrorViewPanel> viewFiller) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
if (!isEmpty) {
VcsException exception = firstGetter.get();
if (!handleCustom(exception)) {
throw new RuntimeException(exception);
}
}
return;
}
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (myProject.isDisposed()) return;
if (isEmpty) {
removeContents(null, tabDisplayName);
return;
}
final VcsErrorViewPanel errorTreeView = new VcsErrorViewPanel(myProject);
openMessagesView(errorTreeView, tabDisplayName);
viewFiller.consume(errorTreeView);
}
});
}
public boolean handleCustom(VcsException exception) {
if (myCustomHandler != null) {
myCustomHandler.consume(exception);
return true;
}
return false;
}
@Override
public void showErrors(final Map<HotfixData, List<VcsException>> exceptionGroups, @NotNull final String tabDisplayName) {
showErrorsImpl(exceptionGroups.isEmpty(), new Getter<VcsException>() {
public VcsException get() {
final List<VcsException> exceptionList = exceptionGroups.values().iterator().next();
return exceptionList == null ? null : (exceptionList.isEmpty() ? null : exceptionList.get(0));
}
}, tabDisplayName, new Consumer<VcsErrorViewPanel>() {
public void consume(VcsErrorViewPanel vcsErrorViewPanel) {
for (Map.Entry<HotfixData, List<VcsException>> entry : exceptionGroups.entrySet()) {
if (entry.getKey() == null) {
addDirectMessages(vcsErrorViewPanel, entry.getValue());
} else {
final List<VcsException> exceptionList = entry.getValue();
final List<SimpleErrorData> list = new ArrayList<SimpleErrorData>(exceptionList.size());
for (VcsException exception : exceptionList) {
final String[] messages = getExceptionMessages(exception);
list.add(new SimpleErrorData(
ErrorTreeElementKind.convertMessageFromCompilerErrorType(getErrorCategory(exception)), messages, exception.getVirtualFile()));
}
vcsErrorViewPanel.addHotfixGroup(entry.getKey(), list);
}
}
}
});
}
private static int getErrorCategory(VcsException exception) {
if (exception.isWarning()) {
return MessageCategory.WARNING;
}
else {
return MessageCategory.ERROR;
}
}
protected void removeContents(Content notToRemove, final String tabDisplayName) {
MessageView messageView = MessageView.SERVICE.getInstance(myProject);
Content[] contents = messageView.getContentManager().getContents();
for (Content content : contents) {
LOG.assertTrue(content != null);
if (content.isPinned()) continue;
if (tabDisplayName.equals(content.getDisplayName()) && content != notToRemove) {
ErrorTreeView listErrorView = (ErrorTreeView)content.getComponent();
if (listErrorView != null) {
if (messageView.getContentManager().removeContent(content, true)) {
content.release();
}
}
}
}
}
public List<VcsException> runTransactionRunnable(AbstractVcs vcs, TransactionRunnable runnable, Object vcsParameters) {
List<VcsException> exceptions = new ArrayList<VcsException>();
TransactionProvider transactionProvider = vcs.getTransactionProvider();
boolean transactionSupported = transactionProvider != null;
if (transactionSupported) {
try {
transactionProvider.startTransaction(vcsParameters);
}
catch (VcsException e) {
return Collections.singletonList(e);
}
}
runnable.run(exceptions);
if (transactionSupported) {
if (exceptions.isEmpty()) {
try {
transactionProvider.commitTransaction(vcsParameters);
}
catch (VcsException e) {
exceptions.add(e);
transactionProvider.rollbackTransaction(vcsParameters);
}
}
else {
transactionProvider.rollbackTransaction(vcsParameters);
}
}
return exceptions;
}
public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs) {
OpenFileDescriptor openFileDescriptor = new OpenFileDescriptor(myProject, file);
Editor editor = FileEditorManager.getInstance(myProject).openTextEditor(openFileDescriptor, true);
if (editor == null) {
Messages.showMessageDialog(VcsBundle.message("message.text.cannot.open.editor", file.getPresentableUrl()),
VcsBundle.message("message.title.cannot.open.editor"), Messages.getInformationIcon());
return;
}
AnnotateToggleAction.doAnnotate(editor, myProject, file, annotation, vcs, false);
}
public void showDifferences(final VcsFileRevision version1, final VcsFileRevision version2, final File file) {
try {
final byte[] byteContent1 = VcsHistoryUtil.loadRevisionContent(version1);
final byte[] byteContent2 = VcsHistoryUtil.loadRevisionContent(version2);
if (Comparing.equal(byteContent1, byteContent2)) {
Messages.showInfoMessage(VcsBundle.message("message.text.versions.are.identical"), VcsBundle.message("message.title.diff"));
}
final SimpleDiffRequest request = new SimpleDiffRequest(myProject, file.getAbsolutePath());
final FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(file.getName());
if (fileType.isBinary()) {
Messages.showInfoMessage(VcsBundle.message("message.text.binary.versions.differ"), VcsBundle.message("message.title.diff"));
return;
}
final DiffContent content1 = getContentForVersion(version1, file);
final DiffContent content2 = getContentForVersion(version2, file);
if (version2.getRevisionNumber().compareTo(version1.getRevisionNumber()) > 0) {
request.setContents(content2, content1);
request.setContentTitles(version2.getRevisionNumber().asString(), version1.getRevisionNumber().asString());
}
else {
request.setContents(content1, content2);
request.setContentTitles(version1.getRevisionNumber().asString(), version2.getRevisionNumber().asString());
}
DiffManager.getInstance().getDiffTool().show(request);
}
catch (VcsException e) {
showError(e, VcsBundle.message("message.title.diff"));
}
catch (IOException e) {
showError(new VcsException(e), VcsBundle.message("message.title.diff"));
}
}
public void showChangesBrowser(List<CommittedChangeList> changelists) {
showChangesBrowser(changelists, null);
}
public void showChangesBrowser(List<CommittedChangeList> changelists, @Nls String title) {
showChangesBrowser(new CommittedChangesTableModel(changelists, false), title, false, null);
}
private ChangesBrowserDialog createChangesBrowserDialog(CommittedChangesTableModel changelists,
String title,
boolean showSearchAgain,
@Nullable final Component parent, Consumer<ChangesBrowserDialog> initRunnable) {
final ChangesBrowserDialog.Mode mode = showSearchAgain ? ChangesBrowserDialog.Mode.Browse : ChangesBrowserDialog.Mode.Simple;
final ChangesBrowserDialog dlg = parent != null
? new ChangesBrowserDialog(myProject, parent, changelists, mode, initRunnable)
: new ChangesBrowserDialog(myProject, changelists, mode, initRunnable);
if (title != null) {
dlg.setTitle(title);
}
return dlg;
}
private void showChangesBrowser(CommittedChangesTableModel changelists,
String title,
boolean showSearchAgain,
@Nullable final Component parent) {
final ChangesBrowserDialog.Mode mode = showSearchAgain ? ChangesBrowserDialog.Mode.Browse : ChangesBrowserDialog.Mode.Simple;
final ChangesBrowserDialog dlg = parent != null
? new ChangesBrowserDialog(myProject, parent, changelists, mode, null)
: new ChangesBrowserDialog(myProject, changelists, mode, null);
if (title != null) {
dlg.setTitle(title);
}
dlg.show();
}
@Override
public void showChangesListBrowser(CommittedChangeList changelist, @Nullable VirtualFile toSelect, @Nls String title) {
final ChangeListViewerDialog dlg = new ChangeListViewerDialog(myProject, changelist, toSelect);
if (title != null) {
dlg.setTitle(title);
}
dlg.show();
}
public void showChangesListBrowser(CommittedChangeList changelist, @Nls String title) {
showChangesListBrowser(changelist, null, title);
}
public void showWhatDiffersBrowser(final Component parent, final Collection<Change> changes, @Nls final String title) {
final ChangeListViewerDialog dlg;
if (parent != null) {
dlg = new ChangeListViewerDialog(parent, myProject, changes, false);
}
else {
dlg = new ChangeListViewerDialog(myProject, changes, false);
}
if (title != null) {
dlg.setTitle(title);
}
dlg.show();
}
public void showChangesBrowser(final CommittedChangesProvider provider,
final RepositoryLocation location,
@Nls String title,
Component parent) {
final ChangesBrowserSettingsEditor filterUI = provider.createFilterUI(true);
ChangeBrowserSettings settings = provider.createDefaultSettings();
boolean ok;
if (filterUI != null) {
final CommittedChangesFilterDialog dlg = new CommittedChangesFilterDialog(myProject, filterUI, settings);
dlg.show();
ok = dlg.getExitCode() == DialogWrapper.OK_EXIT_CODE;
settings = dlg.getSettings();
}
else {
ok = true;
}
if (ok) {
if (myProject.isDefault() || (ProjectLevelVcsManager.getInstance(myProject).getAllActiveVcss().length == 0) ||
(! ModalityState.NON_MODAL.equals(ModalityState.current()))) {
final List<CommittedChangeList> versions = new ArrayList<CommittedChangeList>();
if (parent == null || !parent.isValid()) {
parent = WindowManager.getInstance().suggestParentWindow(myProject);
}
final CommittedChangesTableModel model = new CommittedChangesTableModel(versions, true);
final AsynchronousListsLoader[] task = new AsynchronousListsLoader[1];
final ChangeBrowserSettings finalSettings = settings;
final ChangesBrowserDialog dlg = createChangesBrowserDialog(model, title, filterUI != null, parent, new Consumer<ChangesBrowserDialog>() {
@Override
public void consume(ChangesBrowserDialog changesBrowserDialog) {
task[0] = new AsynchronousListsLoader(myProject, provider, location, finalSettings, changesBrowserDialog);
ProgressManager.getInstance().run(task[0]);
}
});
dlg.startLoading();
dlg.show();
if (task[0] != null) {
task[0].cancel();
final List<VcsException> exceptions = task[0].getExceptions();
if (! exceptions.isEmpty()) {
Messages.showErrorDialog(myProject, VcsBundle.message("browse.changes.error.message", exceptions.get(0).getMessage()),
VcsBundle.message("browse.changes.error.title"));
return;
}
if (! task[0].isRevisionsReturned()) {
Messages.showInfoMessage(myProject, VcsBundle.message("browse.changes.nothing.found"),
VcsBundle.message("browse.changes.nothing.found.title"));
}
}
}
else {
openCommittedChangesTab(provider, location, settings, 0, title);
}
}
}
@Nullable
public <T extends CommittedChangeList, U extends ChangeBrowserSettings> T chooseCommittedChangeList(@NotNull CommittedChangesProvider<T, U> provider,
RepositoryLocation location) {
final List<T> changes;
try {
changes = provider.getCommittedChanges(provider.createDefaultSettings(), location, 0);
}
catch (VcsException e) {
return null;
}
final ChangesBrowserDialog dlg = new ChangesBrowserDialog(myProject, new CommittedChangesTableModel((List<CommittedChangeList>)changes,
provider.getColumns(), false),
ChangesBrowserDialog.Mode.Choose, null);
dlg.show();
if (dlg.isOK()) {
return (T)dlg.getSelectedChangeList();
}
else {
return null;
}
}
@Override
@NotNull
public List<VirtualFile> showMergeDialog(List<VirtualFile> files, MergeProvider provider, @NotNull MergeDialogCustomizer mergeDialogCustomizer) {
if (files.isEmpty()) return Collections.emptyList();
final MultipleFileMergeDialog fileMergeDialog = new MultipleFileMergeDialog(myProject, files, provider, mergeDialogCustomizer);
fileMergeDialog.show();
return fileMergeDialog.getProcessedFiles();
}
private static DiffContent getContentForVersion(final VcsFileRevision version, final File file) throws IOException, VcsException {
VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file);
if (vFile != null && (version instanceof CurrentRevision) && !vFile.getFileType().isBinary()) {
return new DocumentContent(FileDocumentManager.getInstance().getDocument(vFile), vFile.getFileType());
}
else {
return new SimpleContent(VcsHistoryUtil.loadRevisionContentGuessEncoding(version, vFile, null),
FileTypeManager.getInstance().getFileTypeByFileName(file.getName()));
}
}
public void openCommittedChangesTab(final AbstractVcs vcs,
final VirtualFile root,
final ChangeBrowserSettings settings,
final int maxCount,
String title) {
final RepositoryLocation location = CommittedChangesCache.getInstance(myProject).getLocationCache().getLocation(vcs, new FilePathImpl(root),
false);
openCommittedChangesTab(vcs.getCommittedChangesProvider(), location, settings, maxCount, title);
}
public void openCommittedChangesTab(final CommittedChangesProvider provider,
final RepositoryLocation location,
final ChangeBrowserSettings settings,
final int maxCount,
String title) {
DefaultActionGroup extraActions = new DefaultActionGroup();
CommittedChangesPanel panel = new CommittedChangesPanel(myProject, provider, settings, location, extraActions);
panel.setMaxCount(maxCount);
panel.refreshChanges(false);
final ContentFactory factory = ContentFactory.SERVICE.getInstance();
if (title == null && location != null) {
title = VcsBundle.message("browse.changes.content.title", location.toPresentableString());
}
final Content content = factory.createContent(panel, title, false);
final ChangesViewContentI contentManager = ChangesViewContentManager.getInstance(myProject);
contentManager.addContent(content);
contentManager.setSelectedContent(content);
extraActions.add(new CloseTabToolbarAction() {
public void actionPerformed(final AnActionEvent e) {
contentManager.removeContent(content);
}
});
ToolWindow window = ToolWindowManager.getInstance(myProject).getToolWindow(ChangesViewContentManager.TOOLWINDOW_ID);
if (!window.isVisible()) {
window.activate(null);
}
}
private static class AsynchronousListsLoader extends Task.Backgroundable {
private final CommittedChangesProvider myProvider;
private final RepositoryLocation myLocation;
private final ChangeBrowserSettings mySettings;
private final ChangesBrowserDialog myDlg;
private final List<VcsException> myExceptions;
private volatile boolean myCanceled;
private boolean myRevisionsReturned;
private AsynchronousListsLoader(@Nullable Project project, final CommittedChangesProvider provider,
final RepositoryLocation location, final ChangeBrowserSettings settings, final ChangesBrowserDialog dlg) {
super(project, VcsBundle.message("browse.changes.progress.title"), true, BackgroundFromStartOption.getInstance());
myProvider = provider;
myLocation = location;
mySettings = settings;
myDlg = dlg;
myExceptions = new LinkedList<VcsException>();
}
public void cancel() {
myCanceled = true;
}
public void run(@NotNull final ProgressIndicator indicator) {
final AsynchConsumer<List<CommittedChangeList>> appender = myDlg.getAppender();
final BufferedListConsumer<CommittedChangeList> bufferedListConsumer = new BufferedListConsumer<CommittedChangeList>(10, appender, -1);
final Application application = ApplicationManager.getApplication();
try {
myProvider.loadCommittedChanges(mySettings, myLocation, 0, new AsynchConsumer<CommittedChangeList>() {
public void consume(CommittedChangeList committedChangeList) {
myRevisionsReturned = true;
bufferedListConsumer.consumeOne(committedChangeList);
if (myCanceled) {
indicator.cancel();
}
}
public void finished() {
bufferedListConsumer.flush();
appender.finished();
if (! myRevisionsReturned) {
application.invokeLater(new Runnable() {
public void run() {
myDlg.close(-1);
}
}, ModalityState.stateForComponent(myDlg.getWindow()));
}
}
});
}
catch (VcsException e) {
myExceptions.add(e);
application.invokeLater(new Runnable() {
public void run() {
myDlg.close(-1);
}
}, ModalityState.stateForComponent(myDlg.getWindow()));
}
}
public List<VcsException> getExceptions() {
return myExceptions;
}
public boolean isRevisionsReturned() {
return myRevisionsReturned;
}
}
@TestOnly
public static void setCustomExceptionHandler(Project project, Consumer<VcsException> customHandler) {
((AbstractVcsHelperImpl)getInstance(project)).myCustomHandler = customHandler;
}
}