Skip to content

Commit f34844d

Browse files
committed
Allow using visible regions with projections eclipse-platform#3073
While ProjectionViewer supports both using visible regions and projections, these features cannot be used in conjunction. This change allows the use of projections when visible regions are used. Fixes eclipse-platform#3074
1 parent d2177cf commit f34844d

File tree

2 files changed

+293
-3
lines changed

2 files changed

+293
-3
lines changed

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

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
import org.eclipse.swt.dnd.TextTransfer;
2929
import org.eclipse.swt.dnd.Transfer;
3030
import org.eclipse.swt.events.VerifyEvent;
31+
import org.eclipse.swt.graphics.GC;
3132
import org.eclipse.swt.graphics.Point;
33+
import org.eclipse.swt.graphics.Rectangle;
34+
import org.eclipse.swt.widgets.Canvas;
3235
import org.eclipse.swt.widgets.Composite;
3336
import org.eclipse.swt.widgets.Display;
3437

@@ -99,6 +102,7 @@ public class ProjectionViewer extends SourceViewer implements ITextViewerExtensi
99102
*/
100103
public static final int COLLAPSE_ALL= BASE + 5;
101104

105+
102106
/**
103107
* Internal listener to changes of the annotation model.
104108
*/
@@ -272,6 +276,77 @@ private void computeExpectedExecutionCosts() {
272276
}
273277
}
274278

279+
/**
280+
* A {@link ProjectionAnnotation} that is always collapsed and invisible.
281+
*/
282+
private static class InvisibleCollapsedProjectionAnnotation extends ProjectionAnnotation {
283+
public InvisibleCollapsedProjectionAnnotation() {
284+
super(true);
285+
}
286+
287+
@Override
288+
public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
289+
}
290+
}
291+
292+
/**
293+
* An {@link IProjectionPosition} that includes hiding the offset and length.
294+
*/
295+
private static class ExactRegionProjectionPosition extends Position implements IProjectionPosition {
296+
297+
public ExactRegionProjectionPosition(int offset, int length) {
298+
super(offset, length);
299+
}
300+
301+
@Override
302+
public IRegion[] computeProjectionRegions(IDocument document) throws BadLocationException {
303+
return new IRegion[] {
304+
new Region(getOffset(), getLength())
305+
};
306+
}
307+
308+
@Override
309+
public int computeCaptionOffset(IDocument document) throws BadLocationException {
310+
return 0;
311+
}
312+
313+
}
314+
315+
/**
316+
* An {@link IDocumentListener} that makes sure that {@link #fVisibleRegionDuringProjection} is
317+
* updated when the document changes and ensures that the collapsed region after the visible
318+
* region is recreated appropriately.
319+
*/
320+
private final class UpdateDocumentListener implements IDocumentListener {
321+
@Override
322+
public void documentChanged(DocumentEvent event) {
323+
if (fVisibleRegionDuringProjection != null) {
324+
int oldLength= event.getLength();
325+
int newLength= event.getText().length();
326+
int oldVisibleRegionEnd= fVisibleRegionDuringProjection.getOffset() + fVisibleRegionDuringProjection.getLength();
327+
328+
if (oldVisibleRegionEnd >= event.getOffset() && oldVisibleRegionEnd <= event.getOffset() + event.getLength()) {
329+
// If the end of the visible region is modified, the projection annotation needs to be recreated
330+
int newVisibleRegionEnd= event.getOffset() + newLength;
331+
fProjectionAnnotationModel.addAnnotation(new InvisibleCollapsedProjectionAnnotation(), new Position(newVisibleRegionEnd, getDocument().getLength() - newVisibleRegionEnd));
332+
fVisibleRegionDuringProjection= new Region(fVisibleRegionDuringProjection.getOffset(), newVisibleRegionEnd - fVisibleRegionDuringProjection.getOffset());
333+
}
334+
335+
if (event.getOffset() < fVisibleRegionDuringProjection.getOffset()) {
336+
fVisibleRegionDuringProjection= new Region(fVisibleRegionDuringProjection.getOffset() + newLength - oldLength, fVisibleRegionDuringProjection.getLength());
337+
} else {
338+
if (event.getOffset() + oldLength < oldVisibleRegionEnd) {
339+
fVisibleRegionDuringProjection= new Region(fVisibleRegionDuringProjection.getOffset(), fVisibleRegionDuringProjection.getLength() + newLength - oldLength);
340+
}
341+
}
342+
}
343+
}
344+
345+
@Override
346+
public void documentAboutToBeChanged(DocumentEvent event) {
347+
}
348+
}
349+
275350
/** The projection annotation model used by this viewer. */
276351
private ProjectionAnnotationModel fProjectionAnnotationModel;
277352
/** The annotation model listener */
@@ -292,6 +367,11 @@ private void computeExpectedExecutionCosts() {
292367
private IDocument fReplaceVisibleDocumentExecutionTrigger;
293368
/** <code>true</code> if projection was on the last time we switched to segmented mode. */
294369
private boolean fWasProjectionEnabled;
370+
/**
371+
* The region set by {@link #setVisibleRegion(int, int)} during projection or <code>null</code>
372+
* if not in a projection
373+
*/
374+
private IRegion fVisibleRegionDuringProjection;
295375
/** The queue of projection commands used to assess the costs of projection changes. */
296376
private ProjectionCommandQueue fCommandQueue;
297377
/**
@@ -301,6 +381,8 @@ private void computeExpectedExecutionCosts() {
301381
*/
302382
private int fDeletedLines;
303383

384+
private UpdateDocumentListener fUpdateDocumentListener= new UpdateDocumentListener();
385+
304386

305387
/**
306388
* Creates a new projection source viewer.
@@ -510,6 +592,11 @@ public final void disableProjection() {
510592
fProjectionAnnotationModel.removeAllAnnotations();
511593
fFindReplaceDocumentAdapter= null;
512594
fireProjectionDisabled();
595+
if (fVisibleRegionDuringProjection != null) {
596+
super.setVisibleRegion(fVisibleRegionDuringProjection.getOffset(), fVisibleRegionDuringProjection.getLength());
597+
fVisibleRegionDuringProjection= null;
598+
}
599+
getDocument().removeDocumentListener(fUpdateDocumentListener);
513600
}
514601
}
515602

@@ -518,9 +605,14 @@ public final void disableProjection() {
518605
*/
519606
public final void enableProjection() {
520607
if (!isProjectionMode()) {
608+
IRegion visibleRegion= getVisibleRegion();
521609
addProjectionAnnotationModel(getVisualAnnotationModel());
522610
fFindReplaceDocumentAdapter= null;
523611
fireProjectionEnabled();
612+
if (visibleRegion != null && (visibleRegion.getOffset() != 0 || visibleRegion.getLength() != 0)) {
613+
setVisibleRegion(visibleRegion.getOffset(), visibleRegion.getLength());
614+
}
615+
getDocument().addDocumentListener(fUpdateDocumentListener);
524616
}
525617
}
526618

@@ -529,6 +621,10 @@ private void expandAll() {
529621
IDocument doc= getDocument();
530622
int length= doc == null ? 0 : doc.getLength();
531623
if (isProjectionMode()) {
624+
if (fVisibleRegionDuringProjection != null) {
625+
offset= fVisibleRegionDuringProjection.getOffset();
626+
length= fVisibleRegionDuringProjection.getLength();
627+
}
532628
fProjectionAnnotationModel.expandAll(offset, length);
533629
}
534630
}
@@ -683,9 +779,24 @@ private int toLineStart(IDocument document, int offset, boolean testLastLine) th
683779

684780
@Override
685781
public void setVisibleRegion(int start, int length) {
686-
fWasProjectionEnabled= isProjectionMode();
687-
disableProjection();
688-
super.setVisibleRegion(start, length);
782+
if (isProjectionMode()) {
783+
for (Iterator<Annotation> annotationIterator= fProjectionAnnotationModel.getAnnotationIterator(); annotationIterator.hasNext();) {
784+
Annotation ann= annotationIterator.next();
785+
if (ann instanceof InvisibleCollapsedProjectionAnnotation) {
786+
fProjectionAnnotationModel.removeAnnotation(ann);
787+
}
788+
}
789+
if (start > 0) {
790+
fProjectionAnnotationModel.addAnnotation(new InvisibleCollapsedProjectionAnnotation(), new ExactRegionProjectionPosition(0, start));
791+
}
792+
int regionEnd= start + length + 1;
793+
if (regionEnd < getDocument().getLength()) {
794+
fProjectionAnnotationModel.addAnnotation(new InvisibleCollapsedProjectionAnnotation(), new ExactRegionProjectionPosition(regionEnd, getDocument().getLength() - regionEnd));
795+
}
796+
fVisibleRegionDuringProjection= new Region(start, length);
797+
} else {
798+
super.setVisibleRegion(start, length);
799+
}
689800
}
690801

691802
@Override
@@ -710,6 +821,9 @@ public void resetVisibleRegion() {
710821

711822
@Override
712823
public IRegion getVisibleRegion() {
824+
if (fVisibleRegionDuringProjection != null) {
825+
return fVisibleRegionDuringProjection;
826+
}
713827
disableProjection();
714828
IRegion visibleRegion= getModelCoverage();
715829
if (visibleRegion == null)

0 commit comments

Comments
 (0)