mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
lst: extract LST popup logic to separate class
This commit is contained in:
committed by
Aleksey Pivovarov
parent
688d0fa063
commit
9ef2903168
@@ -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<DiffFragment> 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<DiffFragment> 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<ProgressIndicator, List<DiffFragment>>() {
|
||||
@Override
|
||||
public List<DiffFragment> fun(ProgressIndicator indicator) {
|
||||
return ByWord.compare(vcsContent, currentContent, ComparisonPolicy.DEFAULT, indicator);
|
||||
}
|
||||
}, Registry.intValue("diff.status.tracker.byword.delay"));
|
||||
}
|
||||
|
||||
private void installMasterEditorHighlighters(@Nullable List<DiffFragment> wordDiff, @NotNull Disposable parentDisposable) {
|
||||
if (wordDiff == null) return;
|
||||
final List<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
|
||||
|
||||
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<DiffFragment> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<DiffFragment> 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<DiffFragment> 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<ProgressIndicator, List<DiffFragment>>() {
|
||||
@Override
|
||||
public List<DiffFragment> 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<AnAction> 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<DiffFragment> wordDiff,
|
||||
@NotNull Disposable parentDisposable) {
|
||||
if (wordDiff == null) return;
|
||||
final List<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>();
|
||||
|
||||
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<AnAction> 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<DiffFragment> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user