diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopup.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopup.java new file mode 100644 index 000000000000..c5e432181893 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusMarkerPopup.java @@ -0,0 +1,303 @@ +/* + * Copyright 2000-2016 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.ex; + +import com.intellij.codeInsight.hint.EditorFragmentComponent; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.codeInsight.hint.HintManagerImpl; +import com.intellij.diff.comparison.ByWord; +import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.fragments.DiffFragment; +import com.intellij.diff.util.DiffDrawUtil; +import com.intellij.diff.util.DiffUtil; +import com.intellij.diff.util.TextDiffType; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.PlainTextFileType; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.util.BackgroundTaskUtil; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.HintHint; +import com.intellij.ui.HintListener; +import com.intellij.ui.LightweightHint; +import com.intellij.util.Function; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.List; + +import static com.intellij.diff.util.DiffUtil.getDiffType; +import static com.intellij.diff.util.DiffUtil.getLineCount; + +public abstract class LineStatusMarkerPopup { + @NotNull public final LineStatusTracker myTracker; + @NotNull public final Editor myEditor; + @NotNull public final Range myRange; + + public LineStatusMarkerPopup(@NotNull LineStatusTracker tracker, @NotNull Editor editor, @NotNull Range range) { + myTracker = tracker; + myEditor = editor; + myRange = range; + } + + @NotNull + protected abstract ActionToolbar buildToolbar(@Nullable Point mousePosition, @NotNull Disposable parentDisposable); + + @NotNull + protected FileType getFileType() { + return PlainTextFileType.INSTANCE; + } + + protected boolean isShowInnerDifferences() { + return false; + } + + + public void scrollAndShow() { + if (!myTracker.isValid()) return; + final Document document = myTracker.getDocument(); + int line = Math.min(myRange.getType() == Range.DELETED ? myRange.getLine2() : myRange.getLine2() - 1, getLineCount(document) - 1); + final int lastOffset = document.getLineStartOffset(line); + myEditor.getCaretModel().moveToOffset(lastOffset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); + + showAfterScroll(); + } + + public void showAfterScroll() { + myEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() { + public void run() { + showHintAt(null); + } + }); + } + + public void showHint(@NotNull MouseEvent e) { + final JComponent comp = (JComponent)e.getComponent(); // shall be EditorGutterComponent, cast is safe. + final JLayeredPane layeredPane = comp.getRootPane().getLayeredPane(); + final Point point = SwingUtilities.convertPoint(comp, ((EditorEx)myEditor).getGutterComponentEx().getWidth(), e.getY(), layeredPane); + showHintAt(point); + e.consume(); + } + + public void showHintAt(@Nullable Point mousePosition) { + if (!myTracker.isValid()) return; + final Disposable disposable = Disposer.newDisposable(); + + FileType fileType = getFileType(); + List wordDiff = computeWordDiff(); + + installMasterEditorHighlighters(wordDiff, disposable); + JComponent editorComponent = createEditorComponent(fileType, wordDiff); + + ActionToolbar toolbar = buildToolbar(mousePosition, disposable); + toolbar.updateActionsImmediately(); // we need valid ActionToolbar.getPreferredSize() to calc size of popup + toolbar.setReservePlaceAutoPopupIcon(false); + + PopupPanel popupPanel = new PopupPanel(myEditor, toolbar, editorComponent); + + LightweightHint hint = new LightweightHint(popupPanel); + HintListener closeListener = new HintListener() { + public void hintHidden(final EventObject event) { + Disposer.dispose(disposable); + } + }; + hint.addHintListener(closeListener); + + int line = myEditor.getCaretModel().getLogicalPosition().line; + Point point = HintManagerImpl.getHintPosition(hint, myEditor, new LogicalPosition(line, 0), HintManager.UNDER); + if (mousePosition != null) { // show right after the nearest line + int lineHeight = myEditor.getLineHeight(); + int delta = (point.y - mousePosition.y) % lineHeight; + if (delta < 0) delta += lineHeight; + point.y = mousePosition.y + delta; + } + point.x -= popupPanel.getEditorTextOffset(); // align main editor with the one in popup + + int flags = HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING; + HintManagerImpl.getInstanceImpl().showEditorHint(hint, myEditor, point, flags, -1, false, new HintHint(myEditor, point)); + + if (!hint.isVisible()) { + closeListener.hintHidden(null); + } + } + + @Nullable + private List computeWordDiff() { + if (!isShowInnerDifferences()) return null; + if (myRange.getType() != Range.MODIFIED) return null; + + final CharSequence vcsContent = myTracker.getVcsContent(myRange); + final CharSequence currentContent = myTracker.getCurrentContent(myRange); + + return BackgroundTaskUtil.tryComputeFast(new Function>() { + @Override + public List fun(ProgressIndicator indicator) { + return ByWord.compare(vcsContent, currentContent, ComparisonPolicy.DEFAULT, indicator); + } + }, Registry.intValue("diff.status.tracker.byword.delay")); + } + + private void installMasterEditorHighlighters(@Nullable List wordDiff, @NotNull Disposable parentDisposable) { + if (wordDiff == null) return; + final List highlighters = new ArrayList(); + + int currentStartShift = myTracker.getCurrentTextRange(myRange).getStartOffset(); + for (DiffFragment fragment : wordDiff) { + int currentStart = currentStartShift + fragment.getStartOffset2(); + int currentEnd = currentStartShift + fragment.getEndOffset2(); + TextDiffType type = getDiffType(fragment); + + highlighters.addAll(DiffDrawUtil.createInlineHighlighter(myEditor, currentStart, currentEnd, type)); + } + + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + for (RangeHighlighter highlighter : highlighters) { + highlighter.dispose(); + } + } + }); + } + + @Nullable + private EditorFragmentComponent createEditorComponent(@Nullable FileType fileType, @Nullable List wordDiff) { + if (myRange.getType() == Range.INSERTED) return null; + + EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(myTracker.getVcsDocument(), myTracker.getProject()); + uEditor.setColorsScheme(myEditor.getColorsScheme()); + + DiffUtil.setEditorCodeStyle(myTracker.getProject(), uEditor, fileType); + + EditorHighlighterFactory highlighterFactory = EditorHighlighterFactory.getInstance(); + uEditor.setHighlighter(highlighterFactory.createEditorHighlighter(myTracker.getProject(), getFileName(myTracker.getDocument()))); + + if (wordDiff != null) { + int vcsStartShift = myTracker.getVcsTextRange(myRange).getStartOffset(); + for (DiffFragment fragment : wordDiff) { + int vcsStart = vcsStartShift + fragment.getStartOffset1(); + int vcsEnd = vcsStartShift + fragment.getEndOffset1(); + TextDiffType type = getDiffType(fragment); + + DiffDrawUtil.createInlineHighlighter(uEditor, vcsStart, vcsEnd, type); + } + } + + EditorFragmentComponent fragmentComponent = + EditorFragmentComponent.createEditorFragmentComponent(uEditor, myRange.getVcsLine1(), myRange.getVcsLine2(), false, false); + + EditorFactory.getInstance().releaseEditor(uEditor); + + return fragmentComponent; + } + + private static String getFileName(@NotNull Document document) { + final VirtualFile file = FileDocumentManager.getInstance().getFile(document); + if (file == null) return ""; + return file.getName(); + } + + private static class PopupPanel extends JPanel { + @Nullable private final JComponent myEditorComponent; + + public PopupPanel(@NotNull final Editor editor, + @NotNull ActionToolbar toolbar, + @Nullable JComponent editorComponent) { + super(new BorderLayout()); + setOpaque(false); + + myEditorComponent = editorComponent; + boolean isEditorVisible = myEditorComponent != null; + + Color background = ((EditorEx)editor).getBackgroundColor(); + Color borderColor = editor.getColorsScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR); + + JComponent toolbarComponent = toolbar.getComponent(); + toolbarComponent.setBackground(background); + toolbarComponent.setBorder(null); + + JComponent toolbarPanel = JBUI.Panels.simplePanel(toolbarComponent); + toolbarPanel.setBackground(background); + Border outsideToolbarBorder = JBUI.Borders.customLine(borderColor, 1, 1, isEditorVisible ? 0 : 1, 1); + Border insideToolbarBorder = JBUI.Borders.empty(1, 5, 1, 5); + toolbarPanel.setBorder(BorderFactory.createCompoundBorder(outsideToolbarBorder, insideToolbarBorder)); + + if (myEditorComponent != null) { + // default border of EditorFragmentComponent is replaced here with our own. + Border outsideEditorBorder = JBUI.Borders.customLine(borderColor, 1); + Border insideEditorBorder = JBUI.Borders.empty(2); + myEditorComponent.setBorder(BorderFactory.createCompoundBorder(outsideEditorBorder, insideEditorBorder)); + } + + // 'empty space' to the right of toolbar + JPanel emptyPanel = new JPanel(); + emptyPanel.setOpaque(false); + emptyPanel.setPreferredSize(new Dimension()); + + JPanel topPanel = new JPanel(new BorderLayout()); + topPanel.setOpaque(false); + topPanel.add(toolbarPanel, BorderLayout.WEST); + topPanel.add(emptyPanel, BorderLayout.CENTER); + + add(topPanel, BorderLayout.NORTH); + if (myEditorComponent != null) add(myEditorComponent, BorderLayout.CENTER); + + // transfer clicks into editor + MouseAdapter listener = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + transferEvent(e, editor); + } + + @Override + public void mouseClicked(MouseEvent e) { + transferEvent(e, editor); + } + + public void mouseReleased(MouseEvent e) { + transferEvent(e, editor); + } + }; + emptyPanel.addMouseListener(listener); + } + + private static void transferEvent(MouseEvent e, Editor editor) { + editor.getContentComponent().dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, editor.getContentComponent())); + } + + public int getEditorTextOffset() { + return 3; // myEditorComponent.getInsets().left + } + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index 9a679c8d061f..ed38bafc2331 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -15,265 +15,107 @@ */ package com.intellij.openapi.vcs.ex; -import com.intellij.codeInsight.hint.EditorFragmentComponent; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.codeInsight.hint.HintManagerImpl; -import com.intellij.diff.comparison.ByWord; -import com.intellij.diff.comparison.ComparisonPolicy; -import com.intellij.diff.fragments.DiffFragment; -import com.intellij.diff.util.DiffDrawUtil; -import com.intellij.diff.util.DiffUtil; -import com.intellij.diff.util.TextDiffType; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; -import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.ex.DocumentEx; -import com.intellij.openapi.editor.ex.EditorEx; -import com.intellij.openapi.editor.highlighter.EditorHighlighter; -import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.markup.LineMarkerRenderer; -import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.BackgroundTaskUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vcs.VcsApplicationSettings; import com.intellij.openapi.vcs.actions.ShowNextChangeMarkerAction; import com.intellij.openapi.vcs.actions.ShowPrevChangeMarkerAction; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.HintHint; -import com.intellij.ui.HintListener; -import com.intellij.ui.LightweightHint; -import com.intellij.util.Function; -import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.border.Border; import java.awt.*; -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.EventObject; import java.util.List; -import static com.intellij.diff.util.DiffUtil.getDiffType; -import static com.intellij.diff.util.DiffUtil.getLineCount; - public class LineStatusTrackerDrawing { private LineStatusTrackerDrawing() { } public static LineMarkerRenderer createRenderer(final Range range, final LineStatusTracker tracker) { return new LineStatusMarkerRenderer(range) { - public void doAction(final Editor editor, final MouseEvent e) { - e.consume(); - final JComponent comp = (JComponent)e.getComponent(); // shall be EditorGutterComponent, cast is safe. - final JLayeredPane layeredPane = comp.getRootPane().getLayeredPane(); - final Point point = SwingUtilities.convertPoint(comp, ((EditorEx)editor).getGutterComponentEx().getWidth(), e.getY(), layeredPane); - showActiveHint(range, editor, tracker, point); + public void doAction(Editor editor, MouseEvent e) { + new MyLineStatusMarkerPopup(tracker, editor, range).showHint(e); } }; } - public static void showActiveHint(@NotNull Range range, - @NotNull Editor editor, - @NotNull LineStatusTracker tracker, - @Nullable Point mousePosition) { - if (!tracker.isValid()) return; - final Disposable disposable = Disposer.newDisposable(); - - List wordDiff = computeWordDiff(range, tracker); - - installEditorHighlighters(range, editor, tracker, wordDiff, disposable); - JComponent editorComponent = createEditorComponent(range, editor, tracker, wordDiff); - - ActionToolbar toolbar = buildToolbar(range, editor, tracker, mousePosition, disposable); - toolbar.updateActionsImmediately(); // we need valid ActionToolbar.getPreferredSize() to calc size of popup - toolbar.setReservePlaceAutoPopupIcon(false); - - PopupPanel popupPanel = new PopupPanel(editor, toolbar, editorComponent); - - LightweightHint hint = new LightweightHint(popupPanel); - HintListener closeListener = new HintListener() { - public void hintHidden(final EventObject event) { - Disposer.dispose(disposable); - } - }; - hint.addHintListener(closeListener); - - int line = editor.getCaretModel().getLogicalPosition().line; - Point point = HintManagerImpl.getHintPosition(hint, editor, new LogicalPosition(line, 0), HintManager.UNDER); - if (mousePosition != null) { // show right after the nearest line - int lineHeight = editor.getLineHeight(); - int delta = (point.y - mousePosition.y) % lineHeight; - if (delta < 0) delta += lineHeight; - point.y = mousePosition.y + delta; - } - point.x -= popupPanel.getEditorTextOffset(); // align main editor with the one in popup - - int flags = HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING; - HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, point, flags, -1, false, new HintHint(editor, point)); - - if (!hint.isVisible()) { - closeListener.hintHidden(null); - } + public static void moveToRange(Range range, Editor editor, LineStatusTracker tracker) { + new MyLineStatusMarkerPopup(tracker, editor, range).scrollAndShow(); } - @Nullable - private static List computeWordDiff(@NotNull Range range, @NotNull LineStatusTracker tracker) { - if (!VcsApplicationSettings.getInstance().SHOW_LST_WORD_DIFFERENCES) return null; - if (range.getType() != Range.MODIFIED) return null; - - final CharSequence vcsContent = tracker.getVcsContent(range); - final CharSequence currentContent = tracker.getCurrentContent(range); - - return BackgroundTaskUtil.tryComputeFast(new Function>() { - @Override - public List fun(ProgressIndicator indicator) { - return ByWord.compare(vcsContent, currentContent, ComparisonPolicy.DEFAULT, indicator); - } - }, Registry.intValue("diff.status.tracker.byword.delay")); + public static void showHint(Range range, Editor editor, LineStatusTracker tracker) { + new MyLineStatusMarkerPopup(tracker, editor, range).showAfterScroll(); } - @NotNull - private static ActionToolbar buildToolbar(@NotNull Range range, - @NotNull Editor editor, - @NotNull LineStatusTracker tracker, - @Nullable Point mousePosition, - @NotNull Disposable parentDisposable) { - final DefaultActionGroup group = new DefaultActionGroup(); + private static class MyLineStatusMarkerPopup extends LineStatusMarkerPopup { + @NotNull private final LineStatusTracker myTracker; - final ShowPrevChangeMarkerAction localShowPrevAction = new ShowPrevChangeMarkerAction(tracker.getPrevRange(range), tracker, editor); - final ShowNextChangeMarkerAction localShowNextAction = new ShowNextChangeMarkerAction(tracker.getNextRange(range), tracker, editor); - final RollbackLineStatusRangeAction rollback = new RollbackLineStatusRangeAction(tracker, range, editor); - final ShowLineStatusRangeDiffAction showDiff = new ShowLineStatusRangeDiffAction(tracker, range, editor); - final CopyLineStatusRangeAction copyRange = new CopyLineStatusRangeAction(tracker, range); - final ToggleByWordDiffAction toggleWordDiff = new ToggleByWordDiffAction(range, editor, tracker, mousePosition); - - group.add(localShowPrevAction); - group.add(localShowNextAction); - group.add(rollback); - group.add(showDiff); - group.add(copyRange); - group.add(toggleWordDiff); - - JComponent editorComponent = editor.getComponent(); - EmptyAction.setupAction(localShowPrevAction, "VcsShowPrevChangeMarker", editorComponent); - EmptyAction.setupAction(localShowNextAction, "VcsShowNextChangeMarker", editorComponent); - EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent); - EmptyAction.setupAction(showDiff, "ChangesView.Diff", editorComponent); - EmptyAction.setupAction(copyRange, IdeActions.ACTION_COPY, editorComponent); - - final List actionList = ActionUtil.getActions(editorComponent); - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - actionList.remove(localShowPrevAction); - actionList.remove(localShowNextAction); - actionList.remove(rollback); - actionList.remove(showDiff); - actionList.remove(copyRange); - } - }); - - return ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true); - } - - private static void installEditorHighlighters(@NotNull Range range, - @NotNull Editor editor, - @NotNull LineStatusTracker tracker, - @Nullable List wordDiff, - @NotNull Disposable parentDisposable) { - if (wordDiff == null) return; - final List highlighters = new ArrayList(); - - int currentStartShift = tracker.getCurrentTextRange(range).getStartOffset(); - for (DiffFragment fragment : wordDiff) { - int currentStart = currentStartShift + fragment.getStartOffset2(); - int currentEnd = currentStartShift + fragment.getEndOffset2(); - TextDiffType type = getDiffType(fragment); - - highlighters.addAll(DiffDrawUtil.createInlineHighlighter(editor, currentStart, currentEnd, type)); + public MyLineStatusMarkerPopup(@NotNull LineStatusTracker tracker, + @NotNull Editor editor, + @NotNull Range range) { + super(tracker, editor, range); + myTracker = tracker; } - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - for (RangeHighlighter highlighter : highlighters) { - highlighter.dispose(); + @Override + protected boolean isShowInnerDifferences() { + return VcsApplicationSettings.getInstance().SHOW_LST_WORD_DIFFERENCES; + } + + @NotNull + @Override + protected ActionToolbar buildToolbar(@Nullable Point mousePosition, @NotNull Disposable parentDisposable) { + final DefaultActionGroup group = new DefaultActionGroup(); + + final ShowPrevChangeMarkerAction localShowPrevAction = new ShowPrevChangeMarkerAction(myTracker.getPrevRange(myRange), myTracker, myEditor); + final ShowNextChangeMarkerAction localShowNextAction = new ShowNextChangeMarkerAction(myTracker.getNextRange(myRange), myTracker, myEditor); + final RollbackLineStatusRangeAction rollback = new RollbackLineStatusRangeAction(myTracker, myRange, myEditor); + final ShowLineStatusRangeDiffAction showDiff = new ShowLineStatusRangeDiffAction(myTracker, myRange, myEditor); + final CopyLineStatusRangeAction copyRange = new CopyLineStatusRangeAction(myTracker, myRange); + final ToggleByWordDiffAction toggleWordDiff = new ToggleByWordDiffAction(myRange, myEditor, myTracker, mousePosition); + + group.add(localShowPrevAction); + group.add(localShowNextAction); + group.add(rollback); + group.add(showDiff); + group.add(copyRange); + group.add(toggleWordDiff); + + JComponent editorComponent = myEditor.getComponent(); + EmptyAction.setupAction(localShowPrevAction, "VcsShowPrevChangeMarker", editorComponent); + EmptyAction.setupAction(localShowNextAction, "VcsShowNextChangeMarker", editorComponent); + EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent); + EmptyAction.setupAction(showDiff, "ChangesView.Diff", editorComponent); + EmptyAction.setupAction(copyRange, IdeActions.ACTION_COPY, editorComponent); + + final List actionList = ActionUtil.getActions(editorComponent); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + actionList.remove(localShowPrevAction); + actionList.remove(localShowNextAction); + actionList.remove(rollback); + actionList.remove(showDiff); + actionList.remove(copyRange); } - } - }); - } + }); - @Nullable - private static JComponent createEditorComponent(@NotNull Range range, - @NotNull Editor editor, - @NotNull LineStatusTracker tracker, - @Nullable List wordDiff) { - if (range.getType() == Range.INSERTED) return null; - - DocumentEx doc = (DocumentEx)tracker.getVcsDocument(); - EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(doc, tracker.getProject()); - uEditor.setColorsScheme(editor.getColorsScheme()); - - FileType fileType = tracker.getVirtualFile().getFileType(); - DiffUtil.setEditorCodeStyle(tracker.getProject(), uEditor, fileType); - - EditorHighlighterFactory highlighterFactory = EditorHighlighterFactory.getInstance(); - EditorHighlighter highlighter = highlighterFactory.createEditorHighlighter(tracker.getProject(), getFileName(tracker.getDocument())); - uEditor.setHighlighter(highlighter); - - if (wordDiff != null) { - int vcsStartShift = tracker.getVcsTextRange(range).getStartOffset(); - for (DiffFragment fragment : wordDiff) { - int vcsStart = vcsStartShift + fragment.getStartOffset1(); - int vcsEnd = vcsStartShift + fragment.getEndOffset1(); - TextDiffType type = getDiffType(fragment); - - DiffDrawUtil.createInlineHighlighter(uEditor, vcsStart, vcsEnd, type); - } + return ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true); } - JComponent fragmentComponent = - EditorFragmentComponent.createEditorFragmentComponent(uEditor, range.getVcsLine1(), range.getVcsLine2(), false, false); - - EditorFactory.getInstance().releaseEditor(uEditor); - - return fragmentComponent; - } - - private static String getFileName(final Document document) { - final VirtualFile file = FileDocumentManager.getInstance().getFile(document); - if (file == null) return ""; - return file.getName(); - } - - public static void moveToRange(final Range range, final Editor editor, final LineStatusTracker tracker) { - if (!tracker.isValid()) return; - final Document document = tracker.getDocument(); - int line = Math.min(range.getType() == Range.DELETED ? range.getLine2() : range.getLine2() - 1, getLineCount(document) - 1); - final int lastOffset = document.getLineStartOffset(line); - editor.getCaretModel().moveToOffset(lastOffset); - editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); - - showHint(range, editor, tracker); - } - - public static void showHint(final Range range, final Editor editor, final LineStatusTracker tracker) { - editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() { - public void run() { - showActiveHint(range, editor, tracker, null); - } - }); + @NotNull + @Override + protected FileType getFileType() { + return myTracker.getVirtualFile().getFileType(); + } } private static class ToggleByWordDiffAction extends ToggleAction implements DumbAware { @@ -301,80 +143,7 @@ public class LineStatusTrackerDrawing { @Override public void setSelected(AnActionEvent e, boolean state) { VcsApplicationSettings.getInstance().SHOW_LST_WORD_DIFFERENCES = state; - showActiveHint(myRange, myEditor, myTracker, myMousePosition); - } - } - - private static class PopupPanel extends JPanel { - @Nullable private final JComponent myEditorComponent; - - public PopupPanel(@NotNull final Editor editor, - @NotNull ActionToolbar toolbar, - @Nullable JComponent editorComponent) { - super(new BorderLayout()); - setOpaque(false); - - myEditorComponent = editorComponent; - boolean isEditorVisible = myEditorComponent != null; - - Color background = ((EditorEx)editor).getBackgroundColor(); - Color borderColor = editor.getColorsScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR); - - JComponent toolbarComponent = toolbar.getComponent(); - toolbarComponent.setBackground(background); - toolbarComponent.setBorder(null); - - JComponent toolbarPanel = JBUI.Panels.simplePanel(toolbarComponent); - toolbarPanel.setBackground(background); - Border outsideToolbarBorder = JBUI.Borders.customLine(borderColor, 1, 1, isEditorVisible ? 0 : 1, 1); - Border insideToolbarBorder = JBUI.Borders.empty(1, 5, 1, 5); - toolbarPanel.setBorder(BorderFactory.createCompoundBorder(outsideToolbarBorder, insideToolbarBorder)); - - if (myEditorComponent != null) { - // default border of EditorFragmentComponent is replaced here with our own. - Border outsideEditorBorder = JBUI.Borders.customLine(borderColor, 1); - Border insideEditorBorder = JBUI.Borders.empty(2); - myEditorComponent.setBorder(BorderFactory.createCompoundBorder(outsideEditorBorder, insideEditorBorder)); - } - - // 'empty space' to the right of toolbar - JPanel emptyPanel = new JPanel(); - emptyPanel.setOpaque(false); - emptyPanel.setPreferredSize(new Dimension()); - - JPanel topPanel = new JPanel(new BorderLayout()); - topPanel.setOpaque(false); - topPanel.add(toolbarPanel, BorderLayout.WEST); - topPanel.add(emptyPanel, BorderLayout.CENTER); - - add(topPanel, BorderLayout.NORTH); - if (myEditorComponent != null) add(myEditorComponent, BorderLayout.CENTER); - - // transfer clicks into editor - MouseAdapter listener = new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - transferEvent(e, editor); - } - - @Override - public void mouseClicked(MouseEvent e) { - transferEvent(e, editor); - } - - public void mouseReleased(MouseEvent e) { - transferEvent(e, editor); - } - }; - emptyPanel.addMouseListener(listener); - } - - private static void transferEvent(MouseEvent e, Editor editor) { - editor.getContentComponent().dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, editor.getContentComponent())); - } - - public int getEditorTextOffset() { - return 3; // myEditorComponent.getInsets().left + new MyLineStatusMarkerPopup(myTracker, myEditor, myRange).showHintAt(myMousePosition); } } }