Skip to content

Commit 2bf7aa8

Browse files
committed
hide projection annotations outside of the current visible region
Projection regions that overlap with parts of the file outside of the current visible region cannot be collapsed hence their annotations should not be painted.
1 parent 937cbb2 commit 2bf7aa8

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionAnnotation.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public void run() {
7373
/** Indicates whether this annotation should be painted as range */
7474
private boolean fIsRangeIndication= false;
7575

76+
private boolean hidden= false;
77+
7678
/**
7779
* Creates a new expanded projection annotation.
7880
*/
@@ -115,6 +117,9 @@ private void drawRangeIndication(GC gc, Canvas canvas, Rectangle r) {
115117

116118
@Override
117119
public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
120+
if (hidden) {
121+
return;
122+
}
118123
Image image= getImage(canvas.getDisplay());
119124
if (image != null) {
120125
ImageUtilities.drawImage(image, gc, canvas, rectangle, SWT.CENTER, SWT.TOP);
@@ -128,6 +133,10 @@ public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
128133
}
129134
}
130135

136+
void setHidden(boolean hidden) {
137+
this.hidden= hidden;
138+
}
139+
131140
@Override
132141
public int getLayer() {
133142
return IAnnotationPresentation.DEFAULT_LAYER;

bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ private void processModelChanged(IAnnotationModel model, AnnotationModelEvent ev
124124
fProjectionSummary.updateSummaries();
125125
}
126126
processCatchupRequest(event);
127+
correctChangedAnnotationVisibility(event);
127128

128129
} else if (model == getAnnotationModel() && fProjectionSummary != null) {
129130
fProjectionSummary.updateSummaries();
@@ -773,12 +774,31 @@ public void setVisibleRegion(int start, int length) {
773774
expandOutsideCurrentVisibleRegion(document);
774775
collapseOutsideOfNewVisibleRegion(start, end, document);
775776
fConfiguredVisibleRegion= new Region(start, end - start - 1);
777+
hideProjectionAnnotationsOutsideOfVisibleRegion();
776778
} catch (BadLocationException e) {
777779
ILog log= ILog.of(getClass());
778780
log.log(new Status(IStatus.WARNING, getClass(), IStatus.OK, null, e));
779781
}
780782
}
781783

784+
private void hideProjectionAnnotationsOutsideOfVisibleRegion() throws BadLocationException {
785+
for (Iterator<Annotation> it= fProjectionAnnotationModel.getAnnotationIterator(); it.hasNext();) {
786+
Annotation annotation= it.next();
787+
hideProjectionAnnotationIfPartsAreOutsideOfVisibleRegion(annotation);
788+
}
789+
}
790+
791+
private void hideProjectionAnnotationIfPartsAreOutsideOfVisibleRegion(Annotation annotation) throws BadLocationException {
792+
Position position= fProjectionAnnotationModel.getPosition(annotation);
793+
if (annotation instanceof ProjectionAnnotation a) {
794+
if (overlapsWithNonVisibleRegions(position.getOffset(), position.getLength())) {
795+
a.setHidden(true);
796+
} else {
797+
a.setHidden(false);
798+
}
799+
}
800+
}
801+
782802
private void expandOutsideCurrentVisibleRegion(IDocument document) throws BadLocationException {
783803
if (fConfiguredVisibleRegion != null) {
784804
expand(0, fConfiguredVisibleRegion.getOffset(), false, true);
@@ -855,6 +875,12 @@ public void resetVisibleRegion() {
855875
super.resetVisibleRegion();
856876
}
857877
fConfiguredVisibleRegion= null;
878+
for (Iterator<Annotation> it= fProjectionAnnotationModel.getAnnotationIterator(); it.hasNext();) {
879+
Annotation annotation= it.next();
880+
if (annotation instanceof ProjectionAnnotation a) {
881+
a.setHidden(false);
882+
}
883+
}
858884
}
859885

860886
@Override
@@ -1090,6 +1116,20 @@ protected final void postCatchupRequest(final AnnotationModelEvent event) {
10901116
}
10911117
}
10921118

1119+
private void correctChangedAnnotationVisibility(AnnotationModelEvent event) {
1120+
try {
1121+
for (Annotation annotation : event.getAddedAnnotations()) {
1122+
hideProjectionAnnotationIfPartsAreOutsideOfVisibleRegion(annotation);
1123+
}
1124+
for (Annotation annotation : event.getChangedAnnotations()) {
1125+
hideProjectionAnnotationIfPartsAreOutsideOfVisibleRegion(annotation);
1126+
}
1127+
} catch (BadLocationException e) {
1128+
ILog log= ILog.of(getClass());
1129+
log.log(new Status(IStatus.WARNING, getClass(), IStatus.OK, null, e));
1130+
}
1131+
}
1132+
10931133
/**
10941134
* Tests whether the visible document's master document
10951135
* is identical to this viewer's document.

tests/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Import-Package: org.mockito,
3030
org.mockito.invocation,
3131
org.mockito.stubbing,
3232
org.junit.jupiter.api;version="[5.14.0,6.0.0)",
33+
org.junit.jupiter.api.function;version="[5.14.0,6.0.0)",
3334
org.junit.jupiter.params;version="[5.14.0,6.0.0)",
3435
org.junit.jupiter.params.provider;version="[5.14.0,6.0.0)",
3536
org.junit.platform.suite.api;version="[1.14.0,2.0.0)"

tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.eclipse.jface.text.tests;
1212

1313
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertThrows;
1415

1516
import org.junit.jupiter.api.Test;
1617

@@ -19,6 +20,7 @@
1920
import org.eclipse.swt.dnd.TextTransfer;
2021
import org.eclipse.swt.layout.FillLayout;
2122
import org.eclipse.swt.widgets.Composite;
23+
import org.eclipse.swt.widgets.Display;
2224
import org.eclipse.swt.widgets.Shell;
2325

2426
import org.eclipse.jface.text.BadLocationException;
@@ -368,4 +370,88 @@ public void testRemoveEntireVisibleRegion() throws BadLocationException {
368370
shell.dispose();
369371
}
370372
}
373+
374+
@Test
375+
public void testProjectionRegionsShownOnlyInVisibleRegion() {
376+
Shell shell= new Shell(Display.getCurrent());
377+
shell.setLayout(new FillLayout());
378+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
379+
String documentContent= """
380+
381+
visible_region_start
382+
383+
projection_start
384+
385+
visible_region_end
386+
387+
projection_end
388+
389+
""";
390+
Document document= new Document(documentContent);
391+
viewer.setDocument(document, new AnnotationModel());
392+
ProjectionAnnotation annotation= addVisibleRegionAndProjection(viewer, documentContent);
393+
try {
394+
assertEquals("""
395+
visible_region_start
396+
397+
projection_start
398+
399+
visible_region_end
400+
""", viewer.getVisibleDocument().get());
401+
402+
annotation.paint(null, null, null); //should exit early and not throw NPE
403+
} finally {
404+
shell.dispose();
405+
}
406+
}
407+
408+
@Test
409+
public void testProjectionRegionsShownWithinVisibleRegion() {
410+
Shell shell= new Shell(Display.getCurrent());
411+
shell.setLayout(new FillLayout());
412+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
413+
String documentContent= """
414+
415+
visible_region_start
416+
417+
projection_start
418+
419+
projection_end
420+
421+
visible_region_end
422+
423+
""";
424+
Document document= new Document(documentContent);
425+
viewer.setDocument(document, new AnnotationModel());
426+
ProjectionAnnotation annotation= addVisibleRegionAndProjection(viewer, documentContent);
427+
try {
428+
assertEquals("""
429+
visible_region_start
430+
431+
projection_start
432+
433+
projection_end
434+
435+
visible_region_end
436+
""", viewer.getVisibleDocument().get());
437+
438+
assertThrows(NullPointerException.class, () -> annotation.paint(null, null, null), "expected to run painting logic");
439+
} finally {
440+
shell.dispose();
441+
}
442+
}
443+
444+
private ProjectionAnnotation addVisibleRegionAndProjection(TestProjectionViewer viewer, String documentContent) {
445+
int visibleRegionStart= documentContent.indexOf("visible_region_start");
446+
int visibleRegionEnd= documentContent.indexOf("\n", documentContent.indexOf("visible_region_end")) + 1;
447+
448+
int projectionStart= documentContent.indexOf("projection_start");
449+
int projectionEnd= documentContent.indexOf("\n", documentContent.indexOf("projection_end")) + 1;
450+
451+
viewer.setVisibleRegion(visibleRegionStart, visibleRegionEnd - visibleRegionStart);
452+
viewer.enableProjection();
453+
ProjectionAnnotation annotation= new ProjectionAnnotation();
454+
viewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(projectionStart, projectionEnd - projectionStart));
455+
return annotation;
456+
}
371457
}

0 commit comments

Comments
 (0)