| /******************************************************************************* |
| * Copyright (c) 2019 Red Hat Inc. and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| package org.eclipse.jface.text.tests.source.inlined; |
| |
| import java.util.Collections; |
| |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.widgets.Shell; |
| |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.ITextViewerExtension2; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.AnnotationModel; |
| import org.eclipse.jface.text.source.AnnotationPainter; |
| import org.eclipse.jface.text.source.IAnnotationAccess; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.jface.text.source.SourceViewer; |
| import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport; |
| import org.eclipse.jface.text.source.inlined.LineContentAnnotation; |
| import org.eclipse.jface.text.tests.util.DisplayHelper; |
| |
| /** |
| * This test verify that the bounds of the text as returned by StyledText.getTextBounds() |
| * actually match what's printed on the widget. |
| */ |
| @RunWith(Parameterized.class) |
| public class LineContentBoundsDrawingTest { |
| @Parameters(name="{0}") |
| public static String[] contents() { |
| return new String[] { |
| "annotation inside text", |
| " annotation just after initial space", |
| "\tannoation just after initial tab" |
| }; |
| } |
| |
| private String text; |
| |
| public LineContentBoundsDrawingTest(String text) { |
| this.text = text; |
| } |
| |
| public static final class AccessAllAnnoations implements IAnnotationAccess { |
| @Override |
| public Object getType(Annotation annotation) { |
| return annotation.getType(); |
| } |
| |
| @Override |
| public boolean isMultiLine(Annotation annotation) { |
| return true; |
| } |
| |
| @Override |
| public boolean isTemporary(Annotation annotation) { |
| return true; |
| } |
| } |
| |
| public static final class TestAnnotationPainter extends AnnotationPainter { |
| private boolean painted; |
| |
| public TestAnnotationPainter(ISourceViewer sourceViewer, IAnnotationAccess access) { |
| super(sourceViewer, access); |
| } |
| |
| @Override |
| public void paint(int reason) { |
| this.painted = true; |
| super.paint(reason); |
| } |
| |
| public boolean wasPainted() { |
| return this.painted; |
| } |
| } |
| |
| private Shell fParent; |
| |
| @Before |
| public void setUp() { |
| fParent= new Shell(); |
| } |
| |
| @After |
| public void tearDown() { |
| fParent.dispose(); |
| fParent = null; |
| } |
| |
| @Test |
| public void testTextBoundsMatchPaintedArea() { |
| fParent.setLayout(new FillLayout()); |
| |
| // Create source viewer and initialize the content |
| ISourceViewer sourceViewer = new SourceViewer(fParent,null, |
| SWT.V_SCROLL | SWT.BORDER); |
| sourceViewer.setDocument(new Document(this.text), new AnnotationModel()); |
| |
| // Initialize inlined annotations support |
| InlinedAnnotationSupport support = new InlinedAnnotationSupport(); |
| IAnnotationAccess annotationAccess = new AccessAllAnnoations(); |
| TestAnnotationPainter painter = new TestAnnotationPainter(sourceViewer, annotationAccess); |
| ((ITextViewerExtension2) sourceViewer).addPainter(painter); |
| support.install(sourceViewer, painter); |
| |
| // add annotations |
| LineContentAnnotation annotation= new LineContentAnnotation(new Position(1, 1), sourceViewer); |
| annotation.setText("longAnnationToDisplayOnTab"); |
| support.updateAnnotations(Collections.singleton(annotation)); |
| fParent.open(); |
| StyledText textWidget= sourceViewer.getTextWidget(); |
| Assert.assertTrue(new DisplayHelper() { |
| @Override |
| protected boolean condition() { |
| return textWidget.isVisible() && painter.wasPainted(); |
| } |
| }.waitForCondition(textWidget.getDisplay(), 2000)); |
| DisplayHelper.sleep(textWidget.getDisplay(), 1000); |
| // XXX disabled due bug 549110 |
| // Rectangle textBounds= textWidget.getTextBounds(0, textWidget.getText().length() - 1); |
| // int supposedMostRightPaintedPixel = textBounds.x + textBounds.width - 1; |
| // int mostRightPaintedPixel= getMostRightPaintedPixel(textWidget); |
| // Assert.assertEquals(supposedMostRightPaintedPixel, mostRightPaintedPixel, 1.5); // use double comparison with delta to tolerate variation from a system to the other |
| } |
| |
| public int getMostRightPaintedPixel(StyledText widget) { |
| Image image = new Image(widget.getDisplay(), widget.getSize().x, widget.getSize().y); |
| GC gc = new GC(widget); |
| gc.copyArea(image, 0, 0); |
| gc.dispose(); |
| RGB backgroundRgb = widget.getBackground().getRGB(); |
| ImageData imageData = image.getImageData(); |
| for (int x = imageData.width - 50 /* magic number to avoid rulers and other */; x >= 0; x--) { |
| for (int y = 3 /* magic number as well to avoid title bar */; y < imageData.height - 3; y++) { |
| if (!imageData.palette.getRGB(imageData.getPixel(x, y)).equals(backgroundRgb)) { |
| image.dispose(); |
| return x; |
| } |
| } |
| } |
| image.dispose(); |
| return -1; |
| } |
| } |