From 4cbda94bf7aee8b12c51e6972659503053e7eb9c Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 23 Apr 2015 18:57:52 +0300 Subject: [PATCH] IDEA-139555 diff: show 'go to next file' popup near selected change or cursor --- .../diff/impl/DiffRequestProcessor.java | 46 ++++++++++++++----- .../tools/fragmented/OnesideDiffViewer.java | 20 +++++++- .../diff/tools/simple/SimpleDiffViewer.java | 30 +++++++++--- .../simple/SimpleThreesideDiffViewer.java | 25 +++++++++- .../diff/tools/util/DiffDataKeys.java | 3 ++ 5 files changed, 103 insertions(+), 21 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java index 2295fc55f965..2b6fbcb3a798 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java @@ -34,6 +34,7 @@ import com.intellij.diff.util.DiffUserDataKeys; import com.intellij.diff.util.DiffUserDataKeysEx; import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy; import com.intellij.diff.util.DiffUtil; +import com.intellij.diff.util.LineRange; import com.intellij.ide.DataManager; import com.intellij.ide.impl.DataManagerImpl; import com.intellij.openapi.Disposable; @@ -41,6 +42,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; @@ -668,7 +670,7 @@ public abstract class DiffRequestProcessor implements Disposable { if (!isNavigationEnabled() || !hasNextChange() || !getSettings().isGoToNextFileOnNextDifference()) return; if (myIterationState != IterationState.NEXT) { - notifyMessage(e.getData(DiffDataKeys.CURRENT_EDITOR), true); + notifyMessage(e, true); myIterationState = IterationState.NEXT; return; } @@ -717,7 +719,7 @@ public abstract class DiffRequestProcessor implements Disposable { if (!isNavigationEnabled() || !hasPrevChange() || !getSettings().isGoToNextFileOnNextDifference()) return; if (myIterationState != IterationState.PREV) { - notifyMessage(e.getData(DiffDataKeys.CURRENT_EDITOR), false); + notifyMessage(e, false); myIterationState = IterationState.PREV; return; } @@ -726,32 +728,54 @@ public abstract class DiffRequestProcessor implements Disposable { } } - private void notifyMessage(@Nullable Editor editor, boolean next) { + private void notifyMessage(@NotNull AnActionEvent e, boolean next) { + Editor editor = e.getData(DiffDataKeys.CURRENT_EDITOR); + // TODO: provide "change" word in chain UserData - for tests/etc String message = next ? "Press again to go to the next file" : "Press again to go to the previous file"; final LightweightHint hint = new LightweightHint(HintUtil.createInformationLabel(message)); Point point = new Point(myContentPanel.getWidth() / 2, next ? myContentPanel.getHeight() - JBUI.scale(40) : JBUI.scale(40)); - final HintHint hintHint = new HintHint(myContentPanel, point) - .setPreferredPosition(next ? Balloon.Position.above : Balloon.Position.below) - .setAwtTooltip(true) - .setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD)) - .setTextBg(HintUtil.INFORMATION_COLOR) - .setShowImmediately(true); - if (editor == null) { final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + final HintHint hintHint = createNotifyHint(myContentPanel, point, next); hint.show(myContentPanel, point.x, point.y, owner instanceof JComponent ? (JComponent)owner : null, hintHint); } else { - Point editorPoint = SwingUtilities.convertPoint(myContentPanel, point, editor.getComponent()); + int x = SwingUtilities.convertPoint(myContentPanel, point, editor.getComponent()).x; + + JComponent header = editor.getHeaderComponent(); + int shift = editor.getScrollingModel().getVerticalScrollOffset() - (header != null ? header.getHeight() : 0); + + LogicalPosition position; + LineRange changeRange = e.getData(DiffDataKeys.CURRENT_CHANGE_RANGE); + if (changeRange == null) { + position = new LogicalPosition(editor.getCaretModel().getLogicalPosition().line + (next ? 1 : 0), 0); + } + else { + position = new LogicalPosition(next ? changeRange.end : changeRange.start, 0); + } + int y = editor.logicalPositionToXY(position).y - shift; + + Point editorPoint = new Point(x, y); + final HintHint hintHint = createNotifyHint(editor.getComponent(), editorPoint, !next); HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, editorPoint, HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0, false, hintHint); } } + @NotNull + private static HintHint createNotifyHint(@NotNull JComponent component, @NotNull Point point, boolean above) { + return new HintHint(component, point) + .setPreferredPosition(above ? Balloon.Position.above : Balloon.Position.below) + .setAwtTooltip(true) + .setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD)) + .setTextBg(HintUtil.INFORMATION_COLOR) + .setShowImmediately(true); + } + // Iterate requests protected class MyNextChangeAction extends NextChangeAction { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java index 4ef791fc1d6d..1c1ab05ba8e3 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/fragmented/OnesideDiffViewer.java @@ -566,6 +566,18 @@ public class OnesideDiffViewer extends TextDiffViewerBase { return getOpenFileDescriptor(myEditor.getCaretModel().getOffset()); } + @CalledInAwt + @Nullable + protected OnesideDiffChange getCurrentChange() { + if (myChangedBlockData == null) return null; + int caretLine = myEditor.getCaretModel().getLogicalPosition().line; + + for (OnesideDiffChange change : myChangedBlockData.getDiffChanges()) { + if (DiffUtil.isSelectedByLine(caretLine, change.getLine1(), change.getLine2())) return change; + } + return null; + } + @Nullable protected OpenFileDescriptor getOpenFileDescriptor(int offset) { assert myActualContent1 != null || myActualContent2 != null; @@ -806,9 +818,13 @@ public class OnesideDiffViewer extends TextDiffViewerBase { else if (DiffDataKeys.CURRENT_EDITOR.is(dataId)) { return myEditor; } - else { - return super.getData(dataId); + else if (DiffDataKeys.CURRENT_CHANGE_RANGE.is(dataId)) { + OnesideDiffChange change = getCurrentChange(); + if (change != null) { + return new LineRange(change.getLine1(), change.getLine2()); + } } + return super.getData(dataId); } private class MyStatusPanel extends StatusPanel { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index f81a25c9b238..6b2ffd33713e 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -27,12 +27,9 @@ import com.intellij.diff.requests.DiffRequest; import com.intellij.diff.tools.util.*; import com.intellij.diff.tools.util.base.HighlightPolicy; import com.intellij.diff.tools.util.twoside.TwosideTextDiffViewer; -import com.intellij.diff.util.DiffDividerDrawUtil; -import com.intellij.diff.util.DiffDrawUtil; +import com.intellij.diff.util.*; import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy; -import com.intellij.diff.util.DiffUtil; import com.intellij.diff.util.DiffUtil.DocumentData; -import com.intellij.diff.util.Side; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeEventQueue; import com.intellij.openapi.Disposable; @@ -501,6 +498,23 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { return affectedChanges; } + @Nullable + @CalledInAwt + private SimpleDiffChange getSelectedChange(@NotNull Side side) { + EditorEx editor = side.select(myEditor1, myEditor2); + if (editor == null) return null; + + int caretLine = editor.getCaretModel().getLogicalPosition().line; + + for (SimpleDiffChange change : myDiffChanges) { + int line1 = change.getStartLine(side); + int line2 = change.getEndLine(side); + + if (DiffUtil.isSelectedByLine(caretLine, line1, line2)) return change; + } + return null; + } + // // Actions // @@ -820,9 +834,13 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { if (DiffDataKeys.PREV_NEXT_DIFFERENCE_ITERABLE.is(dataId)) { return myPrevNextDifferenceIterable; } - else { - return super.getData(dataId); + else if (DiffDataKeys.CURRENT_CHANGE_RANGE.is(dataId)) { + SimpleDiffChange change = getSelectedChange(getCurrentSide()); + if (change != null) { + return new LineRange(change.getStartLine(getCurrentSide()), change.getEndLine(getCurrentSide())); + } } + return super.getData(dataId); } private class MySyncScrollable extends BaseSyncScrollable { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java index 1471ad397d33..d8a178cb7223 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java @@ -392,6 +392,22 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewer { // Misc // + @Nullable + @CalledInAwt + private SimpleThreesideDiffChange getSelectedChange(@NotNull ThreeSide side) { + EditorEx editor = side.select(myEditors); + + int caretLine = editor.getCaretModel().getLogicalPosition().line; + + for (SimpleThreesideDiffChange change : myDiffChanges) { + int line1 = change.getStartLine(side); + int line2 = change.getEndLine(side); + + if (DiffUtil.isSelectedByLine(caretLine, line1, line2)) return change; + } + return null; + } + @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") public static boolean canShowRequest(@NotNull DiffContext context, @NotNull DiffRequest request) { return ThreesideTextDiffViewer.canShowRequest(context, request); @@ -505,9 +521,14 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewer { if (DiffDataKeys.PREV_NEXT_DIFFERENCE_ITERABLE.is(dataId)) { return myPrevNextDifferenceIterable; } - else { - return super.getData(dataId); + else if (DiffDataKeys.CURRENT_CHANGE_RANGE.is(dataId)) { + SimpleThreesideDiffChange change = getSelectedChange(getCurrentSide()); + if (change != null) { + return new LineRange(change.getStartLine(getCurrentSide()), change.getEndLine(getCurrentSide())); + } } + + return super.getData(dataId); } private class MySyncScrollable extends BaseSyncScrollable { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java index 94f2fe6c1537..21370a250fea 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/DiffDataKeys.java @@ -19,6 +19,8 @@ import com.intellij.diff.DiffContext; import com.intellij.diff.FrameDiffTool; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.requests.DiffRequest; +import com.intellij.diff.util.IntPair; +import com.intellij.diff.util.LineRange; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -26,6 +28,7 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; public interface DiffDataKeys { DataKey CURRENT_EDITOR = DataKey.create("diff_current_editor"); DataKey CURRENT_CONTENT = DataKey.create("diff_current_content"); + DataKey CURRENT_CHANGE_RANGE = DataKey.create("diff_current_change_range"); DataKey DIFF_REQUEST = DataKey.create("diff_request"); DataKey DIFF_CONTEXT = DataKey.create("diff_context");