1 11 package org.eclipse.jface.fieldassist; 12 13 import org.eclipse.core.runtime.ListenerList; 14 import org.eclipse.swt.SWT; 15 import org.eclipse.swt.events.DisposeEvent; 16 import org.eclipse.swt.events.DisposeListener; 17 import org.eclipse.swt.events.FocusEvent; 18 import org.eclipse.swt.events.FocusListener; 19 import org.eclipse.swt.events.MenuDetectEvent; 20 import org.eclipse.swt.events.MenuDetectListener; 21 import org.eclipse.swt.events.MouseAdapter; 22 import org.eclipse.swt.events.MouseEvent; 23 import org.eclipse.swt.events.MouseMoveListener; 24 import org.eclipse.swt.events.MouseTrackListener; 25 import org.eclipse.swt.events.PaintEvent; 26 import org.eclipse.swt.events.PaintListener; 27 import org.eclipse.swt.events.SelectionEvent; 28 import org.eclipse.swt.events.SelectionListener; 29 import org.eclipse.swt.graphics.GC; 30 import org.eclipse.swt.graphics.Image; 31 import org.eclipse.swt.graphics.Point; 32 import org.eclipse.swt.graphics.Rectangle; 33 import org.eclipse.swt.graphics.Region; 34 import org.eclipse.swt.widgets.Composite; 35 import org.eclipse.swt.widgets.Control; 36 import org.eclipse.swt.widgets.Display; 37 import org.eclipse.swt.widgets.Event; 38 import org.eclipse.swt.widgets.Listener; 39 import org.eclipse.swt.widgets.Shell; 40 import org.eclipse.swt.widgets.Widget; 41 42 74 public class ControlDecoration { 75 78 private static boolean DEBUG = false; 79 80 83 private static boolean CARBON = "carbon".equals(SWT.getPlatform()); 85 88 private Control control; 89 90 94 private Composite composite; 95 96 99 private Image image; 100 101 104 private String descriptionText; 105 108 private int position; 109 110 113 private boolean visible = true; 114 115 119 private boolean showOnlyOnFocus = false; 120 121 125 private boolean showHover = true; 126 127 130 private int marginWidth = 0; 131 132 135 private ListenerList selectionListeners = new ListenerList(); 136 137 140 private ListenerList menuDetectListeners = new ListenerList(); 141 142 145 private FocusListener focusListener; 146 147 150 private DisposeListener disposeListener; 151 152 155 private PaintListener paintListener; 156 157 160 private MouseTrackListener mouseTrackListener; 161 162 165 private MouseMoveListener mouseMoveListener; 166 167 170 private Listener compositeListener; 171 172 176 private Control moveListeningTarget = null; 177 178 181 private int listenerInstalls = 0; 182 183 186 private Rectangle decorationRectangle; 187 188 195 private boolean hasFocus = false; 196 197 200 private Hover hover; 201 202 205 class Hover { 206 private static final String EMPTY = ""; 208 211 private int hao = 10; 212 213 216 private int haw = 8; 217 218 221 private int hah = 10; 222 223 226 private int hm = 2; 227 228 231 Shell hoverShell; 232 233 236 String text = EMPTY; 237 238 241 Region region; 242 243 247 boolean arrowOnLeft = true; 248 249 252 Hover(Shell parent) { 253 final Display display = parent.getDisplay(); 254 hoverShell = new Shell(parent, SWT.NO_TRIM | SWT.ON_TOP 255 | SWT.NO_FOCUS); 256 hoverShell.setBackground(display 257 .getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 258 hoverShell.setForeground(display 259 .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); 260 hoverShell.addPaintListener(new PaintListener() { 261 public void paintControl(PaintEvent pe) { 262 pe.gc.drawText(text, hm, hm); 263 if (!CARBON) { 264 pe.gc.drawPolygon(getPolygon(true)); 265 } 266 } 267 }); 268 hoverShell.addMouseListener(new MouseAdapter() { 269 public void mouseDown(MouseEvent e) { 270 hideHover(); 271 } 272 }); 273 } 274 275 280 int[] getPolygon(boolean border) { 281 Point e = getExtent(); 282 int b = border ? 1 : 0; 283 if (arrowOnLeft) { 284 return new int[] { 0, 0, e.x - b, 0, e.x - b, e.y - b, 285 hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao, 286 e.y - b, 0, e.y - b, 0, 0 }; 287 } 288 return new int[] { 0, 0, e.x - b, 0, e.x - b, e.y - b, 289 e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b, 290 e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0 }; 291 } 292 293 297 void dispose() { 298 if (!hoverShell.isDisposed()) { 299 hoverShell.dispose(); 300 } 301 if (region != null) { 302 region.dispose(); 303 } 304 } 305 306 309 void setVisible(boolean visible) { 310 if (visible) { 311 if (!hoverShell.isVisible()) { 312 hoverShell.setVisible(true); 313 } 314 } else { 315 if (hoverShell.isVisible()) { 316 hoverShell.setVisible(false); 317 } 318 } 319 } 320 321 326 void setText(String t, Rectangle decorationRectangle, 327 Control targetControl) { 328 if (t == null) { 329 t = EMPTY; 330 } 331 if (!t.equals(text)) { 332 Point oldSize = getExtent(); 333 text = t; 334 hoverShell.redraw(); 335 Point newSize = getExtent(); 336 if (!oldSize.equals(newSize)) { 337 arrowOnLeft = decorationRectangle.x <= targetControl 339 .getLocation().x; 340 setNewShape(); 341 } 342 } 343 344 Point extent = getExtent(); 345 int y = -extent.y - hah + 1; 346 int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw / 2; 347 348 hoverShell.setLocation(control.getParent().toDisplay( 349 decorationRectangle.x + x, decorationRectangle.y + y)); 350 } 351 352 355 boolean isVisible() { 356 return hoverShell.isVisible(); 357 } 358 359 362 Point getExtent() { 363 GC gc = new GC(hoverShell); 364 Point e = gc.textExtent(text); 365 gc.dispose(); 366 e.x += hm * 2; 367 e.y += hm * 2; 368 return e; 369 } 370 371 374 void setNewShape() { 375 Region oldRegion = region; 376 region = new Region(); 377 region.add(getPolygon(false)); 378 hoverShell.setRegion(region); 379 if (oldRegion != null) { 380 oldRegion.dispose(); 381 } 382 383 } 384 } 385 386 413 public ControlDecoration(Control control, int position) { 414 this(control, position, null); 415 416 } 417 418 457 public ControlDecoration(Control control, int position, Composite composite) { 458 this.position = position; 459 this.control = control; 460 this.composite = composite; 461 462 addControlListeners(); 463 464 } 465 466 486 public void addMenuDetectListener(MenuDetectListener listener) { 487 menuDetectListeners.add(listener); 488 } 489 490 502 public void removeMenuDetectListener(MenuDetectListener listener) { 503 menuDetectListeners.remove(listener); 504 } 505 506 530 public void addSelectionListener(SelectionListener listener) { 531 selectionListeners.add(listener); 532 } 533 534 546 public void removeSelectionListener(SelectionListener listener) { 547 selectionListeners.remove(listener); 548 } 549 550 555 public void dispose() { 556 if (control == null) { 557 return; 558 } 559 if (hover != null) { 560 hover.dispose(); 561 hover = null; 562 } 563 removeControlListeners(); 564 control = null; 565 } 566 567 573 public Control getControl() { 574 return control; 575 } 576 577 581 private void addControlListeners() { 582 disposeListener = new DisposeListener() { 583 public void widgetDisposed(DisposeEvent event) { 584 dispose(); 585 } 586 }; 587 printAddListener(control, "DISPOSE"); control.addDisposeListener(disposeListener); 589 590 focusListener = new FocusListener() { 591 public void focusGained(FocusEvent event) { 592 hasFocus = true; 593 if (showOnlyOnFocus) { 594 update(); 595 } 596 } 597 598 public void focusLost(FocusEvent event) { 599 hasFocus = false; 600 if (showOnlyOnFocus) { 601 update(); 602 } 603 } 604 }; 605 printAddListener(control, "FOCUS"); control.addFocusListener(focusListener); 607 608 paintListener = new PaintListener() { 610 public void paintControl(PaintEvent event) { 611 Control control = (Control) event.widget; 612 Rectangle rect = getDecorationRectangle(control); 613 if (shouldShowDecoration()) { 614 event.gc.drawImage(getImage(), rect.x, rect.y); 615 } 616 } 617 }; 618 619 mouseMoveListener = new MouseMoveListener() { 622 public void mouseMove(MouseEvent event) { 623 if (showHover) { 624 if (!decorationRectangle.contains(event.x, event.y)) { 625 hideHover(); 626 printRemoveListener(event.widget, "MOUSEMOVE"); ((Control) event.widget) 629 .removeMouseMoveListener(mouseMoveListener); 630 moveListeningTarget = null; 631 } 632 } 633 } 634 }; 635 636 mouseTrackListener = new MouseTrackListener() { 638 public void mouseExit(MouseEvent event) { 639 Control target = (Control) event.widget; 641 if (target == moveListeningTarget) { 642 printRemoveListener(target, "MOUSEMOVE"); target.removeMouseMoveListener(mouseMoveListener); 644 moveListeningTarget = null; 645 } 646 hideHover(); 647 } 648 649 public void mouseHover(MouseEvent event) { 650 if (showHover) { 651 decorationRectangle = getDecorationRectangle((Control) event.widget); 652 if (decorationRectangle.contains(event.x, event.y)) { 653 showHoverText(getDescriptionText()); 654 Control target = (Control) event.widget; 655 if (moveListeningTarget == null) { 656 printAddListener(target, "MOUSEMOVE"); target.addMouseMoveListener(mouseMoveListener); 658 moveListeningTarget = target; 659 } else if (target != moveListeningTarget) { 660 printRemoveListener(moveListeningTarget, 661 "MOUSEMOVE"); moveListeningTarget 663 .removeMouseMoveListener(mouseMoveListener); 664 printAddListener(target, "MOUSEMOVE"); target.addMouseMoveListener(mouseMoveListener); 666 moveListeningTarget = target; 667 } else { 668 } 670 } 671 } 672 } 673 674 public void mouseEnter(MouseEvent event) { 675 } 677 }; 678 679 compositeListener = new Listener() { 680 public void handleEvent(Event event) { 681 if (!visible) { 683 return; 684 } 685 switch (event.type) { 687 case SWT.MouseDown: 688 if (!selectionListeners.isEmpty()) 689 notifySelectionListeners(event); 690 break; 691 case SWT.MouseDoubleClick: 692 if (!selectionListeners.isEmpty()) 693 notifySelectionListeners(event); 694 break; 695 case SWT.MenuDetect: 696 if (!menuDetectListeners.isEmpty()) 697 notifyMenuDetectListeners(event); 698 break; 699 } 700 } 701 }; 702 703 Composite c = control.getParent(); 707 while (c != null) { 708 installCompositeListeners(c); 709 if (composite != null && composite == c) { 710 c = null; 712 } else if (c instanceof Shell) { 713 c = null; 715 } else { 716 c = c.getParent(); 717 } 718 } 719 update(); 722 } 723 724 728 private void installCompositeListeners(Composite c) { 729 if (!c.isDisposed()) { 730 printAddListener(c, "PAINT"); c.addPaintListener(paintListener); 732 printAddListener(c, "MOUSETRACK"); c.addMouseTrackListener(mouseTrackListener); 734 printAddListener(c, "SWT.MenuDetect"); c.addListener(SWT.MenuDetect, compositeListener); 736 printAddListener(c, "SWT.MouseDown"); c.addListener(SWT.MouseDown, compositeListener); 738 printAddListener(c, "SWT.MouseDoubleClick"); c.addListener(SWT.MouseDoubleClick, compositeListener); 740 } 741 } 742 743 747 private void removeCompositeListeners(Composite c) { 748 if (!c.isDisposed()) { 749 printRemoveListener(c, "PAINT"); c.removePaintListener(paintListener); 751 printRemoveListener(c, "MOUSETRACK"); c.removeMouseTrackListener(mouseTrackListener); 753 printRemoveListener(c, "SWT.MenuDetect"); c.removeListener(SWT.MenuDetect, compositeListener); 755 printRemoveListener(c, "SWT.MouseDown"); c.removeListener(SWT.MouseDown, compositeListener); 757 printRemoveListener(c, "SWT.MouseDoubleClick"); c.removeListener(SWT.MouseDoubleClick, compositeListener); 759 } 760 } 761 762 private void notifySelectionListeners(Event event) { 763 if (!(event.widget instanceof Control)) { 764 return; 765 } 766 if (getDecorationRectangle((Control) event.widget).contains(event.x, 767 event.y)) { 768 SelectionEvent clientEvent = new SelectionEvent(event); 769 clientEvent.data = this; 770 if (getImage() != null) { 771 clientEvent.height = getImage().getBounds().height; 772 clientEvent.width = getImage().getBounds().width; 773 } 774 Object [] listeners; 775 switch (event.type) { 776 case SWT.MouseDoubleClick: 777 if (event.button == 1) { 778 listeners = selectionListeners.getListeners(); 779 for (int i = 0; i < listeners.length; i++) { 780 ((SelectionListener) listeners[i]) 781 .widgetDefaultSelected(clientEvent); 782 } 783 } 784 break; 785 case SWT.MouseDown: 786 if (event.button == 1) { 787 listeners = selectionListeners.getListeners(); 788 for (int i = 0; i < listeners.length; i++) { 789 ((SelectionListener) listeners[i]) 790 .widgetSelected(clientEvent); 791 } 792 } 793 break; 794 } 795 } 796 } 797 798 private void notifyMenuDetectListeners(Event event) { 799 if (getDecorationRectangle(null).contains(event.x, event.y)) { 800 MenuDetectEvent clientEvent = new MenuDetectEvent(event); 801 clientEvent.data = this; 802 Object [] listeners = menuDetectListeners.getListeners(); 803 for (int i = 0; i < listeners.length; i++) { 804 ((MenuDetectListener) listeners[i]).menuDetected(clientEvent); 805 806 } 807 } 808 } 809 810 823 public void showHoverText(String text) { 824 if (control == null) { 825 return; 826 } 827 showHoverText(text, control); 828 } 829 830 843 public void hideHover() { 844 if (hover != null) { 845 hover.setVisible(false); 846 } 847 } 848 849 855 public void show() { 856 if (!visible) { 857 visible = true; 858 update(); 859 } 860 } 861 862 866 public void hide() { 867 if (visible) { 868 visible = false; 869 update(); 870 } 871 } 872 873 880 public String getDescriptionText() { 881 return descriptionText; 882 } 883 884 892 public void setDescriptionText(String text) { 893 this.descriptionText = text; 894 update(); 895 } 896 897 903 public Image getImage() { 904 return image; 905 } 906 907 914 public void setImage(Image image) { 915 this.image = image; 916 update(); 917 } 918 919 930 public boolean getShowOnlyOnFocus() { 931 return showOnlyOnFocus; 932 } 933 934 947 public void setShowOnlyOnFocus(boolean showOnlyOnFocus) { 948 this.showOnlyOnFocus = showOnlyOnFocus; 949 update(); 950 } 951 952 962 public boolean getShowHover() { 963 return showHover; 964 } 965 966 977 public void setShowHover(boolean showHover) { 978 this.showHover = showHover; 979 update(); 980 } 981 982 991 public int getMarginWidth() { 992 return marginWidth; 993 } 994 995 1005 public void setMarginWidth(int marginWidth) { 1006 this.marginWidth = marginWidth; 1007 update(); 1008 } 1009 1010 1014 protected void update() { 1015 if (control == null || control.isDisposed()) { 1016 return; 1017 } 1018 Rectangle rect = getDecorationRectangle(control.getShell()); 1019 control.getShell() 1021 .redraw(rect.x, rect.y, rect.width, rect.height, true); 1022 control.getShell().update(); 1023 if (hover != null && getDescriptionText() != null) { 1024 hover.setText(getDescriptionText(), getDecorationRectangle(control 1025 .getParent()), control); 1026 } 1027 } 1028 1029 1033 private void showHoverText(String text, Control hoverNear) { 1034 if (!showHover) { 1036 return; 1037 } 1038 if (text == null) { 1040 hideHover(); 1041 return; 1042 } 1043 1044 if (control == null) { 1046 return; 1047 } 1048 if (hover == null) { 1050 hover = new Hover(hoverNear.getShell()); 1051 } 1052 hover.setText(text, getDecorationRectangle(control.getParent()), 1053 control); 1054 hover.setVisible(true); 1055 } 1056 1057 1060 private void removeControlListeners() { 1061 if (control == null) { 1062 return; 1063 } 1064 printRemoveListener(control, "FOCUS"); control.removeFocusListener(focusListener); 1066 focusListener = null; 1067 1068 printRemoveListener(control, "DISPOSE"); control.removeDisposeListener(disposeListener); 1070 disposeListener = null; 1071 1072 Composite c = control.getParent(); 1073 while (c != null) { 1074 removeCompositeListeners(c); 1075 if (composite != null && composite == c) { 1076 c = null; 1079 } else if (c instanceof Shell) { 1080 c = null; 1083 } else { 1084 c = c.getParent(); 1085 } 1086 } 1087 paintListener = null; 1088 mouseTrackListener = null; 1089 compositeListener = null; 1090 1091 if (moveListeningTarget != null) { 1093 printRemoveListener(moveListeningTarget, "MOUSEMOVE"); moveListeningTarget.removeMouseMoveListener(mouseMoveListener); 1095 moveListeningTarget = null; 1096 mouseMoveListener = null; 1097 } 1098 if (DEBUG) { 1099 if (listenerInstalls > 0) { 1100 System.out.println("LISTENER LEAK>>>CHECK TRACE ABOVE"); } else if (listenerInstalls < 0) { 1102 System.out 1103 .println("REMOVED UNREGISTERED LISTENERS>>>CHECK TRACE ABOVE"); } else { 1105 System.out.println("ALL INSTALLED LISTENERS WERE REMOVED."); } 1107 } 1108 } 1109 1110 1119 protected Rectangle getDecorationRectangle(Control targetControl) { 1120 if (getImage() == null || control == null) { 1121 return new Rectangle(0, 0, 0, 0); 1122 } 1123 Rectangle imageBounds = getImage().getBounds(); 1125 Rectangle controlBounds = control.getBounds(); 1126 int x, y; 1127 if ((position & SWT.RIGHT) == SWT.RIGHT) { 1129 x = controlBounds.x + controlBounds.width + marginWidth; 1130 } else { 1131 x = controlBounds.x - imageBounds.width - marginWidth; 1133 } 1134 if ((position & SWT.TOP) == SWT.TOP) { 1136 y = controlBounds.y; 1137 } else if ((position & SWT.BOTTOM) == SWT.BOTTOM) { 1138 y = controlBounds.y + control.getBounds().height 1139 - imageBounds.height; 1140 } else { 1141 y = controlBounds.y 1143 + (control.getBounds().height - imageBounds.height) / 2; 1144 } 1145 1146 Point globalPoint = control.getParent().toDisplay(x, y); 1148 Point targetPoint; 1149 if (targetControl == null) { 1150 targetPoint = globalPoint; 1151 } else { 1152 targetPoint = targetControl.toControl(globalPoint); 1153 } 1154 return new Rectangle(targetPoint.x, targetPoint.y, imageBounds.width, 1155 imageBounds.height); 1156 } 1157 1158 1161 private boolean shouldShowDecoration() { 1162 if (!visible) { 1163 return false; 1164 } 1165 if (control == null || control.isDisposed() || getImage() == null) { 1166 return false; 1167 } 1168 1169 if (!control.isVisible()) { 1170 return false; 1171 } 1172 if (showOnlyOnFocus) { 1173 return hasFocus; 1174 } 1175 return true; 1176 } 1177 1178 1181 private void printAddListener(Widget widget, String listenerType) { 1182 listenerInstalls++; 1183 if (DEBUG) { 1184 System.out 1185 .println("Added listener>>>" + listenerType + " to>>>" + widget); } 1187 } 1188 1189 1192 private void printRemoveListener(Widget widget, String listenerType) { 1193 listenerInstalls--; 1194 if (DEBUG) { 1195 System.out 1196 .println("Removed listener>>>" + listenerType + " from>>>" + widget); } 1198 } 1199} 1200 | Popular Tags |