mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
lst: do not store RangeHighlighter in tracker Blocks
* use single RangeHighlighter to render ranges in gutter
This commit is contained in:
@@ -186,6 +186,10 @@ public class DiffDrawUtil {
|
||||
return editor.logicalPositionToXY(editor.offsetToLogicalPosition(document.getLineStartOffset(line))).y;
|
||||
}
|
||||
|
||||
public static int yToLine(@NotNull Editor editor, int y) {
|
||||
return editor.xyToLogicalPosition(new Point(0, y)).line;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TextAttributes getTextAttributes(@NotNull final TextDiffType type,
|
||||
@Nullable final Editor editor,
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ public abstract class LineStatusMarkerPopupRenderer extends LineStatusMarkerRend
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canDoAction(@NotNull Range range, MouseEvent e) {
|
||||
protected boolean canDoAction(@NotNull Editor editor, @NotNull Range range, MouseEvent e) {
|
||||
return isInsideMarkerArea(e);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,10 @@ package com.intellij.openapi.vcs.ex;
|
||||
|
||||
import com.intellij.diff.util.DiffDrawUtil;
|
||||
import com.intellij.diff.util.DiffUtil;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diff.DiffColors;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
@@ -26,27 +29,139 @@ import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
|
||||
import com.intellij.openapi.editor.impl.DocumentMarkupModel;
|
||||
import com.intellij.openapi.editor.markup.*;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.MergingUpdateQueue;
|
||||
import com.intellij.util.ui.update.Update;
|
||||
import org.jetbrains.annotations.CalledInAwt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.diff.util.DiffDrawUtil.lineToY;
|
||||
import static com.intellij.diff.util.DiffDrawUtil.yToLine;
|
||||
import static com.intellij.openapi.diagnostic.Logger.getInstance;
|
||||
import static com.intellij.util.ui.update.MergingUpdateQueue.ANY_COMPONENT;
|
||||
|
||||
public abstract class LineStatusMarkerRenderer {
|
||||
private static final Logger LOG = getInstance(LineStatusMarkerRenderer.class);
|
||||
|
||||
@NotNull protected final LineStatusTrackerBase<?> myTracker;
|
||||
private final MarkupEditorFilter myEditorFilter;
|
||||
|
||||
@NotNull private final MergingUpdateQueue myUpdateQueue;
|
||||
private boolean myDisposed = false;
|
||||
@NotNull private final RangeHighlighter myHighlighter;
|
||||
@NotNull private final List<RangeHighlighter> myTooltipHighlighters = new ArrayList<>();
|
||||
|
||||
public LineStatusMarkerRenderer(@NotNull LineStatusTrackerBase<?> tracker) {
|
||||
myTracker = tracker;
|
||||
myEditorFilter = getEditorFilter();
|
||||
|
||||
Document document = myTracker.getDocument();
|
||||
MarkupModel markupModel = DocumentMarkupModel.forDocument(document, myTracker.getProject(), true);
|
||||
myHighlighter = markupModel.addRangeHighlighter(0, document.getTextLength(), DiffDrawUtil.LST_LINE_MARKER_LAYER, null,
|
||||
HighlighterTargetArea.LINES_IN_RANGE);
|
||||
myHighlighter.setGreedyToLeft(true);
|
||||
myHighlighter.setGreedyToRight(true);
|
||||
|
||||
myHighlighter.setLineMarkerRenderer(new MyActiveGutterRenderer());
|
||||
|
||||
if (myEditorFilter != null) myHighlighter.setEditorFilter(myEditorFilter);
|
||||
|
||||
myUpdateQueue = new MergingUpdateQueue("LineStatusMarkerRenderer", 100, true, ANY_COMPONENT, myTracker.getDisposable());
|
||||
|
||||
Disposer.register(myTracker.getDisposable(), new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myDisposed = true;
|
||||
destroyHighlighters();
|
||||
}
|
||||
});
|
||||
|
||||
scheduleUpdate();
|
||||
}
|
||||
|
||||
public void scheduleUpdate() {
|
||||
myUpdateQueue.queue(new Update("update") {
|
||||
@Override
|
||||
public void run() {
|
||||
updateHighlighters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean canDoAction(@NotNull Range range, MouseEvent e) {
|
||||
@CalledInAwt
|
||||
private void updateHighlighters() {
|
||||
if (myDisposed) return;
|
||||
|
||||
for (RangeHighlighter highlighter: myTooltipHighlighters) {
|
||||
disposeHighlighter(highlighter);
|
||||
}
|
||||
myTooltipHighlighters.clear();
|
||||
|
||||
List<? extends Range> ranges = myTracker.getRanges();
|
||||
if (ranges != null) {
|
||||
MarkupModel markupModel = DocumentMarkupModel.forDocument(myTracker.getDocument(), myTracker.getProject(), true);
|
||||
for (Range range: ranges) {
|
||||
RangeHighlighter highlighter = createTooltipRangeHighlighter(range, markupModel);
|
||||
if (myEditorFilter != null) highlighter.setEditorFilter(myEditorFilter);
|
||||
myTooltipHighlighters.add(highlighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyHighlighters() {
|
||||
disposeHighlighter(myHighlighter);
|
||||
|
||||
for (RangeHighlighter highlighter: myTooltipHighlighters) {
|
||||
disposeHighlighter(highlighter);
|
||||
}
|
||||
myTooltipHighlighters.clear();
|
||||
}
|
||||
|
||||
private static void disposeHighlighter(@NotNull RangeHighlighter highlighter) {
|
||||
try {
|
||||
highlighter.dispose();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canDoAction(@NotNull Editor editor, MouseEvent e) {
|
||||
Range range = getSelectedRange(editor, e);
|
||||
return range != null && canDoAction(editor, range, e);
|
||||
}
|
||||
|
||||
private void doAction(@NotNull Editor editor, MouseEvent e) {
|
||||
Range range = getSelectedRange(editor, e);
|
||||
if (range != null) {
|
||||
doAction(editor, range, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Range getSelectedRange(@NotNull Editor editor, MouseEvent e) {
|
||||
int line = yToLine(editor, e.getY());
|
||||
Range range = myTracker.getRangeForLine(line);
|
||||
if (range != null) return range;
|
||||
|
||||
// special handling for deletion at the end of file
|
||||
int lineCount = DiffUtil.getLineCount(editor.getDocument());
|
||||
if (line == lineCount - 1) {
|
||||
return myTracker.getRangeForLine(lineCount);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean canDoAction(@NotNull Editor editor, @NotNull Range range, MouseEvent e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,24 +177,9 @@ public abstract class LineStatusMarkerRenderer {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
RangeHighlighter createHighlighter(@NotNull Range range) {
|
||||
MarkupModel markupModel = DocumentMarkupModel.forDocument(myTracker.getDocument(), myTracker.getProject(), true);
|
||||
RangeHighlighter highlighter = createRangeHighlighter(range, markupModel);
|
||||
|
||||
MarkupEditorFilter editorFilter = getEditorFilter();
|
||||
if (editorFilter != null) highlighter.setEditorFilter(editorFilter);
|
||||
|
||||
highlighter.setLineMarkerRenderer(new MyActiveGutterRenderer(range));
|
||||
|
||||
return highlighter;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static RangeHighlighter createRangeHighlighter(@NotNull Range range,
|
||||
@NotNull MarkupModel markupModel) {
|
||||
public static RangeHighlighter createTooltipRangeHighlighter(@NotNull Range range,
|
||||
@NotNull MarkupModel markupModel) {
|
||||
TextRange textRange = DiffUtil.getLinesRange(markupModel.getDocument(), range.getLine1(), range.getLine2(), false);
|
||||
TextAttributes attributes = getTextAttributes(range);
|
||||
|
||||
@@ -94,9 +194,8 @@ public abstract class LineStatusMarkerRenderer {
|
||||
return highlighter;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static TextAttributes getTextAttributes(@NotNull final Range range) {
|
||||
private static TextAttributes getTextAttributes(@NotNull Range range) {
|
||||
return new TextAttributes() {
|
||||
@Override
|
||||
public Color getErrorStripeColor() {
|
||||
@@ -109,6 +208,21 @@ public abstract class LineStatusMarkerRenderer {
|
||||
// Gutter painting
|
||||
//
|
||||
|
||||
protected void paint(@NotNull Editor editor, @NotNull Graphics g) {
|
||||
List<? extends Range> ranges = myTracker.getRanges();
|
||||
if (ranges == null) return;
|
||||
|
||||
Rectangle area = editor.getScrollingModel().getVisibleArea();
|
||||
int line1 = yToLine(editor, area.y);
|
||||
int line2 = yToLine(editor, area.y + area.height);
|
||||
|
||||
for (Range range : ranges) {
|
||||
if (range.getLine2() < line1) continue;
|
||||
if (range.getLine1() > line2) return;
|
||||
paint(editor, range, g);
|
||||
}
|
||||
}
|
||||
|
||||
protected void paint(@NotNull Editor editor, @NotNull Range range, @NotNull Graphics g) {
|
||||
paintRange(g, editor, range, getFramingBorderSize());
|
||||
}
|
||||
@@ -322,25 +436,19 @@ public abstract class LineStatusMarkerRenderer {
|
||||
|
||||
|
||||
private class MyActiveGutterRenderer implements ActiveGutterRenderer {
|
||||
@NotNull private final Range myRange;
|
||||
|
||||
public MyActiveGutterRenderer(@NotNull Range range) {
|
||||
myRange = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Editor editor, Graphics g, Rectangle r) {
|
||||
LineStatusMarkerRenderer.this.paint(editor, myRange, g);
|
||||
LineStatusMarkerRenderer.this.paint(editor, g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDoAction(MouseEvent e) {
|
||||
return LineStatusMarkerRenderer.this.canDoAction(myRange, e);
|
||||
public boolean canDoAction(Editor editor, MouseEvent e) {
|
||||
return LineStatusMarkerRenderer.this.canDoAction(editor, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Editor editor, MouseEvent e) {
|
||||
LineStatusMarkerRenderer.this.doAction(editor, myRange, e);
|
||||
LineStatusMarkerRenderer.this.doAction(editor, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@ import com.intellij.openapi.command.undo.UndoConstants
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.impl.DocumentImpl
|
||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||
import com.intellij.openapi.localVcs.UpToDateLineNumberProvider.ABSENT_LINE_NUMBER
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.VcsBundle
|
||||
@@ -166,7 +164,6 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
if (isReleased) return@Runnable
|
||||
isReleased = true
|
||||
|
||||
updateHighlighters()
|
||||
Disposer.dispose(disposable)
|
||||
}
|
||||
|
||||
@@ -180,10 +177,6 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
|
||||
|
||||
protected open inner class MyDocumentTrackerHandler : DocumentTracker.Handler {
|
||||
override fun onRangeRemoved(block: Block) {
|
||||
destroyHighlighter(block)
|
||||
}
|
||||
|
||||
override fun onRangeShifted(before: Block, after: Block) {
|
||||
after.ourData.innerRanges = before.ourData.innerRanges
|
||||
}
|
||||
@@ -191,22 +184,22 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
override fun afterRefresh() {
|
||||
checkIfFileUnchanged()
|
||||
calcInnerRanges()
|
||||
installMissingHighlighters()
|
||||
updateHighlighters()
|
||||
}
|
||||
|
||||
override fun afterRangeChange() {
|
||||
installMissingHighlighters()
|
||||
updateHighlighters()
|
||||
}
|
||||
|
||||
override fun afterExplicitChange() {
|
||||
checkIfFileUnchanged()
|
||||
calcInnerRanges()
|
||||
installMissingHighlighters()
|
||||
updateHighlighters()
|
||||
}
|
||||
|
||||
override fun onUnfreeze(side: Side) {
|
||||
calcInnerRanges()
|
||||
installMissingHighlighters()
|
||||
updateHighlighters()
|
||||
}
|
||||
|
||||
private fun checkIfFileUnchanged() {
|
||||
@@ -221,17 +214,10 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
for (block in blocks) {
|
||||
if (block.ourData.innerRanges == null) {
|
||||
block.ourData.innerRanges = calcInnerRanges(block)
|
||||
destroyHighlighter(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun installMissingHighlighters() {
|
||||
for (block in blocks) {
|
||||
installHighlighter(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun calcInnerRanges(block: Block): List<Range.InnerRange> {
|
||||
@@ -241,21 +227,8 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
vcsDocument.lineOffsets, document.lineOffsets)
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
protected fun updateHighlighters() {
|
||||
LOCK.write {
|
||||
for (block in blocks) {
|
||||
updateHighlighter(block)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
protected fun updateHighlighter(block: Block) {
|
||||
LOCK.write {
|
||||
destroyHighlighter(block)
|
||||
installHighlighter(block)
|
||||
}
|
||||
renderer.scheduleUpdate()
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
@@ -276,32 +249,6 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
private fun installHighlighter(block: Block) {
|
||||
if (block.ourData.rangeHighlighter != null) return
|
||||
if (!isValid() || block.range.isEmpty) return
|
||||
try {
|
||||
block.ourData.rangeHighlighter = renderer.createHighlighter(block.toRange())
|
||||
}
|
||||
catch (ignore: ProcessCanceledException) {
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
private fun destroyHighlighter(block: Block) {
|
||||
val highlighter = block.ourData.rangeHighlighter ?: return
|
||||
try {
|
||||
block.ourData.rangeHighlighter = null
|
||||
highlighter.dispose()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun isOperational(): Boolean = LOCK.read {
|
||||
return isInitialized && !isReleased
|
||||
}
|
||||
@@ -456,8 +403,7 @@ abstract class LineStatusTrackerBase<R : Range> {
|
||||
}
|
||||
|
||||
|
||||
protected open class BlockData(internal var innerRanges: List<Range.InnerRange>? = null,
|
||||
internal var rangeHighlighter: RangeHighlighter? = null)
|
||||
protected open class BlockData(internal var innerRanges: List<Range.InnerRange>? = null)
|
||||
|
||||
open protected fun createBlockData(): BlockData = BlockData()
|
||||
open protected val Block.ourData: BlockData get() = getBlockData(this)
|
||||
|
||||
+7
-1
@@ -45,5 +45,11 @@ public interface ActiveGutterRenderer extends LineMarkerRenderer {
|
||||
*/
|
||||
void doAction(Editor editor, MouseEvent e);
|
||||
|
||||
boolean canDoAction(final MouseEvent e);
|
||||
default boolean canDoAction(Editor editor, MouseEvent e) {
|
||||
return canDoAction(e);
|
||||
}
|
||||
|
||||
default boolean canDoAction(final MouseEvent e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1740,7 +1740,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
|
||||
if (startY < e.getY() &&
|
||||
e.getY() <= endY &&
|
||||
renderer instanceof ActiveGutterRenderer &&
|
||||
((ActiveGutterRenderer)renderer).canDoAction(e)) {
|
||||
((ActiveGutterRenderer)renderer).canDoAction(myEditor, e)) {
|
||||
gutterRenderer[0] = (ActiveGutterRenderer)renderer;
|
||||
layer[0] = highlighter.getLayer();
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class VcsPreviewPanel implements PreviewPanel {
|
||||
}
|
||||
|
||||
private void addHighlighter(@NotNull Range range, @NotNull ColorKey colorKey) {
|
||||
RangeHighlighter highlighter = LineStatusMarkerRenderer.createRangeHighlighter(range, myEditor.getMarkupModel());
|
||||
RangeHighlighter highlighter = LineStatusMarkerRenderer.createTooltipRangeHighlighter(range, myEditor.getMarkupModel());
|
||||
highlighter.setLineMarkerRenderer(new ActiveGutterRenderer() {
|
||||
@Override
|
||||
public void paint(Editor editor, Graphics g, Rectangle r) {
|
||||
|
||||
@@ -101,14 +101,14 @@ abstract class LineStatusTracker<R : Range> constructor(override val project: Pr
|
||||
: LineStatusMarkerPopupRenderer(tracker) {
|
||||
override fun getEditorFilter(): MarkupEditorFilter? = MarkupEditorFilterFactory.createIsNotDiffFilter()
|
||||
|
||||
override fun canDoAction(range: Range, e: MouseEvent?): Boolean {
|
||||
override fun canDoAction(editor: Editor, range: Range, e: MouseEvent?): Boolean {
|
||||
if (tracker.mode == Mode.SILENT) return false
|
||||
return super.canDoAction(range, e)
|
||||
return super.canDoAction(editor, range, e)
|
||||
}
|
||||
|
||||
override fun paint(editor: Editor, range: Range, g: Graphics) {
|
||||
override fun paint(editor: Editor, g: Graphics) {
|
||||
if (tracker.mode == Mode.SILENT) return
|
||||
super.paint(editor, range, g)
|
||||
super.paint(editor, g)
|
||||
}
|
||||
|
||||
override fun createToolbarActions(editor: Editor, range: Range, mousePosition: Point?): List<AnAction> {
|
||||
|
||||
@@ -21,8 +21,6 @@ import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.openapi.actionSystem.Separator
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.runInEdt
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.command.CommandEvent
|
||||
import com.intellij.openapi.command.CommandListener
|
||||
@@ -265,11 +263,7 @@ class PartialLocalLineStatusTracker(project: Project,
|
||||
if (!affectedBlocks.isEmpty()) {
|
||||
dropExistingUndoActions()
|
||||
|
||||
runInEdt(ModalityState.any()) {
|
||||
for (block in affectedBlocks) {
|
||||
updateHighlighter(block)
|
||||
}
|
||||
}
|
||||
updateHighlighters()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,10 +756,10 @@ class PartialLocalLineStatusTracker(project: Project,
|
||||
assert(blocks.size == states.size)
|
||||
blocks.forEachIndexed { i, block ->
|
||||
block.marker = idToMarker[states[i].changelistId] ?: defaultMarker
|
||||
updateHighlighter(block)
|
||||
}
|
||||
|
||||
updateAffectedChangeLists()
|
||||
updateHighlighters()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user