Bug 529087 - [CodeMining] Improve draw of line content annotation.
Change-Id: I4aabd08ea87b650722d3e50a77832689feb61521
Signed-off-by: angelozerr <angelo.zerr@gmail.com>
diff --git a/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/ColorAnnotation.java b/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/ColorAnnotation.java
index a6e7a31..3a16961 100644
--- a/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/ColorAnnotation.java
+++ b/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/ColorAnnotation.java
@@ -30,19 +30,17 @@
super(pos, viewer);
}
- @Override
- public int getWidth() {
- StyledText styledText = super.getTextWidget();
- return getSquareWidth(styledText);
- }
-
public void setColor(Color color) {
this.color = color;
}
@Override
- public void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
- int size = getSquareSize(gc.getFontMetrics());
+ protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
+ FontMetrics fontMetrics = gc.getFontMetrics();
+ int size = getSquareSize(fontMetrics);
+ x += fontMetrics.getLeading();
+ y += fontMetrics.getDescent();
+
Rectangle rect = new Rectangle(x, y, size, size);
// Fill square
@@ -52,6 +50,7 @@
// Draw square box
gc.setForeground(textWidget.getForeground());
gc.drawRectangle(rect);
+ return getSquareWidth(gc.getFontMetrics());
}
/**
@@ -70,12 +69,9 @@
* @param styledText
* @return the width of square
*/
- private static int getSquareWidth(StyledText styledText) {
- GC gc = new GC(styledText);
- FontMetrics fontMetrics = gc.getFontMetrics();
+ private static int getSquareWidth(FontMetrics fontMetrics) {
// width = 2 spaces + size width of square
int width = 2 * fontMetrics.getAverageCharWidth() + getSquareSize(fontMetrics);
- gc.dispose();
return width;
}
}
diff --git a/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/InlinedAnnotationDemo.java b/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/InlinedAnnotationDemo.java
index 3f3d815..5043c0c 100644
--- a/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/InlinedAnnotationDemo.java
+++ b/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/sources/inlined/InlinedAnnotationDemo.java
@@ -170,7 +170,7 @@
// Color annotation
if (color != null) {
- Position colorPos = new Position(pos.offset + index + "color:".length(), rgb.length());
+ Position colorPos = new Position(pos.offset + index + "color:".length(), 1);
ColorAnnotation colorAnnotation = support.findExistingAnnotation(colorPos);
if (colorAnnotation == null) {
colorAnnotation = new ColorAnnotation(colorPos, viewer);
@@ -179,6 +179,24 @@
annotations.add(colorAnnotation);
}
+ // rgb parameter names annotations
+ int rgbIndex = line.indexOf("rgb");
+ if (rgbIndex != -1) {
+ rgbIndex = rgbIndex + "rgb".length();
+ int startOffset = pos.offset + rgbIndex;
+ String rgbContent = line.substring(rgbIndex, line.length());
+ int startIndex = addRGBParamNameAnnotation("red:", rgbContent, 0, startOffset, viewer, support,
+ annotations);
+ if (startIndex != -1) {
+ startIndex = addRGBParamNameAnnotation("green:", rgbContent, startIndex, startOffset, viewer,
+ support, annotations);
+ if (startIndex != -1) {
+ startIndex = addRGBParamNameAnnotation("blue:", rgbContent, startIndex, startOffset,
+ viewer, support, annotations);
+ }
+ }
+ }
+
} catch (BadLocationException e) {
e.printStackTrace();
}
@@ -188,6 +206,41 @@
}
/**
+ * Add RGB parameter name annotation
+ *
+ * @param paramName
+ * @param rgbContent
+ * @param startIndex
+ * @param startOffset
+ * @param viewer
+ * @param support
+ * @param annotations
+ * @return the current parsed index
+ */
+ private static int addRGBParamNameAnnotation(String paramName, String rgbContent, int startIndex, int startOffset,
+ ISourceViewer viewer, InlinedAnnotationSupport support, Set<AbstractInlinedAnnotation> annotations) {
+ char startChar = startIndex == 0 ? '(' : ',';
+ char[] chars = rgbContent.toCharArray();
+ for (int i = startIndex; i < chars.length; i++) {
+ char c = chars[i];
+ if (c == startChar) {
+ if (i == chars.length - 1) {
+ return -1;
+ }
+ Position paramPos = new Position(startOffset + i + 1, 1);
+ LineContentAnnotation colorParamAnnotation = support.findExistingAnnotation(paramPos);
+ if (colorParamAnnotation == null) {
+ colorParamAnnotation = new LineContentAnnotation(paramPos, viewer);
+ }
+ colorParamAnnotation.setText(paramName);
+ annotations.add(colorParamAnnotation);
+ return i + 1;
+ }
+ }
+ return -1;
+ }
+
+ /**
* Parse the given input rgb color and returns an instance of SWT Color and null
* otherwise.
*
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java
index 8a9647f..cb9dd36 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java
@@ -13,7 +13,6 @@
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.GlyphMetrics;
import org.eclipse.swt.graphics.Rectangle;
@@ -52,14 +51,6 @@
*/
public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
Color color) {
- if (annotation.isMarkedDeleted()) {
- // When annotation is deleted, redraw the styled text to hide old draw of
- // annotations
- textWidget.redraw();
- // update caret offset since line spacing has changed.
- textWidget.setCaretOffset(textWidget.getCaretOffset());
- return;
- }
if (annotation instanceof LineHeaderAnnotation) {
draw((LineHeaderAnnotation) annotation, gc, textWidget, offset, length, color);
} else {
@@ -79,6 +70,14 @@
*/
private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
Color color) {
+ if (annotation.isMarkedDeleted()) {
+ // When annotation is deleted, redraw the styled text to hide old draw of
+ // annotations
+ textWidget.redraw();
+ // update caret offset since line spacing has changed.
+ textWidget.setCaretOffset(textWidget.getCaretOffset());
+ return;
+ }
// compute current, previous line index.
int lineIndex= -1;
try {
@@ -93,6 +92,10 @@
if (viewer instanceof ITextViewerExtension5) {
firstLineIndex= ((ITextViewerExtension5) viewer).modelLine2WidgetLine(firstLineIndex);
}
+ if (previousLineIndex < firstLineIndex) {
+ // the previous line index where annotation must be drawn in line spacing is hidden, don't draw it.
+ return;
+ }
if (gc != null) {
// Compute the location of the annotation
int x= textWidget.getLocationAtOffset(offset).x;
@@ -146,31 +149,65 @@
*/
private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
Color color) {
+ StyleRange style= null;
+ try {
+ style= textWidget.getStyleRangeAtOffset(offset);
+ } catch (Exception e) {
+ return;
+ }
+ if (annotation.isMarkedDeleted()) {
+ // When annotation is deleted, update metrics to null to remove extra spaces of the line content annotation.
+ if (style != null) {
+ style.metrics= null;
+ textWidget.setStyleRange(style);
+ }
+ return;
+ }
if (gc != null) {
// Compute the location of the annotation
- FontMetrics fontMetrics= gc.getFontMetrics();
Rectangle bounds= textWidget.getTextBounds(offset, offset);
- int x= bounds.x + fontMetrics.getLeading();
- int y= bounds.y + fontMetrics.getDescent();
+ int x= bounds.x;
+ int y= bounds.y;
// Draw the line content annotation
annotation.draw(gc, textWidget, offset, length, color, x, y);
-
- // The inline annotation replaces one character by taking a place width
- // GlyphMetrics
- // Here we need to redraw this first character because GlyphMetrics clip this
- // character.
- String s= textWidget.getText(offset, offset);
- StyleRange style= textWidget.getStyleRangeAtOffset(offset);
- if (style != null) {
- if (style.background != null) {
- gc.setBackground(style.background);
+ // check the width annotation
+ int width= annotation.getWidth();
+ GlyphMetrics metrics= style != null ? style.metrics : null;
+ if (metrics == null || metrics.width != width) {
+ // The annotation drawn width is not the same than metrics width, update it.
+ if (metrics == null) {
+ metrics= new GlyphMetrics(0, 0, width);
+ } else {
+ metrics.width= width;
}
- if (style.foreground != null) {
- gc.setForeground(style.foreground);
+ if (style == null) {
+ style= new StyleRange();
+ style.start= offset;
+ style.length= 1;
+ style.background= textWidget.getBackground();
+ style.foreground= textWidget.getForeground();
}
+ style.metrics= metrics;
+ textWidget.setStyleRange(style);
+ return;
}
- gc.drawString(s, bounds.x + bounds.width - gc.stringExtent(s).x, bounds.y, true);
+ if (width != 0) {
+ // The inline annotation replaces one character by taking a place width
+ // GlyphMetrics
+ // Here we need to redraw this first character because GlyphMetrics clip this
+ // character.
+ String s= textWidget.getText(offset, offset);
+ if (style != null) {
+ if (style.background != null) {
+ gc.setBackground(style.background);
+ }
+ if (style.foreground != null) {
+ gc.setForeground(style.foreground);
+ }
+ }
+ gc.drawString(s, bounds.x + bounds.width - gc.stringExtent(s).x, bounds.y, true);
+ }
} else {
textWidget.redrawRange(offset, length, true);
}
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java
index 33df72f..0d20e10 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationSupport.java
@@ -21,7 +21,6 @@
import java.util.function.Consumer;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextLineSpacingProvider;
import org.eclipse.swt.graphics.Color;
@@ -140,7 +139,6 @@
if (annotationModel == null) {
return;
}
- StyledText styledText= fViewer.getTextWidget();
Map<AbstractInlinedAnnotation, Position> annotationsToAdd= new HashMap<>();
List<AbstractInlinedAnnotation> annotationsToRemove= fInlinedAnnotations != null
? new ArrayList<>(fInlinedAnnotations)
@@ -151,32 +149,11 @@
// The annotation was not created, add it
annotationsToAdd.put(ann, ann.getPosition());
}
- if (ann instanceof LineContentAnnotation) {
- // Create metrics with well width to add space where the inline annotation must
- // be drawn.
- runInUIThread(styledText, (text) -> {
- StyleRange s= new StyleRange();
- s.start= ann.getPosition().getOffset();
- s.length= 1;
- s.metrics= ((LineContentAnnotation) ann).createMetrics();
- text.setStyleRange(s);
- });
- }
}
// Process annotations to remove
for (AbstractInlinedAnnotation ann : annotationsToRemove) {
// Mark annotation as deleted to ignore the draw
ann.markDeleted(true);
- if (ann instanceof LineContentAnnotation) {
- // Set metrics to null to remove space of the inline annotation
- runInUIThread(styledText, (text) -> {
- StyleRange s= new StyleRange();
- s.start= ann.getPosition().getOffset();
- s.length= 1;
- s.metrics= null;
- text.setStyleRange(s);
- });
- }
}
// Update annotation model
synchronized (getLockObject(annotationModel)) {
@@ -217,7 +194,7 @@
return null;
}
for (AbstractInlinedAnnotation ann : fInlinedAnnotations) {
- if (ann.getPosition().offset == pos.offset) {
+ if (pos.equals(ann.getPosition()) && !ann.getPosition().isDeleted()) {
try {
return (T) ann;
} catch (ClassCastException e) {
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java
index e2aae83..7b136c7 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java
@@ -11,9 +11,8 @@
package org.eclipse.jface.text.source.inlined;
import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.GlyphMetrics;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.ISourceViewer;
@@ -27,6 +26,11 @@
public class LineContentAnnotation extends AbstractInlinedAnnotation {
/**
+ * The annotation width
+ */
+ private int width;
+
+ /**
* Line content annotation constructor.
*
* @param position the position where the annotation must be drawn.
@@ -37,32 +41,41 @@
}
/**
- * Returns an instance of GlyphMetrics used to takes 'width' place when the annotation is drawn
- * inside the line.
- *
- * @return an instance of GlyphMetrics used to takes 'width' place when the annotation is drawn
- * inside the line.
- */
- public GlyphMetrics createMetrics() {
- return new GlyphMetrics(0, 0, getWidth());
- }
-
- /**
* Returns the annotation width. By default it computes the well width for the text annotation.
*
* @return the annotation width.
*/
- public int getWidth() {
- String text= super.getText();
- if (text == null) {
- return 0;
- }
- int nbChars= text.length() + 1;
- StyledText styledText= super.getTextWidget();
- GC gc= new GC(styledText);
- FontMetrics fontMetrics= gc.getFontMetrics();
- int width= nbChars * fontMetrics.getAverageCharWidth();
- gc.dispose();
+ public final int getWidth() {
return width;
}
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * After drawn, compute the text width and update it.
+ * </p>
+ */
+ @Override
+ public final void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
+ width= drawAndComputeWidth(gc, textWidget, offset, length, color, x, y);
+ }
+
+ /**
+ * Draw the inlined annotation. By default it draws the text of the annotation with gray color.
+ * User can override this method to draw anything.
+ *
+ * @param gc the graphics context
+ * @param textWidget the text widget to draw on
+ * @param offset the offset of the line
+ * @param length the length of the line
+ * @param color the color of the line
+ * @param x the x position of the annotation
+ * @param y the y position of the annotation
+ * @return the text width.
+ */
+ protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
+ // Draw the text annotation and returns the width
+ super.draw(gc, textWidget, offset, length, color, x, y);
+ return gc.stringExtent(getText()).x + 2 * gc.getFontMetrics().getAverageCharWidth();
+ }
}