From 1213c88d1ce65113923fe104a9a9206c54023f96 Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Fri, 31 Jan 2025 16:35:43 +0100 Subject: [PATCH] introduce getMouseHover, getMouseOut and getMouseMove in ICodeMining This change allows code mining implementors to react on mouse move events and call setCursor on the text widget for example. --- .../CodeMiningLineContentAnnotation.java | 24 ++++++--- .../CodeMiningLineHeaderAnnotation.java | 17 +++++- .../text/codemining/CodeMiningManager.java | 9 +++- .../jface/text/codemining/ICodeMining.java | 32 +++++++++++ .../inlined/AbstractInlinedAnnotation.java | 53 +++++++++++++++++-- .../InlinedAnnotationDrawingStrategy.java | 12 ++++- .../inlined/InlinedAnnotationSupport.java | 2 +- .../source/inlined/LineContentAnnotation.java | 21 +++++++- .../source/inlined/LineHeaderAnnotation.java | 21 +++++++- 9 files changed, 173 insertions(+), 18 deletions(-) diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java index c5ce31946be..e01fab82a32 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineContentAnnotation.java @@ -70,11 +70,7 @@ public class CodeMiningLineContentAnnotation extends LineContentAnnotation imple * @param viewer the viewer */ public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer) { - super(position, viewer); - fResolvedMinings= null; - fMinings= new ArrayList<>(); - fBounds= new ArrayList<>(); - afterPosition= false; + this(position, viewer, false); } /** @@ -84,7 +80,23 @@ public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer) * @param viewer the viewer */ public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer, boolean afterPosition) { - super(position, viewer); + this(position, viewer, afterPosition, null, null, null); + } + + /** + * Code mining annotation constructor. + * + * @param position the position + * @param viewer the viewer + * @param onMouseHover the consumer to be called on mouse hover. If set, the implementor needs + * to take care of setting the cursor if wanted. + * @param onMouseOut the consumer to be called on mouse out. If set, the implementor needs to + * take care of resetting the cursor. + * @param onMouseMove the consumer to be called on mouse move + */ + public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer, boolean afterPosition, Consumer onMouseHover, Consumer onMouseOut, + Consumer onMouseMove) { + super(position, viewer, onMouseHover, onMouseOut, onMouseMove); fResolvedMinings= null; fMinings= new ArrayList<>(); fBounds= new ArrayList<>(); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java index 5b5e61b916b..0f190b9d9a7 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningLineHeaderAnnotation.java @@ -69,7 +69,22 @@ public class CodeMiningLineHeaderAnnotation extends LineHeaderAnnotation impleme * @param viewer the viewer */ public CodeMiningLineHeaderAnnotation(Position position, ISourceViewer viewer) { - super(position, viewer); + this(position, viewer, null, null, null); + } + + /** + * Code mining annotation constructor. + * + * @param position the position + * @param viewer the viewer + * @param onMouseHover the consumer to be called on mouse hover. If set, the implementor needs + * to take care of setting the cursor if wanted. + * @param onMouseOut the consumer to be called on mouse out. If set, the implementor needs to + * take care of resetting the cursor. + * @param onMouseMove the consumer to be called on mouse move + */ + public CodeMiningLineHeaderAnnotation(Position position, ISourceViewer viewer, Consumer onMouseHover, Consumer onMouseOut, Consumer onMouseMove) { + super(position, viewer, onMouseHover, onMouseOut, onMouseMove); fResolvedMinings= null; fMinings= new ArrayList<>(); fBounds= new ArrayList<>(); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java index 2793d1447af..cc9444c7775 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/codemining/CodeMiningManager.java @@ -23,11 +23,13 @@ import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import org.osgi.framework.Bundle; +import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.core.runtime.Assert; @@ -262,7 +264,12 @@ private void renderCodeMinings(Map> groups, ISourceV if (first instanceof LineContentCodeMining m) { afterPosition= m.isAfterPosition(); } - ann= inLineHeader ? new CodeMiningLineHeaderAnnotation(pos, viewer) : new CodeMiningLineContentAnnotation(pos, viewer, afterPosition); + Consumer mouseHover= first != null ? first.getMouseHover() : null; + Consumer mouseOut= first != null ? first.getMouseOut() : null; + Consumer mouseMove= first != null ? first.getMouseMove() : null; + ann= inLineHeader + ? new CodeMiningLineHeaderAnnotation(pos, viewer, mouseHover, mouseOut, mouseMove) + : new CodeMiningLineContentAnnotation(pos, viewer, afterPosition, mouseHover, mouseOut, mouseMove); } else if (ann instanceof ICodeMiningAnnotation && ((ICodeMiningAnnotation) ann).isInVisibleLines()) { // annotation is in visible lines annotationsToRedraw.add((ICodeMiningAnnotation) ann); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/ICodeMining.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/ICodeMining.java index 8e1416deaff..38ca6bd41ff 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/ICodeMining.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/ICodeMining.java @@ -16,6 +16,7 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Color; @@ -115,6 +116,37 @@ public interface ICodeMining { */ Consumer getAction(); + /** + * Returns a consumer which is called when mouse is hovered over the code mining. If set, the + * implementor needs to take care of setting the cursor if wanted. + */ + default Consumer getMouseHover() { + return e -> { + if (e.widget instanceof StyledText st) { + st.setCursor(st.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + } + }; + } + + /** + * Returns a consumer which is called when mouse is moved out of code mining. If set, the + * implementor needs to take care of resetting the cursor. + */ + default Consumer getMouseOut() { + return e -> { + if (e.widget instanceof StyledText st) { + st.setCursor(null); + } + }; + } + + /** + * Returns a consumer which is called when mouse is moved inside the code mining. + */ + default Consumer getMouseMove() { + return null; + } + /** * Dispose the mining. Typically shuts down or cancels all related asynchronous operations. */ diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java index 9f2f10d8497..a09afe85333 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java @@ -62,15 +62,39 @@ public abstract class AbstractInlinedAnnotation extends Annotation { int fY; + private final Consumer onMouseHover; + + private final Consumer onMouseOut; + + private final Consumer onMouseMove; + /** * Inlined annotation constructor. * * @param position the position where the annotation must be drawn. - * @param viewer the {@link ISourceViewer} where the annotation must be drawn. + * @param viewer the {@link ISourceViewer} where the annotation must be drawn. */ protected AbstractInlinedAnnotation(Position position, ISourceViewer viewer) { + this(position, viewer, null, null, null); + } + + /** + * Inlined annotation constructor. + * + * @param position the position where the annotation must be drawn. + * @param viewer the {@link ISourceViewer} where the annotation must be drawn. + * @param onMouseHover the consumer to be called on mouse hover. If set, the implementor needs + * to take care of setting the cursor if wanted. + * @param onMouseOut the consumer to be called on mouse out. If set, the implementor needs to + * take care of resetting the cursor. + * @param onMouseMove the consumer to be called on mouse move + */ + protected AbstractInlinedAnnotation(Position position, ISourceViewer viewer, Consumer onMouseHover, Consumer onMouseOut, Consumer onMouseMove) { super(TYPE, false, ""); //$NON-NLS-1$ this.position= position; + this.onMouseHover= onMouseHover; + this.onMouseOut= onMouseOut; + this.onMouseMove= onMouseMove; } /** @@ -165,8 +189,23 @@ public void draw(GC gc, StyledText textWidget, int widgetOffset, int length, Col * @param e the mouse event */ public void onMouseHover(MouseEvent e) { - StyledText styledText= (StyledText) e.widget; - styledText.setCursor(styledText.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + if (onMouseHover != null) { + onMouseHover.accept(e); + } else { + StyledText styledText= (StyledText) e.widget; + styledText.setCursor(styledText.getDisplay().getSystemCursor(SWT.CURSOR_HAND)); + } + } + + /** + * Called when mouse moved in the inlined annotation. + * + * @param e the mouse event + */ + public void onMouseMove(MouseEvent e) { + if (onMouseMove != null) { + onMouseMove.accept(e); + } } /** @@ -175,8 +214,12 @@ public void onMouseHover(MouseEvent e) { * @param e the mouse event */ public void onMouseOut(MouseEvent e) { - StyledText styledText= (StyledText) e.widget; - styledText.setCursor(null); + if (onMouseOut != null) { + onMouseOut.accept(e); + } else { + StyledText styledText= (StyledText) e.widget; + styledText.setCursor(null); + } } /** diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java index 2f9424847d5..e2fcb597780 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java @@ -198,9 +198,17 @@ private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText text annotation.draw(gc, textWidget, offset, length, color, x, y); } else if (textWidget.getLineVerticalIndent(line) > 0) { // Here vertical indent is done, the redraw of the full line width is done to avoid annotation clipping - Rectangle bounds= textWidget.getTextBounds(offset, offset); Rectangle client= textWidget.getClientArea(); - textWidget.redraw(0, bounds.y, client.width, bounds.height, false); + int y, height; + if (offset < charCount) { + Rectangle bounds= textWidget.getTextBounds(offset, offset); + y= bounds.y; + height= bounds.height; + } else { + y= 0; + height= client.height; + } + textWidget.redraw(0, y, client.width, height, false); } else { if (offset >= charCount) { if (charCount > 0) { diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java index b59ed29c4ba..e6bc1ed8819 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java @@ -290,7 +290,7 @@ public void mouseMove(MouseEvent e) { update(e); if (oldAnnotation != null) { if (oldAnnotation.equals(fAnnotation)) { - // Same annotations which was hovered, do nothing. + fAnnotation.onMouseMove(e); return; } else { oldAnnotation.onMouseOut(e); diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java index 24fffefaf9b..47f45f2752a 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java @@ -13,8 +13,11 @@ */ package org.eclipse.jface.text.source.inlined; +import java.util.function.Consumer; + import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; @@ -48,7 +51,23 @@ public class LineContentAnnotation extends AbstractInlinedAnnotation { * @param viewer the {@link ISourceViewer} where the annotation must be drawn. */ public LineContentAnnotation(Position position, ISourceViewer viewer) { - super(position, viewer); + this(position, viewer, null, null, null); + } + + /** + * Line content annotation constructor. + * + * @param position the position where the annotation must be drawn. + * @param viewer the {@link ISourceViewer} where the annotation must be drawn. + * @param onMouseHover the consumer to be called on mouse hover. If set, the implementor needs + * to take care of setting the cursor if wanted. + * @param onMouseOut the consumer to be called on mouse out. If set, the implementor needs to + * take care of resetting the cursor. + * @param onMouseMove the consumer to be called on mouse move + * @since 3.27 + */ + public LineContentAnnotation(Position position, ISourceViewer viewer, Consumer onMouseHover, Consumer onMouseOut, Consumer onMouseMove) { + super(position, viewer, onMouseHover, onMouseOut, onMouseMove); } /** diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineHeaderAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineHeaderAnnotation.java index 6f8d699d3b0..c6924824a7e 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineHeaderAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineHeaderAnnotation.java @@ -13,7 +13,10 @@ */ package org.eclipse.jface.text.source.inlined; +import java.util.function.Consumer; + import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.MouseEvent; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.ISourceViewer; @@ -34,7 +37,23 @@ public class LineHeaderAnnotation extends AbstractInlinedAnnotation { * @param viewer the {@link ISourceViewer} where the annotation must be drawn. */ public LineHeaderAnnotation(Position position, ISourceViewer viewer) { - super(position, viewer); + this(position, viewer, null, null, null); + } + + /** + * Line header annotation constructor. + * + * @param position the position where the annotation must be drawn. + * @param viewer the {@link ISourceViewer} where the annotation must be drawn. + * @param onMouseHover the consumer to be called on mouse hover. If set, the implementor needs + * to take care of setting the cursor if wanted. + * @param onMouseOut the consumer to be called on mouse out. If set, the implementor needs to + * take care of resetting the cursor. + * @param onMouseMove the consumer to be called on mouse move + * @since 3.27 + */ + public LineHeaderAnnotation(Position position, ISourceViewer viewer, Consumer onMouseHover, Consumer onMouseOut, Consumer onMouseMove) { + super(position, viewer, onMouseHover, onMouseOut, onMouseMove); oldLine= -1; }