1 11 package org.eclipse.jface.text.source; 12 13 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.Collection ; 17 import java.util.HashMap ; 18 import java.util.HashSet ; 19 import java.util.Iterator ; 20 import java.util.LinkedList ; 21 import java.util.List ; 22 import java.util.Map ; 23 import java.util.Set ; 24 25 import org.eclipse.swt.SWT; 26 import org.eclipse.swt.SWTException; 27 import org.eclipse.swt.custom.StyleRange; 28 import org.eclipse.swt.custom.StyledText; 29 import org.eclipse.swt.events.PaintEvent; 30 import org.eclipse.swt.events.PaintListener; 31 import org.eclipse.swt.graphics.Color; 32 import org.eclipse.swt.graphics.GC; 33 import org.eclipse.swt.graphics.Point; 34 import org.eclipse.swt.widgets.Display; 35 36 import org.eclipse.core.runtime.Platform; 37 38 import org.eclipse.jface.text.BadLocationException; 39 import org.eclipse.jface.text.IDocument; 40 import org.eclipse.jface.text.IPaintPositionManager; 41 import org.eclipse.jface.text.IPainter; 42 import org.eclipse.jface.text.IRegion; 43 import org.eclipse.jface.text.ITextInputListener; 44 import org.eclipse.jface.text.ITextPresentationListener; 45 import org.eclipse.jface.text.ITextViewerExtension2; 46 import org.eclipse.jface.text.ITextViewerExtension5; 47 import org.eclipse.jface.text.JFaceTextUtil; 48 import org.eclipse.jface.text.Position; 49 import org.eclipse.jface.text.Region; 50 import org.eclipse.jface.text.TextPresentation; 51 52 53 65 public class AnnotationPainter implements IPainter, PaintListener, IAnnotationModelListener, IAnnotationModelListenerExtension, ITextPresentationListener { 66 67 68 73 public interface IDrawingStrategy { 74 95 void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color); 96 } 97 98 103 public static class SquigglesStrategy implements IDrawingStrategy { 104 105 109 public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) { 110 if (gc != null) { 111 112 if (length < 1) 113 return; 114 115 Point left= textWidget.getLocationAtOffset(offset); 116 Point right= textWidget.getLocationAtOffset(offset + length); 117 118 int[] polyline= computePolyline(left, right, textWidget.getBaseline(offset), textWidget.getLineHeight(offset)); 119 120 gc.setLineWidth(0); gc.setLineStyle(SWT.LINE_SOLID); 122 gc.setForeground(color); 123 gc.drawPolyline(polyline); 124 125 } else { 126 textWidget.redrawRange(offset, length, true); 127 } 128 } 129 130 140 private int[] computePolyline(Point left, Point right, int baseline, int lineHeight) { 141 142 final int WIDTH= 4; final int HEIGHT= 2; 145 int peaks= (right.x - left.x) / WIDTH; 146 if (peaks == 0 && right.x - left.x > 2) 147 peaks= 1; 148 149 int leftX= left.x; 150 151 int length= ((2 * peaks) + 1) * 2; 153 if (length < 0) 154 return new int[0]; 155 156 int[] coordinates= new int[length]; 157 158 int top= left.y + Math.min(baseline + 1, lineHeight - HEIGHT - 1); 160 int bottom= top + HEIGHT; 161 162 for (int i= 0; i < peaks; i++) { 164 int index= 4 * i; 165 coordinates[index]= leftX + (WIDTH * i); 166 coordinates[index+1]= bottom; 167 coordinates[index+2]= coordinates[index] + WIDTH/2; 168 coordinates[index+3]= top; 169 } 170 171 coordinates[length-2]= Math.min(Math.max(0, right.x - 1), left.x + (WIDTH * peaks)); 173 coordinates[length-1]= bottom; 174 175 return coordinates; 176 } 177 } 178 179 184 public static final class NullStrategy implements IDrawingStrategy { 185 186 190 public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) { 191 } 193 } 194 195 199 private static class ReusableRegion extends Position implements IRegion {} 200 201 205 private static boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jface.text/debug/AnnotationPainter")); 210 private static final IDrawingStrategy fgSquigglyDrawer= new SquigglesStrategy(); 211 215 private static final Object SQUIGGLES= new Object (); 216 220 private static final IDrawingStrategy fgNullDrawer= new NullStrategy(); 221 222 227 private static class Decoration { 228 229 private Position fPosition; 230 231 private Color fColor; 232 236 private int fLayer; 237 241 private IDrawingStrategy fPainter; 242 } 243 244 245 private boolean fIsActive= false; 246 247 private boolean fIsPainting= false; 248 249 private volatile boolean fIsSettingModel= false; 250 251 private ISourceViewer fSourceViewer; 252 253 private StyledText fTextWidget; 254 255 private IAnnotationModel fModel; 256 257 private IAnnotationAccess fAnnotationAccess; 258 262 private Map fDecorationsMap= new HashMap (); 267 private Map fHighlightedDecorationsMap= new HashMap (); 272 private Object fDecorationMapLock= new Object (); 273 277 private Object fHighlightedDecorationsMapLock= new Object (); 278 279 private Map fColorTable= new HashMap (); 280 284 private Set fConfiguredAnnotationTypes= new HashSet (); 285 289 private Set fAllowedAnnotationTypes= new HashSet (); 290 294 private Set fConfiguredHighlightAnnotationTypes= new HashSet (); 295 299 private Set fAllowedHighlightAnnotationTypes= new HashSet (); 300 304 private Position fCurrentHighlightAnnotationRange= null; 305 310 private Position fTotalHighlightAnnotationRange= null; 311 315 private Position fCurrentDrawRange= null; 316 321 private Position fTotalDrawRange= null; 322 326 private ITextInputListener fTextInputListener; 327 331 private boolean fInputDocumentAboutToBeChanged; 332 336 private Map fAnnotationType2DrawingStrategyId= new HashMap (); 337 341 private Map fRegisteredDrawingStrategies= new HashMap (); 342 343 347 private ReusableRegion fReusableRegion= new ReusableRegion(); 348 349 357 public AnnotationPainter(ISourceViewer sourceViewer, IAnnotationAccess access) { 358 fSourceViewer= sourceViewer; 359 fAnnotationAccess= access; 360 fTextWidget= sourceViewer.getTextWidget(); 361 362 fRegisteredDrawingStrategies.put(SQUIGGLES, fgSquigglyDrawer); 364 } 365 366 371 private boolean hasDecorations() { 372 synchronized (fDecorationMapLock) { 373 return !fDecorationsMap.isEmpty(); 374 } 375 } 376 377 381 private void enablePainting() { 382 if (!fIsPainting && hasDecorations()) { 383 fIsPainting= true; 384 fTextWidget.addPaintListener(this); 385 handleDrawRequest(null); 386 } 387 } 388 389 395 private void disablePainting(boolean redraw) { 396 if (fIsPainting) { 397 fIsPainting= false; 398 fTextWidget.removePaintListener(this); 399 if (redraw && hasDecorations()) 400 handleDrawRequest(null); 401 } 402 } 403 404 410 private void setModel(IAnnotationModel model) { 411 if (fModel != model) { 412 if (fModel != null) 413 fModel.removeAnnotationModelListener(this); 414 fModel= model; 415 if (fModel != null) { 416 try { 417 fIsSettingModel= true; 418 fModel.addAnnotationModelListener(this); 419 } finally { 420 fIsSettingModel= false; 421 } 422 } 423 } 424 } 425 426 432 private void catchupWithModel(AnnotationModelEvent event) { 433 434 synchronized (fDecorationMapLock) { 435 if (fDecorationsMap == null) 436 return; 437 } 438 439 IRegion clippingRegion= computeClippingRegion(null, true); 440 IDocument document= fSourceViewer.getDocument(); 441 442 int highlightAnnotationRangeStart= Integer.MAX_VALUE; 443 int highlightAnnotationRangeEnd= -1; 444 445 int drawRangeStart= Integer.MAX_VALUE; 446 int drawRangeEnd= -1; 447 448 if (fModel != null) { 449 450 Map decorationsMap; 451 Map highlightedDecorationsMap; 452 453 synchronized (fDecorationMapLock) { 455 decorationsMap= new HashMap (fDecorationsMap); 456 } 457 synchronized (fHighlightedDecorationsMapLock) { 458 highlightedDecorationsMap= new HashMap (fHighlightedDecorationsMap); 459 } 460 461 boolean isWorldChange= false; 462 463 Iterator e; 464 if (event == null || event.isWorldChange()) { 465 isWorldChange= true; 466 467 if (DEBUG && event == null) 468 System.out.println("AP: INTERNAL CHANGE"); 470 Iterator iter= decorationsMap.entrySet().iterator(); 471 while (iter.hasNext()) { 472 Map.Entry entry= (Map.Entry )iter.next(); 473 Annotation annotation= (Annotation)entry.getKey(); 474 Decoration decoration= (Decoration)entry.getValue(); 475 drawDecoration(decoration, null, annotation, clippingRegion, document); 476 } 477 478 decorationsMap.clear(); 479 480 highlightedDecorationsMap.clear(); 481 482 e= fModel.getAnnotationIterator(); 483 484 485 } else { 486 487 Annotation[] removedAnnotations= event.getRemovedAnnotations(); 489 for (int i=0, length= removedAnnotations.length; i < length; i++) { 490 Annotation annotation= removedAnnotations[i]; 491 Decoration decoration= (Decoration)highlightedDecorationsMap.remove(annotation); 492 if (decoration != null) { 493 Position position= decoration.fPosition; 494 if (position != null) { 495 highlightAnnotationRangeStart= Math.min(highlightAnnotationRangeStart, position.offset); 496 highlightAnnotationRangeEnd= Math.max(highlightAnnotationRangeEnd, position.offset + position.length); 497 } 498 } 499 decoration= (Decoration)decorationsMap.remove(annotation); 500 if (decoration != null) { 501 drawDecoration(decoration, null, annotation, clippingRegion, document); 502 Position position= decoration.fPosition; 503 if (position != null) { 504 drawRangeStart= Math.min(drawRangeStart, position.offset); 505 drawRangeEnd= Math.max(drawRangeEnd, position.offset + position.length); 506 } 507 } 508 509 } 510 511 Annotation[] changedAnnotations= event.getChangedAnnotations(); 513 for (int i=0, length= changedAnnotations.length; i < length; i++) { 514 Annotation annotation= changedAnnotations[i]; 515 516 Object annotationType= annotation.getType(); 517 boolean isHighlighting= shouldBeHighlighted(annotationType); 518 boolean usesDrawingStrategy= shouldBeDrawn(annotationType); 519 520 Decoration decoration= (Decoration)highlightedDecorationsMap.get(annotation); 521 522 if (decoration != null) { 523 decoration= getDecoration(annotation, decoration, usesDrawingStrategy, isHighlighting); 525 if (decoration == null) 526 highlightedDecorationsMap.remove(annotation); 527 } else { 528 decoration= getDecoration(annotation, decoration, usesDrawingStrategy, isHighlighting); 529 if (decoration != null && isHighlighting) 530 highlightedDecorationsMap.put(annotation, decoration); 531 } 532 533 Position position= null; 534 if (decoration == null) 535 position= fModel.getPosition(annotation); 536 else 537 position= decoration.fPosition; 538 539 if (position != null && !position.isDeleted()) { 540 if (isHighlighting) { 541 highlightAnnotationRangeStart= Math.min(highlightAnnotationRangeStart, position.offset); 542 highlightAnnotationRangeEnd= Math.max(highlightAnnotationRangeEnd, position.offset + position.length); 543 } 544 if (usesDrawingStrategy) { 545 drawRangeStart= Math.min(drawRangeStart, position.offset); 546 drawRangeEnd= Math.max(drawRangeEnd, position.offset + position.length); 547 } 548 } else { 549 highlightedDecorationsMap.remove(annotation); 550 } 551 552 if (usesDrawingStrategy) { 553 Decoration oldDecoration= (Decoration)decorationsMap.get(annotation); 554 if (oldDecoration != null) { 555 drawDecoration(oldDecoration, null, annotation, clippingRegion, document); 556 557 if (decoration != null) 558 decorationsMap.put(annotation, decoration); 559 else if (oldDecoration != null) 560 decorationsMap.remove(annotation); 561 } 562 } 563 } 564 565 e= Arrays.asList(event.getAddedAnnotations()).iterator(); 566 } 567 568 while (e.hasNext()) { 570 Annotation annotation= (Annotation) e.next(); 571 572 Object annotationType= annotation.getType(); 573 boolean isHighlighting= shouldBeHighlighted(annotationType); 574 boolean usesDrawingStrategy= shouldBeDrawn(annotationType); 575 576 Decoration pp= getDecoration(annotation, null, usesDrawingStrategy, isHighlighting); 577 if (pp != null) { 578 579 if (usesDrawingStrategy) { 580 decorationsMap.put(annotation, pp); 581 drawRangeStart= Math.min(drawRangeStart, pp.fPosition.offset); 582 drawRangeEnd= Math.max(drawRangeEnd, pp.fPosition.offset + pp.fPosition.length); 583 } 584 585 if (isHighlighting) { 586 highlightedDecorationsMap.put(annotation, pp); 587 highlightAnnotationRangeStart= Math.min(highlightAnnotationRangeStart, pp.fPosition.offset); 588 highlightAnnotationRangeEnd= Math.max(highlightAnnotationRangeEnd, pp.fPosition.offset + pp.fPosition.length); 589 } 590 591 } 592 } 593 594 synchronized (fDecorationMapLock) { 595 fDecorationsMap= decorationsMap; 596 updateDrawRanges(drawRangeStart, drawRangeEnd, isWorldChange); 597 } 598 599 synchronized (fHighlightedDecorationsMapLock) { 600 fHighlightedDecorationsMap= highlightedDecorationsMap; 601 updateHighlightRanges(highlightAnnotationRangeStart, highlightAnnotationRangeEnd, isWorldChange); 602 } 603 } else { 604 synchronized (fDecorationMapLock) { 606 fDecorationsMap.clear(); 607 } 608 synchronized (fHighlightedDecorationsMapLock) { 609 fHighlightedDecorationsMap.clear(); 610 } 611 } 612 } 613 614 622 private void updateHighlightRanges(int highlightAnnotationRangeStart, int highlightAnnotationRangeEnd, boolean isWorldChange) { 623 if (highlightAnnotationRangeStart != Integer.MAX_VALUE) { 624 625 int maxRangeStart= highlightAnnotationRangeStart; 626 int maxRangeEnd= highlightAnnotationRangeEnd; 627 628 if (fTotalHighlightAnnotationRange != null) { 629 maxRangeStart= Math.min(maxRangeStart, fTotalHighlightAnnotationRange.offset); 630 maxRangeEnd= Math.max(maxRangeEnd, fTotalHighlightAnnotationRange.offset + fTotalHighlightAnnotationRange.length); 631 } 632 633 if (fTotalHighlightAnnotationRange == null) 634 fTotalHighlightAnnotationRange= new Position(0); 635 if (fCurrentHighlightAnnotationRange == null) 636 fCurrentHighlightAnnotationRange= new Position(0); 637 638 if (isWorldChange) { 639 fTotalHighlightAnnotationRange.offset= highlightAnnotationRangeStart; 640 fTotalHighlightAnnotationRange.length= highlightAnnotationRangeEnd - highlightAnnotationRangeStart; 641 fCurrentHighlightAnnotationRange.offset= maxRangeStart; 642 fCurrentHighlightAnnotationRange.length= maxRangeEnd - maxRangeStart; 643 } else { 644 fTotalHighlightAnnotationRange.offset= maxRangeStart; 645 fTotalHighlightAnnotationRange.length= maxRangeEnd - maxRangeStart; 646 fCurrentHighlightAnnotationRange.offset=highlightAnnotationRangeStart; 647 fCurrentHighlightAnnotationRange.length= highlightAnnotationRangeEnd - highlightAnnotationRangeStart; 648 } 649 } else { 650 if (isWorldChange) { 651 fCurrentHighlightAnnotationRange= fTotalHighlightAnnotationRange; 652 fTotalHighlightAnnotationRange= null; 653 } else { 654 fCurrentHighlightAnnotationRange= null; 655 } 656 } 657 658 adaptToDocumentLength(fCurrentHighlightAnnotationRange); 659 adaptToDocumentLength(fTotalHighlightAnnotationRange); 660 } 661 662 670 private void updateDrawRanges(int drawRangeStart, int drawRangeEnd, boolean isWorldChange) { 671 if (drawRangeStart != Integer.MAX_VALUE) { 672 673 int maxRangeStart= drawRangeStart; 674 int maxRangeEnd= drawRangeEnd; 675 676 if (fTotalDrawRange != null) { 677 maxRangeStart= Math.min(maxRangeStart, fTotalDrawRange.offset); 678 maxRangeEnd= Math.max(maxRangeEnd, fTotalDrawRange.offset + fTotalDrawRange.length); 679 } 680 681 if (fTotalDrawRange == null) 682 fTotalDrawRange= new Position(0); 683 if (fCurrentDrawRange == null) 684 fCurrentDrawRange= new Position(0); 685 686 if (isWorldChange) { 687 fTotalDrawRange.offset= drawRangeStart; 688 fTotalDrawRange.length= drawRangeEnd - drawRangeStart; 689 fCurrentDrawRange.offset= maxRangeStart; 690 fCurrentDrawRange.length= maxRangeEnd - maxRangeStart; 691 } else { 692 fTotalDrawRange.offset= maxRangeStart; 693 fTotalDrawRange.length= maxRangeEnd - maxRangeStart; 694 fCurrentDrawRange.offset=drawRangeStart; 695 fCurrentDrawRange.length= drawRangeEnd - drawRangeStart; 696 } 697 } else { 698 if (isWorldChange) { 699 fCurrentDrawRange= fTotalDrawRange; 700 fTotalDrawRange= null; 701 } else { 702 fCurrentDrawRange= null; 703 } 704 } 705 706 adaptToDocumentLength(fCurrentDrawRange); 707 adaptToDocumentLength(fTotalDrawRange); 708 } 709 710 716 private void adaptToDocumentLength(Position position) { 717 if (position == null) 718 return; 719 720 int length= fSourceViewer.getDocument().getLength(); 721 position.offset= Math.min(position.offset, length); 722 position.length= Math.min(position.length, length - position.offset); 723 } 724 725 736 private Decoration getDecoration(Annotation annotation, Decoration decoration, boolean isDrawingSquiggles, boolean isHighlighting) { 737 738 if (annotation.isMarkedDeleted()) 739 return null; 740 741 Color color= null; 742 743 if (isDrawingSquiggles || isHighlighting) 744 color= findColor(annotation.getType()); 745 746 if (color == null) 747 return null; 748 749 Position position= fModel.getPosition(annotation); 750 if (position == null || position.isDeleted()) 751 return null; 752 753 if (decoration == null) 754 decoration= new Decoration(); 755 756 decoration.fPosition= position; 757 decoration.fColor= color; 758 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 759 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 760 decoration.fLayer= extension.getLayer(annotation); 761 } else { 762 decoration.fLayer= IAnnotationAccessExtension.DEFAULT_LAYER; 763 } 764 decoration.fPainter= getDrawingStrategy(annotation); 765 766 return decoration; 767 } 768 769 776 private IDrawingStrategy getDrawingStrategy(Annotation annotation) { 777 String type= annotation.getType(); 778 IDrawingStrategy strategy = (IDrawingStrategy) fRegisteredDrawingStrategies.get(fAnnotationType2DrawingStrategyId.get(type)); 779 if (strategy != null) 780 return strategy; 781 782 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 783 IAnnotationAccessExtension ext = (IAnnotationAccessExtension) fAnnotationAccess; 784 Object [] sts = ext.getSupertypes(type); 785 for (int i= 0; i < sts.length; i++) { 786 strategy= (IDrawingStrategy) fRegisteredDrawingStrategies.get(fAnnotationType2DrawingStrategyId.get(sts[i])); 787 if (strategy != null) 788 return strategy; 789 } 790 } 791 792 return fgNullDrawer; 793 794 } 795 796 804 private boolean shouldBeDrawn(Object annotationType) { 805 return contains(annotationType, fAllowedAnnotationTypes, fConfiguredAnnotationTypes); 806 } 807 808 816 private boolean shouldBeHighlighted(Object annotationType) { 817 return contains(annotationType, fAllowedHighlightAnnotationTypes, fConfiguredHighlightAnnotationTypes); 818 } 819 820 832 private boolean contains(Object annotationType, Set allowed, Set configured) { 833 if (allowed.contains(annotationType)) 834 return true; 835 836 boolean covered= isCovered(annotationType, configured); 837 if (covered) 838 allowed.add(annotationType); 839 840 return covered; 841 } 842 843 854 private boolean isCovered(Object annotationType, Set configured) { 855 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 856 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 857 Iterator e= configured.iterator(); 858 while (e.hasNext()) { 859 if (extension.isSubtype(annotationType,e.next())) 860 return true; 861 } 862 return false; 863 } 864 return configured.contains(annotationType); 865 } 866 867 874 private Color findColor(Object annotationType) { 875 Color color= (Color) fColorTable.get(annotationType); 876 if (color != null) 877 return color; 878 879 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 880 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 881 Object [] superTypes= extension.getSupertypes(annotationType); 882 if (superTypes != null) { 883 for (int i= 0; i < superTypes.length; i++) { 884 color= (Color) fColorTable.get(superTypes[i]); 885 if (color != null) 886 return color; 887 } 888 } 889 } 890 891 return null; 892 } 893 894 900 private void updatePainting(AnnotationModelEvent event) { 901 disablePainting(event == null); 902 903 catchupWithModel(event); 904 905 if (!fInputDocumentAboutToBeChanged) 906 invalidateTextPresentation(); 907 908 enablePainting(); 909 } 910 911 private void invalidateTextPresentation() { 912 IRegion r= null; 913 synchronized (fHighlightedDecorationsMapLock) { 914 if (fCurrentHighlightAnnotationRange != null) 915 r= new Region(fCurrentHighlightAnnotationRange.getOffset(), fCurrentHighlightAnnotationRange.getLength()); 916 } 917 if (r == null) 918 return; 919 920 if (fSourceViewer instanceof ITextViewerExtension2) { 921 if (DEBUG) 922 System.out.println("AP: invalidating offset: " + r.getOffset() + ", length= " + r.getLength()); 924 ((ITextViewerExtension2)fSourceViewer).invalidateTextPresentation(r.getOffset(), r.getLength()); 925 926 } else { 927 fSourceViewer.invalidateTextPresentation(); 928 } 929 } 930 931 935 public void applyTextPresentation(TextPresentation tp) { 936 Set decorations; 937 938 synchronized (fHighlightedDecorationsMapLock) { 939 if (fHighlightedDecorationsMap == null || fHighlightedDecorationsMap.isEmpty()) 940 return; 941 942 decorations= new HashSet (fHighlightedDecorationsMap.entrySet()); 943 } 944 945 IRegion region= tp.getExtent(); 946 947 if (DEBUG) 948 System.out.println("AP: applying text presentation offset: " + region.getOffset() + ", length= " + region.getLength()); 950 for (int layer= 0, maxLayer= 1; layer < maxLayer; layer++) { 951 952 for (Iterator iter= decorations.iterator(); iter.hasNext();) { 953 Map.Entry entry= (Map.Entry )iter.next(); 954 955 Annotation a= (Annotation)entry.getKey(); 956 if (a.isMarkedDeleted()) 957 continue; 958 959 Decoration pp = (Decoration)entry.getValue(); 960 961 maxLayer= Math.max(maxLayer, pp.fLayer + 1); if (pp.fLayer != layer) continue; 964 965 Position p= pp.fPosition; 966 if (fSourceViewer instanceof ITextViewerExtension5) { 967 ITextViewerExtension5 extension3= (ITextViewerExtension5) fSourceViewer; 968 if (null == extension3.modelRange2WidgetRange(new Region(p.getOffset(), p.getLength()))) 969 continue; 970 } else if (!fSourceViewer.overlapsWithVisibleRegion(p.offset, p.length)) { 971 continue; 972 } 973 974 int regionEnd= region.getOffset() + region.getLength(); 975 int pEnd= p.getOffset() + p.getLength(); 976 if (pEnd >= region.getOffset() && regionEnd > p.getOffset()) { 977 int start= Math.max(p.getOffset(), region.getOffset()); 978 int end= Math.min(regionEnd, pEnd); 979 int length= Math.max(end - start, 0); 980 tp.mergeStyleRange(new StyleRange(start, length, null, pp.fColor)); 981 } 982 } 983 } 984 } 985 986 989 public synchronized void modelChanged(final IAnnotationModel model) { 990 if (DEBUG) 991 System.err.println("AP: OLD API of AnnotationModelListener called"); 993 modelChanged(new AnnotationModelEvent(model)); 994 } 995 996 999 public void modelChanged(final AnnotationModelEvent event) { 1000 Display textWidgetDisplay; 1001 try { 1002 StyledText textWidget= fTextWidget; 1003 if (textWidget == null || textWidget.isDisposed()) 1004 return; 1005 textWidgetDisplay= textWidget.getDisplay(); 1006 } catch (SWTException ex) { 1007 if (ex.code == SWT.ERROR_WIDGET_DISPOSED) 1008 return; 1009 throw ex; 1010 } 1011 1012 if (fIsSettingModel) { 1013 if (textWidgetDisplay == Display.getCurrent()) 1015 updatePainting(event); 1016 else { 1017 1021 return; 1022 } 1023 } else { 1024 if (DEBUG && event != null && event.isWorldChange()) { 1025 System.out.println("AP: WORLD CHANGED, stack trace follows:"); new Throwable ().printStackTrace(System.out); 1027 } 1028 1029 textWidgetDisplay.asyncExec(new Runnable () { 1035 public void run() { 1036 if (fTextWidget != null && !fTextWidget.isDisposed()) 1037 updatePainting(event); 1038 } 1039 }); 1040 } 1041 } 1042 1043 1049 public void setAnnotationTypeColor(Object annotationType, Color color) { 1050 if (color != null) 1051 fColorTable.put(annotationType, color); 1052 else 1053 fColorTable.remove(annotationType); 1054 } 1055 1056 1063 public void addAnnotationType(Object annotationType) { 1064 addAnnotationType(annotationType, SQUIGGLES); 1065 } 1066 1067 1076 public void addAnnotationType(Object annotationType, Object drawingStrategyID) { 1077 fConfiguredAnnotationTypes.add(annotationType); 1078 fAnnotationType2DrawingStrategyId.put(annotationType, drawingStrategyID); 1079 } 1080 1081 1091 public void addDrawingStrategy(Object id, IDrawingStrategy strategy) { 1092 if (id == null) 1095 throw new IllegalArgumentException (); 1096 fRegisteredDrawingStrategies.put(id, strategy); 1097 } 1098 1099 1107 public void addHighlightAnnotationType(Object annotationType) { 1108 fConfiguredHighlightAnnotationTypes.add(annotationType); 1109 if (fTextInputListener == null) { 1110 fTextInputListener= new ITextInputListener() { 1111 1114 public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { 1115 fInputDocumentAboutToBeChanged= true; 1116 } 1117 1120 public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { 1121 fInputDocumentAboutToBeChanged= false; 1122 } 1123 }; 1124 fSourceViewer.addTextInputListener(fTextInputListener); 1125 } 1126 } 1127 1128 1135 public void removeAnnotationType(Object annotationType) { 1136 fConfiguredAnnotationTypes.remove(annotationType); 1137 fAllowedAnnotationTypes.clear(); 1138 } 1139 1140 1148 public void removeHighlightAnnotationType(Object annotationType) { 1149 fConfiguredHighlightAnnotationTypes.remove(annotationType); 1150 fAllowedHighlightAnnotationTypes.clear(); 1151 if (fConfiguredHighlightAnnotationTypes.isEmpty() && fTextInputListener != null) { 1152 fSourceViewer.removeTextInputListener(fTextInputListener); 1153 fTextInputListener= null; 1154 fInputDocumentAboutToBeChanged= false; 1155 } 1156 } 1157 1158 1162 public void removeAllAnnotationTypes() { 1163 fConfiguredAnnotationTypes.clear(); 1164 fAllowedAnnotationTypes.clear(); 1165 fConfiguredHighlightAnnotationTypes.clear(); 1166 fAllowedHighlightAnnotationTypes.clear(); 1167 if (fTextInputListener != null) { 1168 fSourceViewer.removeTextInputListener(fTextInputListener); 1169 fTextInputListener= null; 1170 } 1171 } 1172 1173 1179 public boolean isPaintingAnnotations() { 1180 return !fConfiguredAnnotationTypes.isEmpty() || !fConfiguredHighlightAnnotationTypes.isEmpty(); 1181 } 1182 1183 1186 public void dispose() { 1187 1188 if (fColorTable != null) 1189 fColorTable.clear(); 1190 fColorTable= null; 1191 1192 if (fConfiguredAnnotationTypes != null) 1193 fConfiguredAnnotationTypes.clear(); 1194 fConfiguredAnnotationTypes= null; 1195 1196 if (fAllowedAnnotationTypes != null) 1197 fAllowedAnnotationTypes.clear(); 1198 fAllowedAnnotationTypes= null; 1199 1200 if (fConfiguredHighlightAnnotationTypes != null) 1201 fConfiguredHighlightAnnotationTypes.clear(); 1202 fConfiguredHighlightAnnotationTypes= null; 1203 1204 if (fAllowedHighlightAnnotationTypes != null) 1205 fAllowedHighlightAnnotationTypes.clear(); 1206 fAllowedHighlightAnnotationTypes= null; 1207 1208 fTextWidget= null; 1209 fSourceViewer= null; 1210 fAnnotationAccess= null; 1211 fModel= null; 1212 synchronized (fDecorationMapLock) { 1213 fDecorationsMap= null; 1214 } 1215 synchronized (fHighlightedDecorationsMapLock) { 1216 fHighlightedDecorationsMap= null; 1217 } 1218 } 1219 1220 1226 private int getInclusiveTopIndexStartOffset() { 1227 1228 if (fTextWidget != null && !fTextWidget.isDisposed()) { 1229 int top= JFaceTextUtil.getPartialTopIndex(fSourceViewer); 1230 try { 1231 IDocument document= fSourceViewer.getDocument(); 1232 return document.getLineOffset(top); 1233 } catch (BadLocationException x) { 1234 } 1235 } 1236 1237 return -1; 1238 } 1239 1240 1246 private int getExclusiveBottomIndexEndOffset() { 1247 1248 if (fTextWidget != null && !fTextWidget.isDisposed()) { 1249 int bottom= JFaceTextUtil.getPartialBottomIndex(fSourceViewer); 1250 try { 1251 IDocument document= fSourceViewer.getDocument(); 1252 1253 if (bottom >= document.getNumberOfLines()) 1254 bottom= document.getNumberOfLines() - 1; 1255 1256 return document.getLineOffset(bottom) + document.getLineLength(bottom); 1257 } catch (BadLocationException x) { 1258 } 1259 } 1260 1261 return -1; 1262 } 1263 1264 1267 public void paintControl(PaintEvent event) { 1268 if (fTextWidget != null) 1269 handleDrawRequest(event); 1270 } 1271 1272 1277 private void handleDrawRequest(PaintEvent event) { 1278 1279 if (fTextWidget == null) { 1280 return; 1282 } 1283 1284 IRegion clippingRegion= computeClippingRegion(event, false); 1285 if (clippingRegion == null) 1286 return; 1287 1288 int vOffset= clippingRegion.getOffset(); 1289 int vLength= clippingRegion.getLength(); 1290 1291 final GC gc= event != null ? event.gc : null; 1292 1293 Collection decorations; 1295 synchronized (fDecorationMapLock) { 1296 decorations= new ArrayList (fDecorationsMap.size()); 1297 decorations.addAll(fDecorationsMap.entrySet()); 1298 } 1299 1300 1304 ArrayList toBeDrawn= new ArrayList (10); 1305 for (Iterator e = decorations.iterator(); e.hasNext();) { 1306 Map.Entry entry= (Map.Entry )e.next(); 1307 1308 Annotation a= (Annotation)entry.getKey(); 1309 Decoration pp = (Decoration)entry.getValue(); 1310 if (!(a.isMarkedDeleted() || pp.fPainter == fgNullDrawer || pp.fPainter instanceof NullStrategy || skip(a) || !pp.fPosition.overlapsWith(vOffset, vLength))) { 1312 for (int i= toBeDrawn.size(); i <= pp.fLayer; i++) 1314 toBeDrawn.add(new LinkedList ()); 1315 ((List ) toBeDrawn.get(pp.fLayer)).add(entry); 1316 } 1317 } 1318 IDocument document= fSourceViewer.getDocument(); 1319 for (Iterator it= toBeDrawn.iterator(); it.hasNext();) { 1320 List layer= (List ) it.next(); 1321 for (Iterator e = layer.iterator(); e.hasNext();) { 1322 Map.Entry entry= (Map.Entry )e.next(); 1323 Annotation a= (Annotation)entry.getKey(); 1324 Decoration pp = (Decoration)entry.getValue(); 1325 drawDecoration(pp, gc, a, clippingRegion, document); 1326 } 1327 } 1328 } 1329 1330 private void drawDecoration(Decoration pp, GC gc, Annotation annotation, IRegion clippingRegion, IDocument document) { 1331 if (clippingRegion == null || pp.fPainter == fgNullDrawer) 1332 return; 1333 1334 int clippingOffset= clippingRegion.getOffset(); 1335 int clippingLength= clippingRegion.getLength(); 1336 1337 Position p= pp.fPosition; 1338 try { 1339 1340 int startLine= document.getLineOfOffset(p.getOffset()); 1341 int lastInclusive= Math.max(p.getOffset(), p.getOffset() + p.getLength() - 1); 1342 int endLine= document.getLineOfOffset(lastInclusive); 1343 1344 for (int i= startLine; i <= endLine; i++) { 1345 int lineOffset= document.getLineOffset(i); 1346 int paintStart= Math.max(lineOffset, p.getOffset()); 1347 String lineDelimiter= document.getLineDelimiter(i); 1348 int delimiterLength= lineDelimiter != null ? lineDelimiter.length() : 0; 1349 int paintLength= Math.min(lineOffset + document.getLineLength(i) - delimiterLength, p.getOffset() + p.getLength()) - paintStart; 1350 if (paintLength >= 0 && overlapsWith(paintStart, paintLength, clippingOffset, clippingLength)) { 1351 IRegion widgetRange= getWidgetRange(paintStart, paintLength); 1353 if (widgetRange != null) { 1354 pp.fPainter.draw(annotation, gc, fTextWidget, widgetRange.getOffset(), widgetRange.getLength(), pp.fColor); 1355 } 1356 } 1357 } 1358 1359 } catch (BadLocationException x) { 1360 } 1361 } 1362 1363 1374 private IRegion computeClippingRegion(PaintEvent event, boolean isClearing) { 1375 if (event == null) { 1376 1377 if (!isClearing && fCurrentDrawRange != null) 1378 return new Region(fCurrentDrawRange.offset, fCurrentDrawRange.length); 1379 1380 int vOffset= getInclusiveTopIndexStartOffset(); 1382 if (vOffset == -1) 1383 return null; 1384 1385 int vLength= getExclusiveBottomIndexEndOffset() - vOffset; 1387 1388 return new Region(vOffset, vLength); 1389 } 1390 1391 int widgetOffset; 1392 try { 1393 int widgetClippingStartOffset= fTextWidget.getOffsetAtLocation(new Point(0, event.y)); 1394 int firstWidgetLine= fTextWidget.getLineAtOffset(widgetClippingStartOffset); 1395 widgetOffset= fTextWidget.getOffsetAtLine(firstWidgetLine); 1396 } catch (IllegalArgumentException ex1) { 1397 try { 1398 int firstVisibleLine= JFaceTextUtil.getPartialTopIndex(fTextWidget); 1399 widgetOffset= fTextWidget.getOffsetAtLine(firstVisibleLine); 1400 } catch (IllegalArgumentException ex2) { widgetOffset= 0; 1402 } 1403 } 1404 1405 int widgetEndOffset; 1406 try { 1407 int widgetClippingEndOffset= fTextWidget.getOffsetAtLocation(new Point(0, event.y + event.height)); 1408 int lastWidgetLine= fTextWidget.getLineAtOffset(widgetClippingEndOffset); 1409 widgetEndOffset= fTextWidget.getOffsetAtLine(lastWidgetLine + 1); 1410 } catch (IllegalArgumentException ex1) { 1411 try { 1413 int lastVisibleLine= JFaceTextUtil.getPartialBottomIndex(fTextWidget); 1414 if (lastVisibleLine == fTextWidget.getLineCount() - 1) 1415 widgetEndOffset= fTextWidget.getCharCount(); 1417 else 1418 widgetEndOffset= fTextWidget.getOffsetAtLine(lastVisibleLine + 1) - 1; 1419 } catch (IllegalArgumentException ex2) { widgetEndOffset= fTextWidget.getCharCount(); 1421 } 1422 } 1423 1424 IRegion clippingRegion= getModelRange(widgetOffset, widgetEndOffset - widgetOffset); 1425 1426 return clippingRegion; 1427 } 1428 1429 1437 protected boolean skip(Annotation annotation) { 1438 return false; 1439 } 1440 1441 1449 private IRegion getWidgetRange(int modelOffset, int modelLength) { 1450 fReusableRegion.setOffset(modelOffset); 1451 fReusableRegion.setLength(modelLength); 1452 1453 if (fReusableRegion == null || fReusableRegion.getOffset() == Integer.MAX_VALUE) 1454 return null; 1455 1456 if (fSourceViewer instanceof ITextViewerExtension5) { 1457 ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer; 1458 return extension.modelRange2WidgetRange(fReusableRegion); 1459 } 1460 1461 IRegion region= fSourceViewer.getVisibleRegion(); 1462 int offset= region.getOffset(); 1463 int length= region.getLength(); 1464 1465 if (overlapsWith(fReusableRegion, region)) { 1466 int p1= Math.max(offset, fReusableRegion.getOffset()); 1467 int p2= Math.min(offset + length, fReusableRegion.getOffset() + fReusableRegion.getLength()); 1468 return new Region(p1 - offset, p2 - p1); 1469 } 1470 return null; 1471 } 1472 1473 1482 private IRegion getModelRange(int offset, int length) { 1483 if (offset == Integer.MAX_VALUE) 1484 return null; 1485 1486 if (fSourceViewer instanceof ITextViewerExtension5) { 1487 ITextViewerExtension5 extension= (ITextViewerExtension5) fSourceViewer; 1488 return extension.widgetRange2ModelRange(new Region(offset, length)); 1489 } 1490 1491 IRegion region= fSourceViewer.getVisibleRegion(); 1492 return new Region(region.getOffset() + offset, length); 1493 } 1494 1495 1503 private boolean overlapsWith(IRegion range1, IRegion range2) { 1504 return overlapsWith(range1.getOffset(), range1.getLength(), range2.getOffset(), range2.getLength()); 1505 } 1506 1507 1517 private boolean overlapsWith(int offset1, int length1, int offset2, int length2) { 1518 int end= offset2 + length2; 1519 int thisEnd= offset1 + length1; 1520 1521 if (length2 > 0) { 1522 if (length1 > 0) 1523 return offset1 < end && offset2 < thisEnd; 1524 return offset2 <= offset1 && offset1 < end; 1525 } 1526 1527 if (length1 > 0) 1528 return offset1 <= offset2 && offset2 < thisEnd; 1529 return offset1 == offset2; 1530 } 1531 1532 1535 public void deactivate(boolean redraw) { 1536 if (fIsActive) { 1537 fIsActive= false; 1538 disablePainting(redraw); 1539 setModel(null); 1540 catchupWithModel(null); 1541 } 1542 } 1543 1544 1551 protected boolean isRepaintReason(int reason) { 1552 return CONFIGURATION == reason || INTERNAL == reason; 1553 } 1554 1555 1562 protected IAnnotationModel findAnnotationModel(ISourceViewer sourceViewer) { 1563 if(sourceViewer != null) 1564 return sourceViewer.getAnnotationModel(); 1565 return null; 1566 } 1567 1568 1571 public void paint(int reason) { 1572 if (fSourceViewer.getDocument() == null) { 1573 deactivate(false); 1574 return; 1575 } 1576 1577 if (!fIsActive) { 1578 IAnnotationModel model= findAnnotationModel(fSourceViewer); 1579 if (model != null) { 1580 fIsActive= true; 1581 setModel(model); 1582 } 1583 } else if (isRepaintReason(reason)) 1584 updatePainting(null); 1585 } 1586 1587 1590 public void setPositionManager(IPaintPositionManager manager) { 1591 } 1592} 1593 | Popular Tags |