diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index b108be276009..8159317c76df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -235,7 +235,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid ((EditorGutterComponentEx) getEditor2().getGutter()).setLineNumberConvertor(newConvertor); } } - + // todo pay attention here private static DiffHighlighterFactory createHighlighter(FileType contentType, VirtualFile file, Project project) { return new DiffHighlighterFactoryImpl(contentType, file, project); } @@ -307,8 +307,11 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } private void updateStatusBar() { - int differentLineBlocks = getLineBlocks().getCount(); - myPanel.setStatusBarText(DiffBundle.message("diff.count.differences.status.text", differentLineBlocks)); + myPanel.setStatusBarText(getNumDifferencesText()); + } + + public String getNumDifferencesText() { + return DiffBundle.message("diff.count.differences.status.text", getLineBlocks().getCount()); } public boolean hasDifferences() { @@ -416,7 +419,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid return getSideView(side).getEditor(); } - private DiffSideView getSideView(FragmentSide side) { + public DiffSideView getSideView(FragmentSide side) { if (side == FragmentSide.SIDE1) { return myLeftSide; } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/FragmentNumberGutterIconRenderer.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/FragmentNumberGutterIconRenderer.java index ce5190886005..ae93199a17f3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/FragmentNumberGutterIconRenderer.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/FragmentNumberGutterIconRenderer.java @@ -16,15 +16,15 @@ import java.awt.*; * Time: 3:12 PM */ public class FragmentNumberGutterIconRenderer extends GutterIconRenderer { - private final int myNumber; + private final String myPresentation; private CaptionIcon myIcon; - public FragmentNumberGutterIconRenderer(int number, final TextAttributesKey key, final Component component) { - myNumber = number; + public FragmentNumberGutterIconRenderer(String presentation, final TextAttributesKey key, final Component component) { + myPresentation = presentation; final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme(); final Color color = globalScheme.getAttributes(key).getBackgroundColor(); - myIcon = new CaptionIcon(color, UIUtil.getButtonFont(), String.valueOf(number), component, CaptionIcon.Form.ROUNDED, false, false); + myIcon = new CaptionIcon(color, UIUtil.getButtonFont(), presentation, component, CaptionIcon.Form.ROUNDED, false, false); } @NotNull @@ -40,13 +40,13 @@ public class FragmentNumberGutterIconRenderer extends GutterIconRenderer { FragmentNumberGutterIconRenderer that = (FragmentNumberGutterIconRenderer)o; - if (myNumber != that.myNumber) return false; + if (!myPresentation.equals(that.myPresentation)) return false; return true; } @Override public int hashCode() { - return myNumber; + return myPresentation.hashCode(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java index 902e0ac47753..639d14a318df 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/FragmentedDiffPanelState.java @@ -58,6 +58,8 @@ public class FragmentedDiffPanelState extends DiffPanelState { } private LineBlocks addMarkup(final List lines) { + myFragmentHighlighter.precalculateNumbers(lines); + for (Iterator iterator = lines.iterator(); iterator.hasNext();) { LineFragment line = iterator.next(); myFragmentHighlighter.setIsLast(!iterator.hasNext()); @@ -126,4 +128,12 @@ public class FragmentedDiffPanelState extends DiffPanelState { } myRanges.addAll(ranges); } + + public List getLeftLines() { + return myFragmentHighlighter.getLeftLines(); + } + + public List getRightLines() { + return myFragmentHighlighter.getRightLines(); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/NumberedFragmentHighlighter.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/NumberedFragmentHighlighter.java index 172e3dcbf7a4..a3f31eb50a91 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/NumberedFragmentHighlighter.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/highlighting/NumberedFragmentHighlighter.java @@ -4,9 +4,14 @@ import com.intellij.openapi.diff.DiffColors; import com.intellij.openapi.diff.impl.FragmentNumberGutterIconRenderer; import com.intellij.openapi.diff.impl.fragments.Fragment; import com.intellij.openapi.diff.impl.fragments.FragmentHighlighterImpl; +import com.intellij.openapi.diff.impl.fragments.LineFragment; import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum; import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.editor.markup.GutterIconRenderer; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.TextRange; +import com.intellij.util.containers.MultiMap; + +import java.util.*; /** * @author irengrig @@ -15,23 +20,18 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer; */ public class NumberedFragmentHighlighter extends FragmentHighlighterImpl { private final boolean myDrawNumber; - private int myCounter; + private final Map> myLeftPrecalculated; + private final Map> myRightPrecalculated; + private int myPreviousLineLeft; + private int myPreviousLineRight; public NumberedFragmentHighlighter(DiffMarkup appender1, DiffMarkup appender2, boolean drawNumber) { super(appender1, appender2); myDrawNumber = drawNumber; - myCounter = 0; - } - - private GutterIconRenderer createRenderer(Fragment fragment) { - final TextAttributesKey key = getColorAttributesKey(fragment.getType()); - if (key != null) { - final FragmentNumberGutterIconRenderer renderer = - new FragmentNumberGutterIconRenderer(myCounter + 1, key, myAppender1.getEditor().getScrollPane()); - ++ myCounter; - return renderer; - } - return null; + myLeftPrecalculated = new HashMap>(); + myRightPrecalculated = new HashMap>(); + myPreviousLineLeft = -1; + myPreviousLineRight = -1; } private TextAttributesKey getColorAttributesKey(final TextDiffTypeEnum textDiffTypeEnum) { @@ -50,13 +50,103 @@ public class NumberedFragmentHighlighter extends FragmentHighlighterImpl { @Override protected void highlightFragmentImpl(Fragment fragment, boolean drawBorder) { - final GutterIconRenderer renderer = myDrawNumber ? createRenderer(fragment) : null; + if (! myDrawNumber || fragment.getType() == null || TextDiffTypeEnum.NONE.equals(fragment.getType())) { + myAppender1.highlightText(fragment, drawBorder, null); + myAppender2.highlightText(fragment, drawBorder, null); + return; + } + int lineLeft = myAppender1.getDocument().getLineNumber(fragment.getRange(FragmentSide.SIDE1).getStartOffset()); + int lineRight = myAppender2.getDocument().getLineNumber(fragment.getRange(FragmentSide.SIDE2).getStartOffset()); + Pair left = myLeftPrecalculated.get(lineLeft); + if (myPreviousLineLeft == lineLeft || left == null) { + myAppender1.highlightText(fragment, drawBorder, null); + } else { + myAppender1.highlightText(fragment, drawBorder, new FragmentNumberGutterIconRenderer(left.getFirst(), getColorAttributesKey(left.getSecond()), myAppender1.getEditor().getScrollPane())); + myPreviousLineLeft = lineLeft; + } - myAppender1.highlightText(fragment, drawBorder, renderer); - myAppender2.highlightText(fragment, drawBorder, renderer); + Pair right = myLeftPrecalculated.get(lineRight); + if (myPreviousLineRight == lineRight || right == null) { + myAppender2.highlightText(fragment, drawBorder, null); + } else { + myAppender2.highlightText(fragment, drawBorder, new FragmentNumberGutterIconRenderer(right.getFirst(), getColorAttributesKey(right.getSecond()), myAppender1.getEditor().getScrollPane())); + myPreviousLineRight = lineRight; + } } public void reset() { - myCounter = 0; + myLeftPrecalculated.clear(); + myRightPrecalculated.clear(); + myPreviousLineLeft = -1; + myPreviousLineRight = -1; + } + + public void precalculateNumbers(List lines) { + final MultiMap> leftMap = new MultiMap>(); + final MultiMap> rightMap = new MultiMap>(); + + int cnt = 1; + for (LineFragment line : lines) { + if (line.getType() == null || TextDiffTypeEnum.NONE.equals(line.getType())) continue; + + final Iterator iterator = line.getChildrenIterator(); + if (iterator == null) continue; + while (iterator.hasNext()) { + final Fragment next = iterator.next(); + if (next.getType() == null || TextDiffTypeEnum.NONE.equals(next.getType())) continue; + + TextRange left = next.getRange(FragmentSide.SIDE1); + TextRange right = next.getRange(FragmentSide.SIDE2); + + leftMap.putValue(myAppender1.getDocument().getLineNumber(left.getStartOffset()), new Pair(cnt, next.getType())); + rightMap.putValue(myAppender2.getDocument().getLineNumber(right.getStartOffset()), new Pair(cnt, next.getType())); + ++ cnt; + } + } + + // merge + merge(leftMap, myLeftPrecalculated); + merge(rightMap, myRightPrecalculated); + } + + private void merge(MultiMap> leftMap, + final Map> whereTo) { + for (Map.Entry>> entry : leftMap.entrySet()) { + List> value = (List>) entry.getValue(); + if (value.size() > 1) { + Pair pair1 = value.iterator().next(); + Pair pair2 = value.get(value.size() - 1); + TextDiffTypeEnum type = mergeDiffType(value); + whereTo.put(entry.getKey(), new Pair(String.valueOf(pair1.getFirst()) + "-" + + String.valueOf(pair2.getFirst()), type)); + } else { + Pair pair = value.iterator().next(); + whereTo.put(entry.getKey(), new Pair(String.valueOf(pair.getFirst()), pair.getSecond())); + } + } + } + + private TextDiffTypeEnum mergeDiffType(List> value) { + TextDiffTypeEnum previous = null; + for (Pair pair : value) { + if (previous == null) { + previous = pair.getSecond(); + continue; + } + if (! previous.equals(pair.getSecond())) return TextDiffTypeEnum.CHANGED; + } + return previous; + } + + public List getLeftLines() { + List list = new ArrayList(myLeftPrecalculated.keySet()); + Collections.sort(list); + return list; + } + + public List getRightLines() { + List list = new ArrayList(myRightPrecalculated.keySet()); + Collections.sort(list); + return list; } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java index 792ca5bb5dd8..73e3d99dc089 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java @@ -24,12 +24,11 @@ import com.intellij.openapi.diff.SimpleContent; import com.intellij.openapi.diff.ex.DiffPanelEx; import com.intellij.openapi.diff.ex.DiffPanelOptions; import com.intellij.openapi.diff.impl.DiffPanelImpl; +import com.intellij.openapi.diff.impl.DiffSideView; import com.intellij.openapi.diff.impl.highlighting.DiffPanelState; +import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.highlighting.FragmentedDiffPanelState; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.LogicalPosition; -import com.intellij.openapi.editor.ScrollingModel; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.VisibleAreaEvent; import com.intellij.openapi.editor.event.VisibleAreaListener; import com.intellij.openapi.editor.ex.EditorEx; @@ -48,11 +47,13 @@ import com.intellij.util.BeforeAfter; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.ButtonlessScrollBarUI; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; +import java.awt.event.MouseEvent; import java.util.*; import java.util.List; @@ -74,8 +75,11 @@ public class ChangesFragmentedDiffPanel implements Disposable { private DiffPanel myVertical; private boolean myCurrentHorizontal; private JPanel myTopPanel; + private List myLeftLines; + private List myRightLines; + private final MyNextDiffAction myNextDiff; + private final MyPreviousDiffAction myPreviousDiff; - // todo here public ChangesFragmentedDiffPanel(final Project project, final FragmentedContent fragmentedContent, final LinkedList cache, String filePath) { myProject = project; @@ -112,6 +116,8 @@ public class ChangesFragmentedDiffPanel implements Disposable { return myPanel; } }; + myNextDiff = new MyNextDiffAction(); + myPreviousDiff = new MyPreviousDiffAction(); } @Override @@ -129,10 +135,22 @@ public class ChangesFragmentedDiffPanel implements Disposable { final JPanel wrapper = new JPanel(); //final BoxLayout boxLayout = new BoxLayout(wrapper, BoxLayout.X_AXIS); wrapper.setLayout(new BorderLayout()); - final JLabel label = new JLabel(myFilePath); - label.setBorder(BorderFactory.createEmptyBorder(1,2,0,0)); - wrapper.add(label, BorderLayout.WEST); - wrapper.add(new MyShowSettingsButton(), BorderLayout.EAST); // todo should be one button for all.. + final JLabel titleLabel = new JLabel(myFilePath); + titleLabel.setBorder(BorderFactory.createEmptyBorder(1, 2, 0, 0)); + wrapper.add(titleLabel, BorderLayout.WEST); + DefaultActionGroup dag = new DefaultActionGroup(); + boolean navigationEnabled = !myFragmentedContent.isOneSide() && myFragmentedContent.getSize() > 1; + myNextDiff.setEnabled(navigationEnabled); + myPreviousDiff.setEnabled(navigationEnabled); + myPreviousDiff.copyShortcutFrom(ActionManager.getInstance().getAction("PreviousDiff")); + myNextDiff.copyShortcutFrom(ActionManager.getInstance().getAction("NextDiff")); + dag.add(myPreviousDiff); + dag.add(myNextDiff); + myPreviousDiff.registerCustomShortcutSet(myPreviousDiff.getShortcutSet(), myPanel); + myNextDiff.registerCustomShortcutSet(myNextDiff.getShortcutSet(), myPanel); + dag.add(new PopupAction()); + ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, dag, true); + wrapper.add(toolbar.getComponent(), BorderLayout.EAST); myTopPanel.add(wrapper, BorderLayout.CENTER); @@ -176,6 +194,11 @@ public class ChangesFragmentedDiffPanel implements Disposable { final DiffPanel diffPanel = createPanel(oldConvertor, newConvertor, sbOld, sbNew, ranges); myCurrentHorizontal = myConfiguration.SHORT_DIFF_HORISONTALLY; savePanel(diffPanel); + titleLabel.setText(titleText((DiffPanelImpl)diffPanel)); + FragmentedDiffPanelState state = (FragmentedDiffPanelState)((DiffPanelImpl)diffPanel).getDiffPanelState(); + myLeftLines = state.getLeftLines(); + myRightLines = state.getRightLines(); + myConfiguration.SHORT_DIFF_HORISONTALLY = ! myConfiguration.SHORT_DIFF_HORISONTALLY; final DiffPanel diffPanel2 = createPanel(oldConvertor, newConvertor, sbOld, sbNew, ranges); savePanel(diffPanel2); @@ -185,6 +208,10 @@ public class ChangesFragmentedDiffPanel implements Disposable { myPanel.add(diffPanel.getComponent(), BorderLayout.CENTER); } + private String titleText(DiffPanelImpl diffPanel) { + return myFilePath + " " + diffPanel.getNumDifferencesText(); + } + private void savePanel(DiffPanel diffPanel) { if (myConfiguration.SHORT_DIFF_HORISONTALLY) { myHorizontal = diffPanel; @@ -426,7 +453,8 @@ public class ChangesFragmentedDiffPanel implements Disposable { private AnAction myNumbered; private PopupAction() { - myUsual = new AnAction("Vertical") { + super("Settings", "Settings", IconLoader.getIcon("/general/secondaryGroup.png")); + myUsual = new AnAction("Top | Bottom") { @Override public void actionPerformed(AnActionEvent e) { boolean was = myConfiguration.SHORT_DIFF_HORISONTALLY; @@ -436,7 +464,7 @@ public class ChangesFragmentedDiffPanel implements Disposable { } } }; - myNumbered = new AnAction("Horizontal") { + myNumbered = new AnAction("Left | Right") { @Override public void actionPerformed(AnActionEvent e) { boolean was = myConfiguration.SHORT_DIFF_HORISONTALLY; @@ -460,13 +488,19 @@ public class ChangesFragmentedDiffPanel implements Disposable { final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, dag, e.getDataContext(), JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false); - final Dimension dimension = popup.getContent().getPreferredSize(); - final Point at = new Point(-dimension.width / 2, 0); - popup.show(new RelativePoint(myParent, at)); + if (e.getInputEvent() instanceof MouseEvent) { + popup.show(new RelativePoint((MouseEvent)e.getInputEvent())); + } else { + // todo correct + /*final Dimension dimension = popup.getContent().getPreferredSize(); + final Point at = new Point(-dimension.width / 2, 0); + popup.show(new RelativePoint(myParent, at));*/ + popup.showInBestPositionFor(e.getDataContext()); + } } } - private class MyShowSettingsButton extends ActionButton implements DumbAware { + /*private class MyShowSettingsButton extends ActionButton implements DumbAware { MyShowSettingsButton() { this(new PopupAction(), new Presentation(), ActionPlaces.CHANGES_LOCAL_DIFF_SETTINGS, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); } @@ -476,16 +510,11 @@ public class ChangesFragmentedDiffPanel implements Disposable { ((PopupAction) getAction()).setParent(this); myPresentation.setIcon(IconLoader.getIcon("/general/secondaryGroup.png")); } - } + }*/ private void ensurePresentation() { if (myCurrentHorizontal != myConfiguration.SHORT_DIFF_HORISONTALLY) { - final DiffPanel panel; - if (myConfiguration.SHORT_DIFF_HORISONTALLY) { - panel = myHorizontal; - } else { - panel = myVertical; - } + final DiffPanel panel = getCurrentPanel(); myPanel.removeAll(); myPanel.add(myTopPanel, BorderLayout.NORTH); @@ -496,4 +525,106 @@ public class ChangesFragmentedDiffPanel implements Disposable { myCurrentHorizontal = myConfiguration.SHORT_DIFF_HORISONTALLY; } } + + private DiffPanel getCurrentPanel() { + DiffPanel panel; + if (myConfiguration.SHORT_DIFF_HORISONTALLY) { + panel = myHorizontal; + } else { + panel = myVertical; + } + return panel; + } + + private int getCurrentLogicalLineIdx(final boolean forward) { + assert ! myLeftLines.isEmpty(); + + final Editor editor = ((DiffPanelImpl) getCurrentPanel()).getEditor1(); + Point location = editor.getScrollingModel().getVisibleArea().getLocation(); + LogicalPosition lp = editor.xyToLogicalPosition(location); + int line = lp.line; + if (forward) { + if (line >= myLeftLines.get(myLeftLines.size() - 1)) { + return myLeftLines.size() - 1; + } + for (int i = myLeftLines.size() - 1; i >= 0; i--) { + Integer integer = myLeftLines.get(i); + if (integer <= line) return i + 1; + } + return 0; + } else { + if (line <= myLeftLines.get(0)) return 0; + for (int i = 0; i < myLeftLines.size(); i++) { + Integer integer = myLeftLines.get(i); + if (integer > line) { + return i; + } + } + return myLeftLines.size() - 1; + } + } + + private class MyPreviousDiffAction extends AnAction { + private boolean myEnabled; + + private MyPreviousDiffAction() { + super("Previous Change", "Previous Change", IconLoader.getIcon("/actions/previousOccurence.png")); + } + + @Override + public void actionPerformed(AnActionEvent e) { + int currentLogicalLineIdx = getCurrentLogicalLineIdx(false); + int nextLineIdx = currentLogicalLineIdx == 0 ? 0 : currentLogicalLineIdx - 1; + int rightIndex = nextLineIdx >= myRightLines.size() ? (myRightLines.size() - 1) : nextLineIdx; + + DiffPanelImpl panel = (DiffPanelImpl) getCurrentPanel(); + panel.getSideView(FragmentSide.SIDE1).scrollToFirstDiff(myLeftLines.get(nextLineIdx)); + panel.getSideView(FragmentSide.SIDE2).scrollToFirstDiff(myRightLines.get(rightIndex)); + } + + public void setEnabled(boolean enabled) { + myEnabled = enabled; + } + + @Override + public void update(AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(myEnabled); + } + } + + private class MyNextDiffAction extends AnAction { + private boolean myEnabled; + + private MyNextDiffAction() { + // todo text + super("Next Change", "Next Change", IconLoader.getIcon("/actions/nextOccurence.png")); + } + + @Override + public void actionPerformed(AnActionEvent e) { + int currentLogicalLineIdx = getCurrentLogicalLineIdx(true); + int nextLineIdx = currentLogicalLineIdx == (myLeftLines.size() - 1) ? currentLogicalLineIdx : currentLogicalLineIdx + 1; + int rightIndex = nextLineIdx >= myRightLines.size() ? (myRightLines.size() - 1) : nextLineIdx; + + DiffPanelImpl panel = (DiffPanelImpl) getCurrentPanel(); + panel.getSideView(FragmentSide.SIDE1).scrollToFirstDiff(myLeftLines.get(nextLineIdx)); + panel.getSideView(FragmentSide.SIDE2).scrollToFirstDiff(myRightLines.get(rightIndex)); + } + + public void setEnabled(boolean enabled) { + myEnabled = enabled; + } + + @Override + public void update(AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(myEnabled); + } + } + /* + + /**/ } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java index d244ec5e35af..cf3d18ec2875 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FragmentedContent.java @@ -48,4 +48,12 @@ public class FragmentedContent { public List> getRanges() { return myRanges; } + + public int getSize() { + return myRanges.size(); + } + + public boolean isOneSide() { + return myRanges.size() == 1 && (myRanges.get(0).getAfter().isEmpty() || myRanges.get(0).getBefore().isEmpty()); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java index fcd2b1381780..ae3c1e113b2e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsChangeDetailsManager.java @@ -33,6 +33,8 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.Details; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsKey; +import com.intellij.openapi.vcs.history.ShortVcsRevisionNumber; +import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.util.BeforeAfter; import com.intellij.util.containers.HashMap; @@ -302,6 +304,12 @@ public class VcsChangeDetailsManager { private static String changeDescription(Change o) { return new StringBuilder().append(ChangesUtil.getFilePath(o).getName()).append(" (").append( o.getBeforeRevision() == null - ? "New" : o.getBeforeRevision().getRevisionNumber().asString()).append(")").toString(); + ? "New" : beforeRevisionText(o)).append(")").toString(); + } + + private static String beforeRevisionText(Change o) { + VcsRevisionNumber revisionNumber = o.getBeforeRevision().getRevisionNumber(); + return revisionNumber instanceof ShortVcsRevisionNumber ? ((ShortVcsRevisionNumber) revisionNumber).toShortString() : + revisionNumber.asString(); } }