1 11 package org.eclipse.jface.text.source; 12 13 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 22 import org.eclipse.swt.SWT; 23 import org.eclipse.swt.custom.StyledText; 24 import org.eclipse.swt.events.DisposeEvent; 25 import org.eclipse.swt.events.DisposeListener; 26 import org.eclipse.swt.events.MouseAdapter; 27 import org.eclipse.swt.events.MouseEvent; 28 import org.eclipse.swt.events.MouseMoveListener; 29 import org.eclipse.swt.events.MouseTrackAdapter; 30 import org.eclipse.swt.events.PaintEvent; 31 import org.eclipse.swt.events.PaintListener; 32 import org.eclipse.swt.graphics.Color; 33 import org.eclipse.swt.graphics.Cursor; 34 import org.eclipse.swt.graphics.GC; 35 import org.eclipse.swt.graphics.Image; 36 import org.eclipse.swt.graphics.Point; 37 import org.eclipse.swt.graphics.RGB; 38 import org.eclipse.swt.graphics.Rectangle; 39 import org.eclipse.swt.widgets.Canvas; 40 import org.eclipse.swt.widgets.Composite; 41 import org.eclipse.swt.widgets.Control; 42 import org.eclipse.swt.widgets.Display; 43 44 import org.eclipse.jface.text.BadLocationException; 45 import org.eclipse.jface.text.IDocument; 46 import org.eclipse.jface.text.IRegion; 47 import org.eclipse.jface.text.ITextListener; 48 import org.eclipse.jface.text.ITextViewer; 49 import org.eclipse.jface.text.ITextViewerExtension5; 50 import org.eclipse.jface.text.JFaceTextUtil; 51 import org.eclipse.jface.text.Position; 52 import org.eclipse.jface.text.Region; 53 import org.eclipse.jface.text.TextEvent; 54 import org.eclipse.jface.text.source.projection.AnnotationBag; 55 56 57 58 67 public class OverviewRuler implements IOverviewRuler { 68 69 72 class InternalListener implements ITextListener, IAnnotationModelListener, IAnnotationModelListenerExtension { 73 74 77 public void textChanged(TextEvent e) { 78 if (fTextViewer != null && e.getDocumentEvent() == null && e.getViewerRedrawState()) { 79 redraw(); 81 } 82 } 83 84 87 public void modelChanged(IAnnotationModel model) { 88 update(); 89 } 90 91 95 public void modelChanged(AnnotationModelEvent event) { 96 if (!event.isValid()) 97 return; 98 99 if (event.isWorldChange()) { 100 update(); 101 return; 102 } 103 104 Annotation[] annotations= event.getAddedAnnotations(); 105 int length= annotations.length; 106 for (int i= 0; i < length; i++) { 107 if (!skip(annotations[i].getType())) { 108 update(); 109 return; 110 } 111 } 112 113 annotations= event.getRemovedAnnotations(); 114 length= annotations.length; 115 for (int i= 0; i < length; i++) { 116 if (!skip(annotations[i].getType())) { 117 update(); 118 return; 119 } 120 } 121 122 annotations= event.getChangedAnnotations(); 123 length= annotations.length; 124 for (int i= 0; i < length; i++) { 125 if (!skip(annotations[i].getType())) { 126 update(); 127 return; 128 } 129 } 130 131 } 132 } 133 134 138 class FilterIterator implements Iterator { 139 140 final static int TEMPORARY= 1 << 1; 141 final static int PERSISTENT= 1 << 2; 142 final static int IGNORE_BAGS= 1 << 3; 143 144 private Iterator fIterator; 145 private Object fType; 146 private Annotation fNext; 147 private int fStyle; 148 149 155 public FilterIterator(Object annotationType, int style) { 156 fType= annotationType; 157 fStyle= style; 158 if (fModel != null) { 159 fIterator= fModel.getAnnotationIterator(); 160 skip(); 161 } 162 } 163 164 171 public FilterIterator(Object annotationType, int style, Iterator iterator) { 172 fType= annotationType; 173 fStyle= style; 174 fIterator= iterator; 175 skip(); 176 } 177 178 private void skip() { 179 180 boolean temp= (fStyle & TEMPORARY) != 0; 181 boolean pers= (fStyle & PERSISTENT) != 0; 182 boolean ignr= (fStyle & IGNORE_BAGS) != 0; 183 184 while (fIterator.hasNext()) { 185 Annotation next= (Annotation) fIterator.next(); 186 187 if (next.isMarkedDeleted()) 188 continue; 189 190 if (ignr && (next instanceof AnnotationBag)) 191 continue; 192 193 fNext= next; 194 Object annotationType= next.getType(); 195 if (fType == null || isSubtype(annotationType)) { 196 if (temp && pers) return; 197 if (pers && next.isPersistent()) return; 198 if (temp && !next.isPersistent()) return; 199 } 200 } 201 fNext= null; 202 } 203 204 private boolean isSubtype(Object annotationType) { 205 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 206 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 207 return extension.isSubtype(annotationType, fType); 208 } 209 return fType.equals(annotationType); 210 } 211 212 215 public boolean hasNext() { 216 return fNext != null; 217 } 218 221 public Object next() { 222 try { 223 return fNext; 224 } finally { 225 if (fIterator != null) 226 skip(); 227 } 228 } 229 232 public void remove() { 233 throw new UnsupportedOperationException (); 234 } 235 } 236 237 240 class HeaderPainter implements PaintListener { 241 242 private Color fIndicatorColor; 243 private Color fSeparatorColor; 244 245 248 public HeaderPainter() { 249 fSeparatorColor= fHeader.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); 250 } 251 252 257 public void setColor(Color color) { 258 fIndicatorColor= color; 259 } 260 261 private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topLeft, Color bottomRight) { 262 gc.setForeground(topLeft == null ? fSeparatorColor : topLeft); 263 gc.drawLine(x, y, x + w -1, y); 264 gc.drawLine(x, y, x, y + h -1); 265 266 gc.setForeground(bottomRight == null ? fSeparatorColor : bottomRight); 267 gc.drawLine(x + w, y, x + w, y + h); 268 gc.drawLine(x, y + h, x + w, y + h); 269 } 270 271 public void paintControl(PaintEvent e) { 272 273 Point s= fHeader.getSize(); 274 275 if (fIndicatorColor != null) { 276 e.gc.setBackground(fIndicatorColor); 277 Rectangle r= new Rectangle(INSET, (s.y - (2*ANNOTATION_HEIGHT)) / 2, s.x - (2*INSET), 2*ANNOTATION_HEIGHT); 278 e.gc.fillRectangle(r); 279 Display d= fHeader.getDisplay(); 280 if (d != null) 281 drawBevelRect(e.gc, r.x, r.y, r.width -1, r.height -1, null, null); 283 } 284 285 e.gc.setForeground(fSeparatorColor); 286 e.gc.setLineWidth(0); e.gc.drawLine(0, s.y -1, s.x -1, s.y -1); 288 } 289 } 290 291 private static final int INSET= 2; 292 private static final int ANNOTATION_HEIGHT= 4; 293 private static boolean ANNOTATION_HEIGHT_SCALABLE= true; 294 295 296 297 private IAnnotationModel fModel; 298 299 private ITextViewer fTextViewer; 300 301 private Canvas fCanvas; 302 303 private Canvas fHeader; 304 305 private Image fBuffer; 306 307 private InternalListener fInternalListener= new InternalListener(); 308 309 private int fWidth; 310 311 private Cursor fHitDetectionCursor; 312 313 private Cursor fLastCursor; 314 315 private int fLastMouseButtonActivityLine= -1; 316 317 private int fAnnotationHeight= -1; 318 319 private IAnnotationAccess fAnnotationAccess; 320 321 private HeaderPainter fHeaderPainter; 322 326 private Set fConfiguredAnnotationTypes= new HashSet (); 327 331 private Set fConfiguredHeaderAnnotationTypes= new HashSet (); 332 333 private Map fAnnotationTypes2Colors= new HashMap (); 334 335 private ISharedTextColors fSharedTextColors; 336 341 private List fAnnotationsSortedByLayer= new ArrayList (); 342 347 private List fLayersSortedByLayer= new ArrayList (); 348 354 private Map fAllowedAnnotationTypes= new HashMap (); 355 361 private Map fAllowedHeaderAnnotationTypes= new HashMap (); 362 366 private List fCachedAnnotations= new ArrayList (); 367 368 372 private Object fRunnableLock= new Object (); 373 377 private boolean fIsRunnablePosted= false; 378 382 private Runnable fRunnable= new Runnable () { 383 public void run() { 384 synchronized (fRunnableLock) { 385 fIsRunnablePosted= false; 386 } 387 redraw(); 388 updateHeader(); 389 } 390 }; 391 392 393 401 public OverviewRuler(IAnnotationAccess annotationAccess, int width, ISharedTextColors sharedColors) { 402 fAnnotationAccess= annotationAccess; 403 fWidth= width; 404 fSharedTextColors= sharedColors; 405 } 406 407 410 public Control getControl() { 411 return fCanvas; 412 } 413 414 417 public int getWidth() { 418 return fWidth; 419 } 420 421 424 public void setModel(IAnnotationModel model) { 425 if (model != fModel || model != null) { 426 427 if (fModel != null) 428 fModel.removeAnnotationModelListener(fInternalListener); 429 430 fModel= model; 431 432 if (fModel != null) 433 fModel.addAnnotationModelListener(fInternalListener); 434 435 update(); 436 } 437 } 438 439 442 public Control createControl(Composite parent, ITextViewer textViewer) { 443 444 fTextViewer= textViewer; 445 446 fHitDetectionCursor= new Cursor(parent.getDisplay(), SWT.CURSOR_HAND); 447 448 fHeader= new Canvas(parent, SWT.NONE); 449 450 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 451 fHeader.addMouseTrackListener(new MouseTrackAdapter() { 452 456 public void mouseEnter(MouseEvent e) { 457 updateHeaderToolTipText(); 458 } 459 }); 460 } 461 462 fCanvas= new Canvas(parent, SWT.NO_BACKGROUND); 463 464 fCanvas.addPaintListener(new PaintListener() { 465 public void paintControl(PaintEvent event) { 466 if (fTextViewer != null) 467 doubleBufferPaint(event.gc); 468 } 469 }); 470 471 fCanvas.addDisposeListener(new DisposeListener() { 472 public void widgetDisposed(DisposeEvent event) { 473 handleDispose(); 474 fTextViewer= null; 475 } 476 }); 477 478 fCanvas.addMouseListener(new MouseAdapter() { 479 public void mouseDown(MouseEvent event) { 480 handleMouseDown(event); 481 } 482 }); 483 484 fCanvas.addMouseMoveListener(new MouseMoveListener() { 485 public void mouseMove(MouseEvent event) { 486 handleMouseMove(event); 487 } 488 }); 489 490 if (fTextViewer != null) 491 fTextViewer.addTextListener(fInternalListener); 492 493 return fCanvas; 494 } 495 496 499 private void handleDispose() { 500 501 if (fTextViewer != null) { 502 fTextViewer.removeTextListener(fInternalListener); 503 fTextViewer= null; 504 } 505 506 if (fModel != null) 507 fModel.removeAnnotationModelListener(fInternalListener); 508 509 if (fBuffer != null) { 510 fBuffer.dispose(); 511 fBuffer= null; 512 } 513 514 if (fHitDetectionCursor != null) { 515 fHitDetectionCursor.dispose(); 516 fHitDetectionCursor= null; 517 } 518 519 fConfiguredAnnotationTypes.clear(); 520 fAllowedAnnotationTypes.clear(); 521 fConfiguredHeaderAnnotationTypes.clear(); 522 fAllowedHeaderAnnotationTypes.clear(); 523 fAnnotationTypes2Colors.clear(); 524 fAnnotationsSortedByLayer.clear(); 525 fLayersSortedByLayer.clear(); 526 } 527 528 533 private void doubleBufferPaint(GC dest) { 534 535 Point size= fCanvas.getSize(); 536 537 if (size.x <= 0 || size.y <= 0) 538 return; 539 540 if (fBuffer != null) { 541 Rectangle r= fBuffer.getBounds(); 542 if (r.width != size.x || r.height != size.y) { 543 fBuffer.dispose(); 544 fBuffer= null; 545 } 546 } 547 if (fBuffer == null) 548 fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); 549 550 GC gc= new GC(fBuffer); 551 try { 552 gc.setBackground(fCanvas.getBackground()); 553 gc.fillRectangle(0, 0, size.x, size.y); 554 555 cacheAnnotations(); 556 557 if (fTextViewer instanceof ITextViewerExtension5) 558 doPaint1(gc); 559 else 560 doPaint(gc); 561 562 } finally { 563 gc.dispose(); 564 } 565 566 dest.drawImage(fBuffer, 0, 0); 567 } 568 569 574 private void doPaint(GC gc) { 575 576 Rectangle r= new Rectangle(0, 0, 0, 0); 577 int yy, hh= ANNOTATION_HEIGHT; 578 579 IDocument document= fTextViewer.getDocument(); 580 IRegion visible= fTextViewer.getVisibleRegion(); 581 582 StyledText textWidget= fTextViewer.getTextWidget(); 583 int maxLines= textWidget.getLineCount(); 584 585 Point size= fCanvas.getSize(); 586 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); 587 588 if (size.y > writable) 589 size.y= Math.max(writable - fHeader.getSize().y, 0); 590 591 for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { 592 Object annotationType= iterator.next(); 593 594 if (skip(annotationType)) 595 continue; 596 597 int[] style= new int[] { FilterIterator.PERSISTENT, FilterIterator.TEMPORARY }; 598 for (int t=0; t < style.length; t++) { 599 600 Iterator e= new FilterIterator(annotationType, style[t], fCachedAnnotations.iterator()); 601 Color fill= getFillColor(annotationType, style[t] == FilterIterator.TEMPORARY); 602 Color stroke= getStrokeColor(annotationType, style[t] == FilterIterator.TEMPORARY); 603 604 for (int i= 0; e.hasNext(); i++) { 605 606 Annotation a= (Annotation) e.next(); 607 Position p= fModel.getPosition(a); 608 609 if (p == null || !p.overlapsWith(visible.getOffset(), visible.getLength())) 610 continue; 611 612 int annotationOffset= Math.max(p.getOffset(), visible.getOffset()); 613 int annotationEnd= Math.min(p.getOffset() + p.getLength(), visible.getOffset() + visible.getLength()); 614 int annotationLength= annotationEnd - annotationOffset; 615 616 try { 617 if (ANNOTATION_HEIGHT_SCALABLE) { 618 int numbersOfLines= document.getNumberOfLines(annotationOffset, annotationLength); 619 IRegion lastLine= document.getLineInformationOfOffset(annotationOffset + annotationLength); 621 if (lastLine.getOffset() == annotationOffset + annotationLength) { 622 numbersOfLines -= 2; 623 hh= (numbersOfLines * size.y) / maxLines + ANNOTATION_HEIGHT; 624 if (hh < ANNOTATION_HEIGHT) 625 hh= ANNOTATION_HEIGHT; 626 } else 627 hh= ANNOTATION_HEIGHT; 628 } 629 fAnnotationHeight= hh; 630 631 int startLine= textWidget.getLineAtOffset(annotationOffset - visible.getOffset()); 632 yy= Math.min((startLine * size.y) / maxLines, size.y - hh); 633 634 if (fill != null) { 635 gc.setBackground(fill); 636 gc.fillRectangle(INSET, yy, size.x-(2*INSET), hh); 637 } 638 639 if (stroke != null) { 640 gc.setForeground(stroke); 641 r.x= INSET; 642 r.y= yy; 643 r.width= size.x - (2 * INSET); 644 r.height= hh; 645 gc.setLineWidth(0); gc.drawRectangle(r); 647 } 648 } catch (BadLocationException x) { 649 } 650 } 651 } 652 } 653 } 654 655 private void cacheAnnotations() { 656 fCachedAnnotations.clear(); 657 if (fModel != null) { 658 Iterator iter= fModel.getAnnotationIterator(); 659 while (iter.hasNext()) { 660 Annotation annotation= (Annotation) iter.next(); 661 662 if (annotation.isMarkedDeleted()) 663 continue; 664 665 if (skip(annotation.getType())) 666 continue; 667 668 fCachedAnnotations.add(annotation); 669 } 670 } 671 } 672 673 679 private void doPaint1(GC gc) { 680 681 Rectangle r= new Rectangle(0, 0, 0, 0); 682 int yy, hh= ANNOTATION_HEIGHT; 683 684 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; 685 IDocument document= fTextViewer.getDocument(); 686 StyledText textWidget= fTextViewer.getTextWidget(); 687 688 int maxLines= textWidget.getLineCount(); 689 Point size= fCanvas.getSize(); 690 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); 691 if (size.y > writable) 692 size.y= Math.max(writable - fHeader.getSize().y, 0); 693 694 for (Iterator iterator= fAnnotationsSortedByLayer.iterator(); iterator.hasNext();) { 695 Object annotationType= iterator.next(); 696 697 if (skip(annotationType)) 698 continue; 699 700 int[] style= new int[] { FilterIterator.PERSISTENT, FilterIterator.TEMPORARY }; 701 for (int t=0; t < style.length; t++) { 702 703 Iterator e= new FilterIterator(annotationType, style[t], fCachedAnnotations.iterator()); 704 Color fill= getFillColor(annotationType, style[t] == FilterIterator.TEMPORARY); 705 Color stroke= getStrokeColor(annotationType, style[t] == FilterIterator.TEMPORARY); 706 707 for (int i= 0; e.hasNext(); i++) { 708 709 Annotation a= (Annotation) e.next(); 710 Position p= fModel.getPosition(a); 711 712 if (p == null) 713 continue; 714 715 IRegion widgetRegion= extension.modelRange2WidgetRange(new Region(p.getOffset(), p.getLength())); 716 if (widgetRegion == null) 717 continue; 718 719 try { 720 if (ANNOTATION_HEIGHT_SCALABLE) { 721 int numbersOfLines= document.getNumberOfLines(p.getOffset(), p.getLength()); 722 IRegion lastLine= document.getLineInformationOfOffset(p.getOffset() + p.getLength()); 724 if (lastLine.getOffset() == p.getOffset() + p.getLength()) { 725 numbersOfLines -= 2; 726 hh= (numbersOfLines * size.y) / maxLines + ANNOTATION_HEIGHT; 727 if (hh < ANNOTATION_HEIGHT) 728 hh= ANNOTATION_HEIGHT; 729 } else 730 hh= ANNOTATION_HEIGHT; 731 } 732 fAnnotationHeight= hh; 733 734 int startLine= textWidget.getLineAtOffset(widgetRegion.getOffset()); 735 yy= Math.min((startLine * size.y) / maxLines, size.y - hh); 736 737 if (fill != null) { 738 gc.setBackground(fill); 739 gc.fillRectangle(INSET, yy, size.x-(2*INSET), hh); 740 } 741 742 if (stroke != null) { 743 gc.setForeground(stroke); 744 r.x= INSET; 745 r.y= yy; 746 r.width= size.x - (2 * INSET); 747 r.height= hh; 748 gc.setLineWidth(0); gc.drawRectangle(r); 750 } 751 } catch (BadLocationException x) { 752 } 753 } 754 } 755 } 756 } 757 758 761 public void update() { 762 if (fCanvas != null && !fCanvas.isDisposed()) { 763 Display d= fCanvas.getDisplay(); 764 if (d != null) { 765 synchronized (fRunnableLock) { 766 if (fIsRunnablePosted) 767 return; 768 fIsRunnablePosted= true; 769 } 770 d.asyncExec(fRunnable); 771 } 772 } 773 } 774 775 778 private void redraw() { 779 if (fTextViewer == null || fModel == null) 780 return; 781 782 if (fCanvas != null && !fCanvas.isDisposed()) { 783 GC gc= new GC(fCanvas); 784 doubleBufferPaint(gc); 785 gc.dispose(); 786 } 787 } 788 789 798 private int[] toLineNumbers(int y_coordinate) { 799 800 StyledText textWidget= fTextViewer.getTextWidget(); 801 int maxLines= textWidget.getContent().getLineCount(); 802 803 int rulerLength= fCanvas.getSize().y; 804 int writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); 805 806 if (rulerLength > writable) 807 rulerLength= Math.max(writable - fHeader.getSize().y, 0); 808 809 if (y_coordinate >= writable || y_coordinate >= rulerLength) 810 return new int[] {-1, -1}; 811 812 int[] lines= new int[2]; 813 814 int pixel0= Math.max(y_coordinate - 1, 0); 815 int pixel1= Math.min(rulerLength, y_coordinate + 1); 816 rulerLength= Math.max(rulerLength, 1); 817 818 lines[0]= (pixel0 * maxLines) / rulerLength; 819 lines[1]= (pixel1 * maxLines) / rulerLength; 820 821 if (fTextViewer instanceof ITextViewerExtension5) { 822 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; 823 lines[0]= extension.widgetLine2ModelLine(lines[0]); 824 lines[1]= extension.widgetLine2ModelLine(lines[1]); 825 } else { 826 try { 827 IRegion visible= fTextViewer.getVisibleRegion(); 828 int lineNumber= fTextViewer.getDocument().getLineOfOffset(visible.getOffset()); 829 lines[0] += lineNumber; 830 lines[1] += lineNumber; 831 } catch (BadLocationException x) { 832 } 833 } 834 835 return lines; 836 } 837 838 845 private Position getAnnotationPosition(int[] lineNumbers, boolean ignoreSelectedAnnotation) { 846 if (lineNumbers[0] == -1) 847 return null; 848 849 Position found= null; 850 851 try { 852 IDocument d= fTextViewer.getDocument(); 853 IRegion line= d.getLineInformation(lineNumbers[0]); 854 855 Point currentSelection= fTextViewer.getSelectedRange(); 856 857 int start= line.getOffset(); 858 859 line= d.getLineInformation(lineNumbers[lineNumbers.length - 1]); 860 int end= line.getOffset() + line.getLength(); 861 862 for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { 863 864 Object annotationType= fAnnotationsSortedByLayer.get(i); 865 866 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY); 867 while (e.hasNext() && found == null) { 868 Annotation a= (Annotation) e.next(); 869 if (a.isMarkedDeleted()) 870 continue; 871 872 if (skip(a.getType())) 873 continue; 874 875 Position p= fModel.getPosition(a); 876 if (p == null) 877 continue; 878 879 int posOffset= p.getOffset(); 880 int posEnd= posOffset + p.getLength(); 881 IRegion region= d.getLineInformationOfOffset(posEnd); 882 if (posEnd > posOffset && region.getOffset() == posEnd) { 884 posEnd--; 885 region= d.getLineInformationOfOffset(posEnd); 886 } 887 888 if (posOffset <= end && posEnd >= start) { 889 if (ignoreSelectedAnnotation || currentSelection.x != posOffset || currentSelection.y != p.getLength()) 890 found= p; 891 } 892 } 893 } 894 } catch (BadLocationException x) { 895 } 896 897 return found; 898 } 899 900 907 private int findBestMatchingLineNumber(int[] lineNumbers) { 908 if (lineNumbers == null || lineNumbers.length < 1) 909 return -1; 910 911 try { 912 Position pos= getAnnotationPosition(lineNumbers, true); 913 if (pos == null) 914 return -1; 915 return fTextViewer.getDocument().getLineOfOffset(pos.getOffset()); 916 } catch (BadLocationException ex) { 917 return -1; 918 } 919 } 920 921 926 private void handleMouseDown(MouseEvent event) { 927 if (fTextViewer != null) { 928 int[] lines= toLineNumbers(event.y); 929 Position p= getAnnotationPosition(lines, false); 930 if (p != null) { 931 fTextViewer.revealRange(p.getOffset(), p.getLength()); 932 fTextViewer.setSelectedRange(p.getOffset(), p.getLength()); 933 } 934 fTextViewer.getTextWidget().setFocus(); 935 } 936 fLastMouseButtonActivityLine= toDocumentLineNumber(event.y); 937 } 938 939 944 private void handleMouseMove(MouseEvent event) { 945 if (fTextViewer != null) { 946 int[] lines= toLineNumbers(event.y); 947 Position p= getAnnotationPosition(lines, true); 948 Cursor cursor= (p != null ? fHitDetectionCursor : null); 949 if (cursor != fLastCursor) { 950 fCanvas.setCursor(cursor); 951 fLastCursor= cursor; 952 } 953 } 954 } 955 956 959 public void addAnnotationType(Object annotationType) { 960 fConfiguredAnnotationTypes.add(annotationType); 961 fAllowedAnnotationTypes.clear(); 962 } 963 964 967 public void removeAnnotationType(Object annotationType) { 968 fConfiguredAnnotationTypes.remove(annotationType); 969 fAllowedAnnotationTypes.clear(); 970 } 971 972 975 public void setAnnotationTypeLayer(Object annotationType, int layer) { 976 int j= fAnnotationsSortedByLayer.indexOf(annotationType); 977 if (j != -1) { 978 fAnnotationsSortedByLayer.remove(j); 979 fLayersSortedByLayer.remove(j); 980 } 981 982 if (layer >= 0) { 983 int i= 0; 984 int size= fLayersSortedByLayer.size(); 985 while (i < size && layer >= ((Integer )fLayersSortedByLayer.get(i)).intValue()) 986 i++; 987 Integer layerObj= new Integer (layer); 988 fLayersSortedByLayer.add(i, layerObj); 989 fAnnotationsSortedByLayer.add(i, annotationType); 990 } 991 } 992 993 996 public void setAnnotationTypeColor(Object annotationType, Color color) { 997 if (color != null) 998 fAnnotationTypes2Colors.put(annotationType, color); 999 else 1000 fAnnotationTypes2Colors.remove(annotationType); 1001 } 1002 1003 1009 private boolean skip(Object annotationType) { 1010 return !contains(annotationType, fAllowedAnnotationTypes, fConfiguredAnnotationTypes); 1011 } 1012 1013 1020 private boolean skipInHeader(Object annotationType) { 1021 return !contains(annotationType, fAllowedHeaderAnnotationTypes, fConfiguredHeaderAnnotationTypes); 1022 } 1023 1024 1036 private boolean contains(Object annotationType, Map allowed, Set configured) { 1037 Boolean cached= (Boolean ) allowed.get(annotationType); 1038 if (cached != null) 1039 return cached.booleanValue(); 1040 1041 boolean covered= isCovered(annotationType, configured); 1042 allowed.put(annotationType, covered ? Boolean.TRUE : Boolean.FALSE); 1043 return covered; 1044 } 1045 1046 1057 private boolean isCovered(Object annotationType, Set configured) { 1058 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 1059 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 1060 Iterator e= configured.iterator(); 1061 while (e.hasNext()) { 1062 if (extension.isSubtype(annotationType,e.next())) 1063 return true; 1064 } 1065 return false; 1066 } 1067 return configured.contains(annotationType); 1068 } 1069 1070 1079 private static RGB interpolate(RGB fg, RGB bg, double scale) { 1080 return new RGB( 1081 (int) ((1.0-scale) * fg.red + scale * bg.red), 1082 (int) ((1.0-scale) * fg.green + scale * bg.green), 1083 (int) ((1.0-scale) * fg.blue + scale * bg.blue) 1084 ); 1085 } 1086 1087 1093 private static double greyLevel(RGB rgb) { 1094 if (rgb.red == rgb.green && rgb.green == rgb.blue) 1095 return rgb.red; 1096 return (0.299 * rgb.red + 0.587 * rgb.green + 0.114 * rgb.blue + 0.5); 1097 } 1098 1099 1105 private static boolean isDark(RGB rgb) { 1106 return greyLevel(rgb) > 128; 1107 } 1108 1109 1116 private Color getColor(Object annotationType, double scale) { 1117 Color base= findColor(annotationType); 1118 if (base == null) 1119 return null; 1120 1121 RGB baseRGB= base.getRGB(); 1122 RGB background= fCanvas.getBackground().getRGB(); 1123 1124 boolean darkBase= isDark(baseRGB); 1125 boolean darkBackground= isDark(background); 1126 if (darkBase && darkBackground) 1127 background= new RGB(255, 255, 255); 1128 else if (!darkBase && !darkBackground) 1129 background= new RGB(0, 0, 0); 1130 1131 return fSharedTextColors.getColor(interpolate(baseRGB, background, scale)); 1132 } 1133 1134 1141 private Color findColor(Object annotationType) { 1142 Color color= (Color) fAnnotationTypes2Colors.get(annotationType); 1143 if (color != null) 1144 return color; 1145 1146 if (fAnnotationAccess instanceof IAnnotationAccessExtension) { 1147 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; 1148 Object [] superTypes= extension.getSupertypes(annotationType); 1149 if (superTypes != null) { 1150 for (int i= 0; i < superTypes.length; i++) { 1151 color= (Color) fAnnotationTypes2Colors.get(superTypes[i]); 1152 if (color != null) 1153 return color; 1154 } 1155 } 1156 } 1157 1158 return null; 1159 } 1160 1161 1168 private Color getStrokeColor(Object annotationType, boolean temporary) { 1169 return getColor(annotationType, temporary ? 0.5 : 0.2); 1170 } 1171 1172 1179 private Color getFillColor(Object annotationType, boolean temporary) { 1180 return getColor(annotationType, temporary ? 0.9 : 0.6); 1181 } 1182 1183 1186 public int getLineOfLastMouseButtonActivity() { 1187 return fLastMouseButtonActivityLine; 1188 } 1189 1190 1193 public int toDocumentLineNumber(int y_coordinate) { 1194 1195 if (fTextViewer == null || y_coordinate == -1) 1196 return -1; 1197 1198 int[] lineNumbers= toLineNumbers(y_coordinate); 1199 int bestLine= findBestMatchingLineNumber(lineNumbers); 1200 if (bestLine == -1 && lineNumbers.length > 0) 1201 return lineNumbers[0]; 1202 return bestLine; 1203 } 1204 1205 1208 public IAnnotationModel getModel() { 1209 return fModel; 1210 } 1211 1212 1215 public int getAnnotationHeight() { 1216 return fAnnotationHeight; 1217 } 1218 1219 1222 public boolean hasAnnotation(int y) { 1223 return findBestMatchingLineNumber(toLineNumbers(y)) != -1; 1224 } 1225 1226 1229 public Control getHeaderControl() { 1230 return fHeader; 1231 } 1232 1233 1236 public void addHeaderAnnotationType(Object annotationType) { 1237 fConfiguredHeaderAnnotationTypes.add(annotationType); 1238 fAllowedHeaderAnnotationTypes.clear(); 1239 } 1240 1241 1244 public void removeHeaderAnnotationType(Object annotationType) { 1245 fConfiguredHeaderAnnotationTypes.remove(annotationType); 1246 fAllowedHeaderAnnotationTypes.clear(); 1247 } 1248 1249 1252 private void updateHeader() { 1253 if (fHeader == null || fHeader.isDisposed()) 1254 return; 1255 1256 fHeader.setToolTipText(null); 1257 1258 Object colorType= null; 1259 outer: for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { 1260 Object annotationType= fAnnotationsSortedByLayer.get(i); 1261 if (skipInHeader(annotationType) || skip(annotationType)) 1262 continue; 1263 1264 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY | FilterIterator.IGNORE_BAGS, fCachedAnnotations.iterator()); 1265 while (e.hasNext()) { 1266 if (e.next() != null) { 1267 colorType= annotationType; 1268 break outer; 1269 } 1270 } 1271 } 1272 1273 Color color= null; 1274 if (colorType != null) 1275 color= findColor(colorType); 1276 1277 if (color == null) { 1278 if (fHeaderPainter != null) 1279 fHeaderPainter.setColor(null); 1280 } else { 1281 if (fHeaderPainter == null) { 1282 fHeaderPainter= new HeaderPainter(); 1283 fHeader.addPaintListener(fHeaderPainter); 1284 } 1285 fHeaderPainter.setColor(color); 1286 } 1287 1288 fHeader.redraw(); 1289 1290 } 1291 1292 1295 private void updateHeaderToolTipText() { 1296 if (fHeader == null || fHeader.isDisposed()) 1297 return; 1298 1299 if (fHeader.getToolTipText() != null) 1300 return; 1301 1302 String overview= ""; 1304 for (int i= fAnnotationsSortedByLayer.size() -1; i >= 0; i--) { 1305 1306 Object annotationType= fAnnotationsSortedByLayer.get(i); 1307 1308 if (skipInHeader(annotationType) || skip(annotationType)) 1309 continue; 1310 1311 int count= 0; 1312 String annotationTypeLabel= null; 1313 1314 Iterator e= new FilterIterator(annotationType, FilterIterator.PERSISTENT | FilterIterator.TEMPORARY | FilterIterator.IGNORE_BAGS, fCachedAnnotations.iterator()); 1315 while (e.hasNext()) { 1316 Annotation annotation= (Annotation)e.next(); 1317 if (annotation != null) { 1318 if (annotationTypeLabel == null) 1319 annotationTypeLabel= ((IAnnotationAccessExtension)fAnnotationAccess).getTypeLabel(annotation); 1320 count++; 1321 } 1322 } 1323 1324 if (annotationTypeLabel != null) { 1325 if (overview.length() > 0) 1326 overview += "\n"; overview += JFaceTextMessages.getFormattedString("OverviewRulerHeader.toolTipTextEntry", new Object [] {annotationTypeLabel, new Integer (count)}); } 1329 } 1330 1331 if (overview.length() > 0) 1332 fHeader.setToolTipText(overview); 1333 } 1334} 1335 | Popular Tags |