fix for IDEA-81304 "Show history for selection" for Subversion is not working!

(exception reporting + correct revisions preload)
This commit is contained in:
irengrig
2012-02-17 18:37:20 +04:00
parent a03489930b
commit a2f4e05bb4
5 changed files with 113 additions and 33 deletions
@@ -32,6 +32,7 @@ import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.WaitForProgressToShow;
import com.intellij.vcsUtil.VcsSelection;
import com.intellij.vcsUtil.VcsSelectionUtil;
@@ -77,11 +78,15 @@ public class SelectedBlockHistoryAction extends AbstractVcsAction {
final int selectionStart = selection.getSelectionStartLineNumber();
final int selectionEnd = selection.getSelectionEndLineNumber();
final VcsException[] preloadException = new VcsException[1];
final CachedRevisionsContents cachedRevisionsContents = new CachedRevisionsContents(project, file);
new VcsHistoryProviderBackgroundableProxy(activeVcs, provider, activeVcs.getDiffProvider()).
createSessionFor(activeVcs.getKeyInstanceMethod(), new FilePathImpl(file),
new Consumer<VcsHistorySession>() {
public void consume(VcsHistorySession session) {
if (preloadException[0] != null) {
reportError(preloadException[0]);
}
if (session == null) return;
final VcsHistoryDialog vcsHistoryDialog =
new VcsHistoryDialog(project,
@@ -103,7 +108,12 @@ public class SelectedBlockHistoryAction extends AbstractVcsAction {
cachedRevisionsContents.setRevisions(revisionList);
if (VcsConfiguration.getInstance(project).SHOW_ONLY_CHANGED_IN_SELECTION_DIFF) {
// preload while in bckgrnd
cachedRevisionsContents.loadContentsFor(revisionList.toArray(new VcsFileRevision[revisionList.size()]));
try {
cachedRevisionsContents.loadContentsFor(revisionList.toArray(new VcsFileRevision[revisionList.size()]));
}
catch (VcsException e) {
preloadException[0] = e;
}
}
}
});
@@ -64,7 +64,7 @@ public class VcsHistoryUtil {
}
}
private static int compareNumbers(VcsFileRevision first, VcsFileRevision second) {
public static int compareNumbers(VcsFileRevision first, VcsFileRevision second) {
return first.getRevisionNumber().compareTo(second.getRevisionNumber());
}
@@ -42,7 +42,7 @@ import java.util.*;
*/
public class CachedRevisionsContents {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.history.impl.CachedRevisionsContents");
private final Map<VcsRevisionNumber, String> myCachedContents = new HashMap<VcsRevisionNumber, String>();
private final Map<VcsRevisionNumber, String> myCachedContents;
private final Project myProject;
// managed outside, for reference here
private List<VcsFileRevision> myRevisions;
@@ -51,13 +51,14 @@ public class CachedRevisionsContents {
public CachedRevisionsContents(final Project project, final VirtualFile file) {
myProject = project;
myFile = file;
myCachedContents = Collections.synchronizedMap(new HashMap<VcsRevisionNumber, String>());
}
public void setRevisions(List<VcsFileRevision> revisions) {
myRevisions = revisions;
}
public void loadContentsFor(final VcsFileRevision[] revisions) {
public void loadContentsFor(final VcsFileRevision[] revisions) throws VcsException {
final VcsFileRevision[] revisionsToLoad = revisionsNeededToBeLoaded(revisions);
final List<VcsFileRevision> toBeLoaded = new LinkedList<VcsFileRevision>();
@@ -67,6 +68,7 @@ public class CachedRevisionsContents {
}
if (toBeLoaded.isEmpty()) return;
final VcsException[] exception = new VcsException[1];
final Runnable process = new Runnable() {
public void run() {
ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
@@ -91,19 +93,17 @@ public class CachedRevisionsContents {
vcsFileRevision.loadContent();
}
catch (final VcsException e) {
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
public void run() {
Messages.showErrorDialog(VcsBundle.message("message.text.cannot.load.version.because.of.error",
vcsFileRevision.getRevisionNumber(), e.getLocalizedMessage()),
VcsBundle.message("message.title.load.version"));
}
}, null, myProject);
exception[0] = new VcsException(e);
LOG.info(e);
return;
}
catch (ProcessCanceledException ex) {
return;
}
catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
exception[0] = new VcsException(e);
LOG.info(e);
return;
}
String content = null;
try {
@@ -113,13 +113,16 @@ public class CachedRevisionsContents {
}
}
catch (IOException e) {
exception[0] = new VcsException(e);
LOG.info(e);
return;
}
catch (VcsException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
exception[0] = new VcsException(e);
LOG.info(e);
return;
}
myCachedContents.put(vcsFileRevision.getRevisionNumber(), content);
}
}
}
@@ -136,9 +139,12 @@ public class CachedRevisionsContents {
} else {
process.run();
}
if (exception[0] != null) {
throw exception[0];
}
}
public String getContentOf(VcsFileRevision revision) {
public String getContentOf(VcsFileRevision revision) throws VcsException {
if (! myCachedContents.containsKey(revision.getRevisionNumber())) {
loadContentsFor(new VcsFileRevision[]{revision});
}
@@ -157,7 +163,7 @@ public class CachedRevisionsContents {
private Collection<VcsFileRevision> collectRevisionsFromFirstTo(VcsFileRevision revision) {
ArrayList<VcsFileRevision> result = new ArrayList<VcsFileRevision>();
for (VcsFileRevision vcsFileRevision : myRevisions) {
if (VcsHistoryUtil.compare(revision, vcsFileRevision) > 0) continue;
if (VcsHistoryUtil.compareNumbers(revision, vcsFileRevision) > 0) continue;
result.add(vcsFileRevision);
}
return result;
@@ -20,6 +20,7 @@ import com.intellij.diff.FindBlock;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.DiffManager;
import com.intellij.openapi.diff.DiffPanel;
@@ -29,12 +30,11 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.history.*;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.table.TableView;
@@ -61,6 +61,7 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
private final int mySelectionStart;
private final int mySelectionEnd;
// todo equals???
private final Map<VcsFileRevision, Block> myRevisionToContentMap = new com.intellij.util.containers.HashMap<VcsFileRevision, Block>();
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.history.impl.VcsHistoryDialog");
@@ -173,11 +174,11 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
});
myList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
final ListSelectionListener selectionListener = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
final VcsFileRevision revision;
if (myList.getSelectedRowCount() == 1) {
revision = (VcsFileRevision) myList.getItems().get(myList.getSelectedRow());
if (myList.getSelectedRowCount() == 1 && !myList.isEmpty()) {
revision = (VcsFileRevision)myList.getItems().get(myList.getSelectedRow());
myComments.setText(revision.getCommitMessage());
myComments.setCaretPosition(0);
}
@@ -190,21 +191,34 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
}
updateDiff();
}
});
};
myList.getSelectionModel().addListSelectionListener(selectionListener);
myChangesOnlyCheckBox.setSelected(configuration.SHOW_ONLY_CHANGED_IN_SELECTION_DIFF);
updateRevisionsList();
try {
updateRevisionsList();
}
catch (final VcsException e) {
// todo test it, always exception
canNotLoadRevisionMessage(e);
}
myChangesOnlyCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
configuration.SHOW_ONLY_CHANGED_IN_SELECTION_DIFF = myChangesOnlyCheckBox.isSelected();
updateRevisionsList();
try {
updateRevisionsList();
}
catch (VcsException e1) {
canNotLoadRevisionMessage(e1);
}
}
});
init();
ApplicationManager.getApplication().invokeLater(new Runnable() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (! VcsHistoryDialog.this.isShowing()) return;
myList.getSelectionModel().addSelectionInterval(0, 0);
}
});
@@ -212,6 +226,21 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
setTitle(VcsBundle.message("dialog.title.history.for.file", file.getName()));
}
private void canNotLoadRevisionMessage(final VcsException e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (! VcsHistoryDialog.this.isShowing()) return;
VcsBalloonProblemNotifier.showBalloonForComponent(VcsHistoryDialog.this.getRootPane(),
canNoLoadMessage(e), MessageType.ERROR, true);
}
});
}
private String canNoLoadMessage(VcsException e) {
return "Can not load revision contents: " + e.getMessage();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myList;
@@ -235,15 +264,15 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
return result;
}
protected String getContentOf(VcsFileRevision revision) {
protected String getContentOf(VcsFileRevision revision) throws VcsException {
return myCachedContents.getContentOf(revision);
}
private void loadContentsFor(final VcsFileRevision[] revisions) {
private void loadContentsFor(final VcsFileRevision[] revisions) throws VcsException {
myCachedContents.loadContentsFor(revisions);
}
private void updateRevisionsList() {
private void updateRevisionsList() throws VcsException {
if (myIsInLoading) return;
if (myChangesOnlyCheckBox.isSelected()) {
loadContentsFor(myRevisions.toArray(new VcsFileRevision[myRevisions.size()]));
@@ -267,7 +296,7 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
}
private List<VcsFileRevision> filteredRevisions() throws FilesTooBigForDiffException {
private List<VcsFileRevision> filteredRevisions() throws FilesTooBigForDiffException, VcsException {
ArrayList<VcsFileRevision> result = new ArrayList<VcsFileRevision>();
VcsFileRevision nextRevision = myRevisions.get(myRevisions.size() - 1);
result.add(nextRevision);
@@ -282,6 +311,7 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
}
private synchronized void updateDiff() {
if (myList.isEmpty()) return;
int[] selectedIndices = myList.getSelectedRows();
if (selectedIndices.length == 0) {
updateDiff(CURRENT, CURRENT);
@@ -314,6 +344,12 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
catch (FilesTooBigForDiffException e) {
myDiffPanel.setTooBigFileErrorContents();
}
catch (VcsException e) {
final String text = canNoLoadMessage(e);
myDiffPanel.setContents(new SimpleContent(text, myContentFileType),
new SimpleContent(text, myContentFileType));
canNotLoadRevisionMessage(e);
}
myDiffPanel.setTitle1(VcsBundle.message("diff.content.title.revision.number", firstRev.getRevisionNumber()));
myDiffPanel.setTitle2(VcsBundle.message("diff.content.title.revision.number", secondRev.getRevisionNumber()));
@@ -414,14 +450,14 @@ public class VcsHistoryDialog extends DialogWrapper implements DataProvider {
return null;
}
protected String getContentToShow(VcsFileRevision revision) throws FilesTooBigForDiffException {
protected String getContentToShow(VcsFileRevision revision) throws FilesTooBigForDiffException, VcsException {
final Block block = getBlock(revision);
if (block == null) return "";
return block.getBlockContent();
}
@Nullable
private Block getBlock(VcsFileRevision revision) throws FilesTooBigForDiffException {
private Block getBlock(VcsFileRevision revision) throws FilesTooBigForDiffException, VcsException {
if (myRevisionToContentMap.containsKey(revision))
return myRevisionToContentMap.get(revision);
@@ -20,9 +20,17 @@ import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
import com.intellij.ui.awt.RelativePoint;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.TimeUnit;
/**
* Shows a notification balloon over one of version control related tool windows: Changes View or Version Control View.
* By default the notification is shown over the Changes View.
@@ -74,4 +82,24 @@ public class VcsBalloonProblemNotifier implements Runnable {
public void run() {
NOTIFICATION_GROUP.createNotification(myMessage, myMessageType).notify(myProject.isDefault() ? null : myProject);
}
public static void showBalloonForComponent(@NotNull JComponent component, @NotNull final String message, final MessageType type,
final boolean atTop) {
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(message, type, null);
Balloon balloon = balloonBuilder.createBalloon();
Dimension size = component.getSize();
Balloon.Position position;
int x;
int y;
if (size == null) {
x = y = 0;
position = Balloon.Position.above;
}
else {
x = Math.min(10, size.width / 2);
y = size.height;
position = Balloon.Position.below;
}
balloon.show(new RelativePoint(component, new Point(x, y)), position);
}
}