Skip to content

Commit b2d270d

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 b2d270d

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-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/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java

Lines changed: 90 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,92 @@ 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+
int visibleRegionStart= documentContent.indexOf("visible_region_start");
393+
int visibleRegionEnd= documentContent.indexOf("\n", documentContent.indexOf("visible_region_end")) + 1;
394+
395+
int projectionStart= documentContent.indexOf("projection_start");
396+
int projectionEnd= documentContent.indexOf("\n", documentContent.indexOf("projection_end")) + 1;
397+
398+
viewer.setVisibleRegion(visibleRegionStart, visibleRegionEnd - visibleRegionStart);
399+
viewer.enableProjection();
400+
ProjectionAnnotation annotation= new ProjectionAnnotation();
401+
viewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(projectionStart, projectionEnd - projectionStart));
402+
try {
403+
assertEquals("""
404+
visible_region_start
405+
406+
projection_start
407+
408+
visible_region_end
409+
""", viewer.getVisibleDocument().get());
410+
411+
annotation.paint(null, null, null); //should exit early and not throw NPE
412+
} finally {
413+
shell.dispose();
414+
}
415+
}
416+
417+
@Test
418+
public void testProjectionRegionsShownWithinVisibleRegion() {
419+
Shell shell= new Shell(Display.getCurrent());
420+
shell.setLayout(new FillLayout());
421+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
422+
String documentContent= """
423+
424+
visible_region_start
425+
426+
projection_start
427+
428+
projection_end
429+
430+
visible_region_end
431+
432+
""";
433+
Document document= new Document(documentContent);
434+
viewer.setDocument(document, new AnnotationModel());
435+
int visibleRegionStart = documentContent.indexOf("visible_region_start");
436+
int visibleRegionEnd = documentContent.indexOf("\n", documentContent.indexOf("visible_region_end"))+1;
437+
438+
int projectionStart= documentContent.indexOf("projection_start");
439+
int projectionEnd= documentContent.indexOf("\n", documentContent.indexOf("projection_end")) + 1;
440+
441+
viewer.setVisibleRegion(visibleRegionStart, visibleRegionEnd - visibleRegionStart);
442+
viewer.enableProjection();
443+
ProjectionAnnotation annotation= new ProjectionAnnotation();
444+
viewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(projectionStart, projectionEnd - projectionStart));
445+
try {
446+
assertEquals("""
447+
visible_region_start
448+
449+
projection_start
450+
451+
projection_end
452+
453+
visible_region_end
454+
""", viewer.getVisibleDocument().get());
455+
456+
assertThrows(NullPointerException.class, () -> annotation.paint(null, null, null), "expected to run painting logic");
457+
} finally {
458+
shell.dispose();
459+
}
460+
}
371461
}

0 commit comments

Comments
 (0)