1 11 package org.eclipse.ui.internal.texteditor; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.custom.StyleRange; 19 import org.eclipse.swt.custom.StyledText; 20 import org.eclipse.swt.events.DisposeEvent; 21 import org.eclipse.swt.events.DisposeListener; 22 import org.eclipse.swt.events.FocusListener; 23 import org.eclipse.swt.events.MenuEvent; 24 import org.eclipse.swt.events.MenuListener; 25 import org.eclipse.swt.events.MouseAdapter; 26 import org.eclipse.swt.events.MouseEvent; 27 import org.eclipse.swt.events.MouseTrackAdapter; 28 import org.eclipse.swt.events.MouseTrackListener; 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.Cursor; 33 import org.eclipse.swt.graphics.Point; 34 import org.eclipse.swt.graphics.Rectangle; 35 import org.eclipse.swt.layout.GridData; 36 import org.eclipse.swt.layout.GridLayout; 37 import org.eclipse.swt.widgets.Canvas; 38 import org.eclipse.swt.widgets.Composite; 39 import org.eclipse.swt.widgets.Control; 40 import org.eclipse.swt.widgets.Display; 41 import org.eclipse.swt.widgets.Event; 42 import org.eclipse.swt.widgets.Layout; 43 import org.eclipse.swt.widgets.Listener; 44 import org.eclipse.swt.widgets.Menu; 45 import org.eclipse.swt.widgets.Shell; 46 import org.eclipse.swt.widgets.Widget; 47 48 import org.eclipse.jface.viewers.IDoubleClickListener; 49 50 import org.eclipse.jface.text.AbstractInformationControlManager; 51 import org.eclipse.jface.text.DefaultInformationControl; 52 import org.eclipse.jface.text.IInformationControl; 53 import org.eclipse.jface.text.IInformationControlCreator; 54 import org.eclipse.jface.text.IInformationControlExtension; 55 import org.eclipse.jface.text.IInformationControlExtension2; 56 import org.eclipse.jface.text.IRegion; 57 import org.eclipse.jface.text.IViewportListener; 58 import org.eclipse.jface.text.Position; 59 import org.eclipse.jface.text.Region; 60 import org.eclipse.jface.text.TextViewer; 61 import org.eclipse.jface.text.source.Annotation; 62 import org.eclipse.jface.text.source.IAnnotationAccess; 63 import org.eclipse.jface.text.source.IAnnotationAccessExtension; 64 import org.eclipse.jface.text.source.IVerticalRulerListener; 65 import org.eclipse.jface.text.source.IAnnotationModel; 66 import org.eclipse.jface.text.source.ISourceViewer; 67 import org.eclipse.jface.text.source.IVerticalRulerInfo; 68 import org.eclipse.jface.text.source.VerticalRulerEvent; 69 70 71 79 public class AnnotationExpansionControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension2 { 80 81 82 public interface ICallback { 83 void run(IInformationControlExtension2 control); 84 } 85 86 93 public static class AnnotationHoverInput { 94 public Annotation[] fAnnotations; 95 public ISourceViewer fViewer; 96 public IVerticalRulerInfo fRulerInfo; 97 public IVerticalRulerListener fAnnotationListener; 98 public IDoubleClickListener fDoubleClickListener; 99 public ICallback redoAction; 100 public IAnnotationModel model; 101 } 102 103 private final class Item { 104 Annotation fAnnotation; 105 Canvas canvas; 106 StyleRange[] oldStyles; 107 108 public void selected() { 109 Display disp= fShell.getDisplay(); 110 canvas.setCursor(fHandCursor); 111 canvas.setBackground(getSelectionColor(disp)); 113 114 oldStyles= setViewerBackground(fAnnotation); 116 117 fSelection= this; 119 120 if (fHoverManager != null) 121 fHoverManager.showInformation(); 122 123 if (fInput.fAnnotationListener != null) { 124 VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); 125 fInput.fAnnotationListener.annotationSelected(event); 126 } 127 128 } 129 130 public void defaultSelected() { 131 if (fInput.fAnnotationListener != null) { 132 VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); 133 fInput.fAnnotationListener.annotationDefaultSelected(event); 134 } 135 136 dispose(); 137 } 138 139 public void showContextMenu(Menu menu) { 140 if (fInput.fAnnotationListener != null) { 141 VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation); 142 fInput.fAnnotationListener.annotationContextMenuAboutToShow(event, menu); 143 } 144 } 145 146 public void deselect() { 147 150 fSelection= null; 152 153 resetViewerBackground(oldStyles); 154 oldStyles= null; 155 156 Display disp= fShell.getDisplay(); 157 canvas.setCursor(null); 158 canvas.setBackground(disp.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 160 161 } 162 163 } 164 165 168 private final static class MyDisposeListener implements DisposeListener { 169 172 public void widgetDisposed(DisposeEvent e) { 173 Item item= (Item) ((Widget) e.getSource()).getData(); 174 item.deselect(); 175 item.canvas= null; 176 item.fAnnotation= null; 177 item.oldStyles= null; 178 179 ((Widget) e.getSource()).setData(null); 180 } 181 } 182 183 186 private final class MyMenuDetectListener implements Listener { 187 190 public void handleEvent(Event event) { 191 if (event.type == SWT.MenuDetect) { 192 if (fInput != null) { 195 Control ruler= fInput.fRulerInfo.getControl(); 196 if (ruler != null && !ruler.isDisposed()) { 197 Menu menu= ruler.getMenu(); 198 if (menu != null && !menu.isDisposed()) { 199 menu.setLocation(event.x, event.y); 200 menu.addMenuListener(new MenuListener() { 201 202 public void menuHidden(MenuEvent e) { 203 dispose(); 204 } 205 206 public void menuShown(MenuEvent e) { 207 } 208 209 }); 210 menu.setVisible(true); 211 } 212 } 213 } 214 } 215 } 216 } 217 218 221 private final class MyMouseListener extends MouseAdapter { 222 225 public void mouseDoubleClick(MouseEvent e) { 226 Item item= (Item) ((Widget) e.getSource()).getData(); 227 if (e.button == 1 && item.fAnnotation == fInput.fAnnotations[0] && fInput.fDoubleClickListener != null) { 228 fInput.fDoubleClickListener.doubleClick(null); 229 if (fInput.redoAction != null) 231 fInput.redoAction.run(AnnotationExpansionControl.this); 232 } 233 } 242 243 246 public void mouseUp(MouseEvent e) { 247 Item item= (Item) ((Widget) e.getSource()).getData(); 248 if (item != null && e.button == 1) item.defaultSelected(); 252 } 253 254 257 public void mouseDown(MouseEvent e) { 258 super.mouseDown(e); 259 } 260 } 261 262 265 private final class MyMouseTrackListener implements MouseTrackListener { 266 269 public void mouseEnter(MouseEvent e) { 270 Item item= (Item) ((Widget) e.getSource()).getData(); 271 if (item != null) 272 item.selected(); 273 } 274 275 278 public void mouseExit(MouseEvent e) { 279 280 Item item= (Item) ((Widget) e.getSource()).getData(); 281 if (item != null) 282 item.deselect(); 283 284 org.eclipse.swt.graphics.Region region= fShell.getRegion(); 286 Canvas can= (Canvas) e.getSource(); 287 Point p= can.toDisplay(e.x, e.y); 288 if (region == null) { 289 Rectangle bounds= fShell.getBounds(); 290 if (!bounds.contains(p)) 292 dispose(); 293 } else { 294 p= fShell.toControl(p); 295 if (!region.contains(p)) 296 dispose(); 297 } 298 299 300 } 301 302 305 public void mouseHover(MouseEvent e) { 306 if (fHoverManager == null) { 307 fHoverManager= new HoverManager(); 308 fHoverManager.takesFocusWhenVisible(false); 309 fHoverManager.install(fComposite); 310 fHoverManager.showInformation(); 311 } 312 } 313 } 314 315 318 private final class MyPaintListener implements PaintListener { 319 322 public void paintControl(PaintEvent e) { 323 Canvas can= (Canvas) e.getSource(); 324 Annotation a= ((Item) can.getData()).fAnnotation; 325 if (a != null) { 326 Rectangle rect= new Rectangle(fLayouter.getBorderWidth(), fLayouter.getBorderWidth(), fLayouter.getAnnotationSize(), fLayouter.getAnnotationSize()); 327 if (fAnnotationAccessExtension != null) 328 fAnnotationAccessExtension.paint(a, e.gc, can, rect); 329 } 330 } 331 } 332 333 336 private final class HoverManager extends AbstractInformationControlManager { 337 338 341 public HoverManager() { 342 super(new IInformationControlCreator() { 343 public IInformationControl createInformationControl(Shell parent) { 344 return new DefaultInformationControl(parent); 345 } 346 }); 347 348 setMargins(5, 10); 349 setAnchor(ANCHOR_BOTTOM); 350 setFallbackAnchors(new Anchor[] {ANCHOR_BOTTOM, ANCHOR_LEFT, ANCHOR_RIGHT} ); 351 } 352 353 356 protected void computeInformation() { 357 if (fSelection != null) { 358 Rectangle subjectArea= fSelection.canvas.getBounds(); 359 Annotation annotation= fSelection.fAnnotation; 360 String msg; 361 if (annotation != null) 362 msg= annotation.getText(); 363 else 364 msg= null; 365 366 setInformation(msg, subjectArea); 367 } 368 } 369 370 371 } 372 373 374 protected AnnotationHoverInput fInput; 375 376 private Shell fShell; 377 378 protected Composite fComposite; 379 380 private Cursor fHandCursor; 381 382 private Item fSelection; 383 384 private HoverManager fHoverManager; 385 386 private IAnnotationAccessExtension fAnnotationAccessExtension; 387 388 389 390 private final MyPaintListener fPaintListener; 391 private final MyMouseTrackListener fMouseTrackListener; 392 private final MyMouseListener fMouseListener; 393 private final MyMenuDetectListener fMenuDetectListener; 394 private final DisposeListener fDisposeListener; 395 private final IViewportListener fViewportListener; 396 397 private LinearLayouter fLayouter; 398 399 406 public AnnotationExpansionControl(Shell parent, int shellStyle, IAnnotationAccess access) { 407 fPaintListener= new MyPaintListener(); 408 fMouseTrackListener= new MyMouseTrackListener(); 409 fMouseListener= new MyMouseListener(); 410 fMenuDetectListener= new MyMenuDetectListener(); 411 fDisposeListener= new MyDisposeListener(); 412 fViewportListener= new IViewportListener() { 413 414 public void viewportChanged(int verticalOffset) { 415 dispose(); 416 } 417 418 }; 419 fLayouter= new LinearLayouter(); 420 421 if (access instanceof IAnnotationAccessExtension) 422 fAnnotationAccessExtension= (IAnnotationAccessExtension) access; 423 424 fShell= new Shell(parent, shellStyle | SWT.NO_FOCUS | SWT.ON_TOP); 425 Display display= fShell.getDisplay(); 426 fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); 427 fComposite= new Composite(fShell, SWT.NO_FOCUS | SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM); 428 430 GridLayout layout= new GridLayout(1, true); 431 layout.marginHeight= 0; 432 layout.marginWidth= 0; 433 fShell.setLayout(layout); 434 435 GridData data= new GridData(GridData.FILL_BOTH); 436 data.heightHint= fLayouter.getAnnotationSize() + 2 * fLayouter.getBorderWidth() + 4; 437 fComposite.setLayoutData(data); 438 fComposite.addMouseTrackListener(new MouseTrackAdapter() { 439 440 public void mouseExit(MouseEvent e) { 441 if (fComposite == null) 442 return; 443 Control[] children= fComposite.getChildren(); 444 Rectangle bounds= null; 445 for (int i= 0; i < children.length; i++) { 446 if (bounds == null) 447 bounds= children[i].getBounds(); 448 else 449 bounds.add(children[i].getBounds()); 450 if (bounds.contains(e.x, e.y)) 451 return; 452 } 453 454 dispose(); 456 } 457 458 }); 459 460 471 fHandCursor= new Cursor(display, SWT.CURSOR_HAND); 472 fShell.setCursor(fHandCursor); 473 fComposite.setCursor(fHandCursor); 474 475 setInfoSystemColor(); 476 } 477 478 private void setInfoSystemColor() { 479 Display display= fShell.getDisplay(); 480 setForegroundColor(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); 481 setBackgroundColor(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 482 } 483 484 487 public void setInformation(String information) { 488 setInput(null); 489 } 490 491 492 495 public void setInput(Object input) { 496 if (fInput != null && fInput.fViewer != null) 497 fInput.fViewer.removeViewportListener(fViewportListener); 498 499 if (input instanceof AnnotationHoverInput) 500 fInput= (AnnotationHoverInput) input; 501 else 502 fInput= null; 503 504 inputChanged(fInput, null); 505 } 506 507 protected void inputChanged(Object newInput, Object newSelection) { 508 refresh(); 509 } 510 511 protected void refresh() { 512 adjustItemNumber(); 513 514 if (fInput == null) 515 return; 516 517 if (fInput.fAnnotations == null) 518 return; 519 520 if (fInput.fViewer != null) 521 fInput.fViewer.addViewportListener(fViewportListener); 522 523 fShell.setRegion(fLayouter.getShellRegion(fInput.fAnnotations.length)); 524 525 Layout layout= fLayouter.getLayout(fInput.fAnnotations.length); 526 fComposite.setLayout(layout); 527 528 Control[] children= fComposite.getChildren(); 529 for (int i= 0; i < fInput.fAnnotations.length; i++) { 530 Canvas canvas= (Canvas) children[i]; 531 Item item= new Item(); 532 item.canvas= canvas; 533 item.fAnnotation= fInput.fAnnotations[i]; 534 canvas.setData(item); 535 canvas.redraw(); 536 } 537 538 } 539 540 protected void adjustItemNumber() { 541 if (fComposite == null) 542 return; 543 544 Control[] children= fComposite.getChildren(); 545 int oldSize= children.length; 546 int newSize= fInput == null ? 0 : fInput.fAnnotations.length; 547 548 Display display= fShell.getDisplay(); 549 550 for (int i= oldSize; i < newSize; i++) { 552 Canvas canvas= new Canvas(fComposite, SWT.NONE); 553 Object gridData= fLayouter.getLayoutData(); 554 canvas.setLayoutData(gridData); 555 canvas.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 556 557 canvas.addPaintListener(fPaintListener); 558 559 canvas.addMouseTrackListener(fMouseTrackListener); 560 561 canvas.addMouseListener(fMouseListener); 562 563 canvas.addListener(SWT.MenuDetect, fMenuDetectListener); 564 565 canvas.addDisposeListener(fDisposeListener); 566 } 567 568 for (int i= oldSize; i > newSize; i--) { 570 Item item= (Item) children[i - 1].getData(); 571 item.deselect(); 572 children[i - 1].dispose(); 573 } 574 575 } 576 577 580 public void setVisible(boolean visible) { 581 fShell.setVisible(visible); 582 } 583 584 587 public void dispose() { 588 if (fShell != null) { 589 if (!fShell.isDisposed()) 590 fShell.dispose(); 591 fShell= null; 592 fComposite= null; 593 if (fHandCursor != null) 594 fHandCursor.dispose(); 595 fHandCursor= null; 596 if (fHoverManager != null) 597 fHoverManager.dispose(); 598 fHoverManager= null; 599 fSelection= null; 600 } 601 } 602 603 606 public boolean hasContents() { 607 return fInput.fAnnotations != null && fInput.fAnnotations.length > 0; 608 } 609 610 613 public void setSizeConstraints(int maxWidth, int maxHeight) { 614 } 617 618 621 public Point computeSizeHint() { 622 return fShell.computeSize(SWT.DEFAULT, SWT.DEFAULT); 623 } 624 625 628 public void setLocation(Point location) { 629 fShell.setLocation(location); 630 } 631 632 635 public void setSize(int width, int height) { 636 fShell.setSize(width, height); 637 } 638 639 642 public void addDisposeListener(DisposeListener listener) { 643 fShell.addDisposeListener(listener); 644 } 645 646 649 public void removeDisposeListener(DisposeListener listener) { 650 fShell.removeDisposeListener(listener); 651 } 652 653 656 public void setForegroundColor(Color foreground) { 657 fComposite.setForeground(foreground); 658 } 659 660 663 public void setBackgroundColor(Color background) { 664 fComposite.setBackground(background); 665 } 666 667 670 public boolean isFocusControl() { 671 if (fComposite.isFocusControl()) 672 return true; 673 674 Control[] children= fComposite.getChildren(); 675 for (int i= 0; i < children.length; i++) { 676 if (children[i].isFocusControl()) 677 return true; 678 } 679 return false; 680 } 681 682 685 public void setFocus() { 686 fShell.forceFocus(); 687 } 688 689 692 public void addFocusListener(FocusListener listener) { 693 fShell.addFocusListener(listener); 694 } 695 696 699 public void removeFocusListener(FocusListener listener) { 700 fShell.removeFocusListener(listener); 701 } 702 703 private StyleRange[] setViewerBackground(Annotation annotation) { 704 StyledText text= fInput.fViewer.getTextWidget(); 705 if (text == null || text.isDisposed()) 706 return null; 707 708 Display disp= text.getDisplay(); 709 710 Position pos= fInput.model.getPosition(annotation); 711 if (pos == null) 712 return null; 713 714 IRegion region= ((TextViewer)fInput.fViewer).modelRange2WidgetRange(new Region(pos.offset, pos.length)); 715 716 StyleRange[] ranges= text.getStyleRanges(region.getOffset(), region.getLength()); 717 718 List undoRanges= new ArrayList (ranges.length); 719 for (int i= 0; i < ranges.length; i++) { 720 undoRanges.add(ranges[i].clone()); 721 } 722 723 int offset= region.getOffset(); 724 StyleRange current= undoRanges.size() > 0 ? (StyleRange) undoRanges.get(0) : null; 725 int curStart= current != null ? current.start : region.getOffset() + region.getLength(); 726 int curEnd= current != null ? current.start + current.length : -1; 727 int index= 0; 728 729 while (curEnd < region.getOffset() + region.getLength()) { 731 if (curStart > offset) { 733 StyleRange undoRange= new StyleRange(offset, curStart - offset, null, null); 734 undoRanges.add(index, undoRange); 735 index++; 736 } 737 738 index++; 740 if (index < undoRanges.size()) { 741 offset= curEnd; 742 current= (StyleRange) undoRanges.get(index); 743 curStart= current.start; 744 curEnd= current.start + current.length; 745 } else if (index == undoRanges.size()) { 746 offset= curEnd; 748 current= null; 749 curStart= region.getOffset() + region.getLength(); 750 curEnd= -1; 751 } else 752 curEnd= region.getOffset() + region.getLength(); 753 } 754 755 List shadedRanges= new ArrayList (undoRanges.size()); 757 for (Iterator it= undoRanges.iterator(); it.hasNext(); ) { 758 StyleRange range= (StyleRange) ((StyleRange) it.next()).clone(); 759 shadedRanges.add(range); 760 range.background= getHighlightColor(disp); 761 } 762 763 for (Iterator iter= shadedRanges.iterator(); iter.hasNext(); ) { 765 text.setStyleRange((StyleRange) iter.next()); 766 767 } 768 769 return (StyleRange[]) undoRanges.toArray(undoRanges.toArray(new StyleRange[0])); 770 } 771 772 private void resetViewerBackground(StyleRange[] oldRanges) { 773 774 if (oldRanges == null) 775 return; 776 777 if (fInput == null) 778 return; 779 780 StyledText text= fInput.fViewer.getTextWidget(); 781 if (text == null || text.isDisposed()) 782 return; 783 784 for (int i= 0; i < oldRanges.length; i++) { 786 text.setStyleRange(oldRanges[i]); 787 } 788 } 789 790 private Color getHighlightColor(Display disp) { 791 return disp.getSystemColor(SWT.COLOR_GRAY); 792 } 793 794 private Color getSelectionColor(Display disp) { 795 return disp.getSystemColor(SWT.COLOR_GRAY); 796 } 797 798 } 799 | Popular Tags |