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 9a09905e83e..a0dae7975eb 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 @@ -47,6 +47,7 @@ import org.eclipse.jface.text.codemining.ICodeMiningProvider; import org.eclipse.jface.text.codemining.LineContentCodeMining; import org.eclipse.jface.text.codemining.LineHeaderCodeMining; +import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation; import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport; @@ -349,4 +350,14 @@ private static ICodeMining getCodeValidMiningAtIndex(ICodeMining[] minings, int } return null; } + + /** + * returns true if the given annotation is a deleted {@link ICodeMiningAnnotation} + */ + public static boolean isDeletedCodeMining(Annotation annotation) { + if (annotation.isMarkedDeleted() && annotation instanceof ICodeMiningAnnotation) { + return true; + } + return false; + } } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java index 27d85d1ea12..42e87fe7ed6 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/AnnotationPainter.java @@ -41,6 +41,8 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.internal.text.codemining.CodeMiningManager; + import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IPaintPositionManager; @@ -1425,7 +1427,7 @@ private void drawDecoration(Decoration pp, GC gc, Annotation annotation, IRegion // textWidget.redrawRange with length 0 is ignored and no redraw takes place paintLength= lineDelimiter.length(); } - if (paintLength >= 0 && regionsTouchOrOverlap(paintStart, paintLength, clippingOffset, clippingLength)) { + if ((paintLength >= 0 && regionsTouchOrOverlap(paintStart, paintLength, clippingOffset, clippingLength) || CodeMiningManager.isDeletedCodeMining(annotation))) { // otherwise inside a line delimiter IRegion widgetRange= getWidgetRange(paintStart, paintLength); if (widgetRange != 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 130afce1a2c..222aeac72bd 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 @@ -27,6 +27,7 @@ import org.eclipse.jface.internal.text.codemining.CodeMiningDocumentFooterAnnotation; import org.eclipse.jface.internal.text.codemining.CodeMiningLineContentAnnotation; import org.eclipse.jface.internal.text.codemining.CodeMiningLineHeaderAnnotation; +import org.eclipse.jface.internal.text.codemining.CodeMiningManager; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Position; @@ -79,7 +80,8 @@ public void draw(Annotation annotation, GC gc, StyledText textWidget, int widget } InlinedAnnotationSupport support = InlinedAnnotationSupport.getSupport(textWidget); inlinedAnnotation.setSupport(support); - if (support.isInVisibleLines(inlinedAnnotation.getPosition().offset) && inlinedAnnotation.isFirstVisibleOffset(widgetOffset, viewer)) { + if ((support.isInVisibleLines(inlinedAnnotation.getPosition().offset) || CodeMiningManager.isDeletedCodeMining(annotation)) + && inlinedAnnotation.isFirstVisibleOffset(widgetOffset, viewer)) { GCConfig initialGCConfig = GCConfig.fromGC(gc); GCConfig annotationGCConfig = new GCConfig(color, textWidget.getBackground(), getAnnotationFont(textWidget)); annotationGCConfig.applyTo(gc); diff --git a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java index 5405b9d3cb0..a64873b5532 100644 --- a/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java +++ b/tests/org.eclipse.e4.ui.tests/src/org/eclipse/e4/ui/tests/workbench/PartRenderingEngineTests.java @@ -65,6 +65,7 @@ import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.Widget; import org.eclipse.test.Screenshots; +import org.eclipse.ui.tests.harness.util.DisplayHelper; import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -2469,7 +2470,8 @@ public void ensureCleanUpAddonCleansUp() { assertTrue(" PartStack with children should be rendered", partStackForPartBPartC.isToBeRendered()); partService.hidePart(partB); partService.hidePart(partC); - contextRule.spinEventLoop(); + DisplayHelper.waitForCondition(Display.getDefault(), 5_000, + () -> partStackForPartBPartC.isToBeRendered() == false); assertFalse( "CleanupAddon should ensure that partStack is not rendered anymore, as all childs have been removed", partStackForPartBPartC.isToBeRendered()); diff --git a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java index 9abe1e3a6b5..3dd123edf01 100644 --- a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java +++ b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.jface.text.tests.codemining; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.text.SimpleDateFormat; import java.util.Date; @@ -22,6 +24,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; @@ -108,6 +111,57 @@ public void run(IProgressMonitor monitor) throws CoreException { }, new NullProgressMonitor()); } + @Test + public void testClearCodeMiningTextEditorDecorationIfInInvisibleArea() throws Exception { + IFile file = project.getFile("test.testprojectionviewer"); + if (file.exists()) { + file.delete(true, new NullProgressMonitor()); + } + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 100; i++) { + b.append("line ").append(i).append("\n"); + } + String source = b.toString(); + file.create(new ByteArrayInputStream(source.getBytes("UTF-8")), true, new NullProgressMonitor()); + CodeMiningTestProvider.provideHeaderMiningAtLine = 96; + CodeMiningTestProvider.lineHeaderMiningText = "first line header\n secone line header\n third line header"; + int offsetAtLine95 = source.indexOf("95"); + CodeMiningTestProvider.provideContentMiningAtOffset = offsetAtLine95; + IEditorPart editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file); + drainEventQueue(); + ISourceViewer viewer = (ISourceViewer) editor.getAdapter(ITextViewer.class); + StyledText styledText = viewer.getTextWidget(); + viewer.setSelectedRange(offsetAtLine95, 0); + viewer.revealRange(offsetAtLine95, 1); + drainEventQueue(); + // assert line vertical height and styleRange is created by rendering + // the codeminings + waitForCondition(Display.getDefault(), 10_000, new Callable() { + + @Override + public Boolean call() throws Exception { + return styledText.getLineVerticalIndent(CodeMiningTestProvider.provideHeaderMiningAtLine) > 0; + } + }); + StyleRange style = styledText.getStyleRangeAtOffset(offsetAtLine95 - 1); + assertTrue(style.metrics.width > 0); + // scroll to top so that code minings are not in visible area + viewer.setSelectedRange(0, 0); + viewer.revealRange(0, 1); + // remove code minings and call update + CodeMiningTestProvider.provideContentMiningAtOffset = -1; + CodeMiningTestProvider.provideHeaderMiningAtLine = -1; + ((ISourceViewerExtension5) viewer).updateCodeMinings(); + drainEventQueue(); + // assert that line vertical height and styleRange was removed after + // deleting the codeminings + for (int i = 0; i < 100; i++) { + assertTrue("line vertical indent not zeri at line index " + i, styledText.getLineVerticalIndent(i) == 0); + } + style = styledText.getStyleRangeAtOffset(offsetAtLine95 - 1); + assertTrue(style == null); + } + @Test public void testInlinedAnnotationSupportIsInLinesReturnsValidResultAfterDocumentChange() throws Exception { IFile file = project.getFile("test.testprojectionviewer");