28
28
import org .eclipse .swt .dnd .TextTransfer ;
29
29
import org .eclipse .swt .dnd .Transfer ;
30
30
import org .eclipse .swt .events .VerifyEvent ;
31
+ import org .eclipse .swt .graphics .GC ;
31
32
import org .eclipse .swt .graphics .Point ;
33
+ import org .eclipse .swt .graphics .Rectangle ;
34
+ import org .eclipse .swt .widgets .Canvas ;
32
35
import org .eclipse .swt .widgets .Composite ;
33
36
import org .eclipse .swt .widgets .Display ;
34
37
@@ -99,6 +102,7 @@ public class ProjectionViewer extends SourceViewer implements ITextViewerExtensi
99
102
*/
100
103
public static final int COLLAPSE_ALL = BASE + 5 ;
101
104
105
+
102
106
/**
103
107
* Internal listener to changes of the annotation model.
104
108
*/
@@ -272,6 +276,77 @@ private void computeExpectedExecutionCosts() {
272
276
}
273
277
}
274
278
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
+
275
350
/** The projection annotation model used by this viewer. */
276
351
private ProjectionAnnotationModel fProjectionAnnotationModel ;
277
352
/** The annotation model listener */
@@ -292,6 +367,11 @@ private void computeExpectedExecutionCosts() {
292
367
private IDocument fReplaceVisibleDocumentExecutionTrigger ;
293
368
/** <code>true</code> if projection was on the last time we switched to segmented mode. */
294
369
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 ;
295
375
/** The queue of projection commands used to assess the costs of projection changes. */
296
376
private ProjectionCommandQueue fCommandQueue ;
297
377
/**
@@ -301,6 +381,8 @@ private void computeExpectedExecutionCosts() {
301
381
*/
302
382
private int fDeletedLines ;
303
383
384
+ private UpdateDocumentListener fUpdateDocumentListener = new UpdateDocumentListener ();
385
+
304
386
305
387
/**
306
388
* Creates a new projection source viewer.
@@ -510,6 +592,11 @@ public final void disableProjection() {
510
592
fProjectionAnnotationModel .removeAllAnnotations ();
511
593
fFindReplaceDocumentAdapter = null ;
512
594
fireProjectionDisabled ();
595
+ if (fVisibleRegionDuringProjection != null ) {
596
+ super .setVisibleRegion (fVisibleRegionDuringProjection .getOffset (), fVisibleRegionDuringProjection .getLength ());
597
+ fVisibleRegionDuringProjection = null ;
598
+ }
599
+ getDocument ().removeDocumentListener (fUpdateDocumentListener );
513
600
}
514
601
}
515
602
@@ -518,9 +605,14 @@ public final void disableProjection() {
518
605
*/
519
606
public final void enableProjection () {
520
607
if (!isProjectionMode ()) {
608
+ IRegion visibleRegion = getVisibleRegion ();
521
609
addProjectionAnnotationModel (getVisualAnnotationModel ());
522
610
fFindReplaceDocumentAdapter = null ;
523
611
fireProjectionEnabled ();
612
+ if (visibleRegion != null && (visibleRegion .getOffset () != 0 || visibleRegion .getLength () != 0 )) {
613
+ setVisibleRegion (visibleRegion .getOffset (), visibleRegion .getLength ());
614
+ }
615
+ getDocument ().addDocumentListener (fUpdateDocumentListener );
524
616
}
525
617
}
526
618
@@ -529,6 +621,10 @@ private void expandAll() {
529
621
IDocument doc = getDocument ();
530
622
int length = doc == null ? 0 : doc .getLength ();
531
623
if (isProjectionMode ()) {
624
+ if (fVisibleRegionDuringProjection != null ) {
625
+ offset = fVisibleRegionDuringProjection .getOffset ();
626
+ length = fVisibleRegionDuringProjection .getLength ();
627
+ }
532
628
fProjectionAnnotationModel .expandAll (offset , length );
533
629
}
534
630
}
@@ -683,9 +779,24 @@ private int toLineStart(IDocument document, int offset, boolean testLastLine) th
683
779
684
780
@ Override
685
781
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 + 2 ;
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
+ }
689
800
}
690
801
691
802
@ Override
@@ -710,6 +821,9 @@ public void resetVisibleRegion() {
710
821
711
822
@ Override
712
823
public IRegion getVisibleRegion () {
824
+ if (fVisibleRegionDuringProjection != null ) {
825
+ return fVisibleRegionDuringProjection ;
826
+ }
713
827
disableProjection ();
714
828
IRegion visibleRegion = getModelCoverage ();
715
829
if (visibleRegion == null )
0 commit comments