1 11 package org.eclipse.jface.fieldassist; 12 13 import org.eclipse.core.runtime.Assert; 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.MouseAdapter; 20 import org.eclipse.swt.events.MouseEvent; 21 import org.eclipse.swt.events.MouseTrackListener; 22 import org.eclipse.swt.events.PaintEvent; 23 import org.eclipse.swt.events.PaintListener; 24 import org.eclipse.swt.graphics.GC; 25 import org.eclipse.swt.graphics.Image; 26 import org.eclipse.swt.graphics.Point; 27 import org.eclipse.swt.graphics.Region; 28 import org.eclipse.swt.layout.FormAttachment; 29 import org.eclipse.swt.layout.FormData; 30 import org.eclipse.swt.layout.FormLayout; 31 import org.eclipse.swt.widgets.Composite; 32 import org.eclipse.swt.widgets.Control; 33 import org.eclipse.swt.widgets.Display; 34 import org.eclipse.swt.widgets.Label; 35 import org.eclipse.swt.widgets.Shell; 36 37 64 public class DecoratedField { 65 66 69 private static boolean CARBON = "carbon".equals(SWT.getPlatform()); 71 75 76 private static final int LEFT_TOP = 0; 77 78 private static final int LEFT_BOTTOM = 1; 79 80 private static final int RIGHT_TOP = 2; 81 82 private static final int RIGHT_BOTTOM = 3; 83 84 private static final int DECORATION_SLOTS = 4; 85 86 92 private class FieldDecorationData { 93 94 FieldDecoration decoration; 95 96 Label label; 97 98 FormData data; 99 100 boolean showOnFocus; 101 102 boolean visible = true; 103 104 118 FieldDecorationData(FieldDecoration decoration, Label label, 119 FormData formData, boolean showOnFocus) { 120 this.decoration = decoration; 121 this.label = label; 122 this.data = formData; 123 this.showOnFocus = showOnFocus; 124 } 125 } 126 127 130 private FieldDecorationData[] decDatas = new FieldDecorationData[DECORATION_SLOTS]; 131 132 135 private Control control; 136 137 140 private Composite form; 141 142 146 private boolean useMaxDecorationWidth = true; 147 148 151 private Hover hover; 152 153 156 class Hover { 157 private static final String EMPTY = ""; 159 162 private int hao = 10; 163 164 167 private int haw = 8; 168 169 172 private int hah = 10; 173 174 177 private int hm = 2; 178 179 182 Shell hoverShell; 183 184 187 String text = EMPTY; 188 189 192 Region region; 193 194 198 boolean arrowOnLeft = true; 199 200 203 Hover(Shell parent) { 204 final Display display = parent.getDisplay(); 205 hoverShell = new Shell(parent, SWT.NO_TRIM | SWT.ON_TOP 206 | SWT.NO_FOCUS); 207 hoverShell.setBackground(display 208 .getSystemColor(SWT.COLOR_INFO_BACKGROUND)); 209 hoverShell.setForeground(display 210 .getSystemColor(SWT.COLOR_INFO_FOREGROUND)); 211 hoverShell.addPaintListener(new PaintListener() { 212 public void paintControl(PaintEvent pe) { 213 pe.gc.drawString(text, hm, hm); 214 if (!CARBON) { 215 pe.gc.drawPolygon(getPolygon(true)); 216 } 217 } 218 }); 219 hoverShell.addMouseListener(new MouseAdapter() { 220 public void mouseDown(MouseEvent e) { 221 hideHover(); 222 } 223 }); 224 } 225 226 231 int[] getPolygon(boolean border) { 232 Point e = getExtent(); 233 int b = border ? 1 : 0; 234 if (arrowOnLeft) { 235 return new int[] { 0, 0, e.x - b, 0, e.x - b, e.y - b, 236 hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao, 237 e.y - b, 0, e.y - b, 0, 0 }; 238 } 239 return new int[] { 0, 0, e.x - b, 0, e.x - b, e.y - b, 240 e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b, 241 e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0 }; 242 } 243 244 248 void dispose() { 249 if (!hoverShell.isDisposed()) { 250 hoverShell.dispose(); 251 } 252 if (region != null) { 253 region.dispose(); 254 } 255 } 256 257 260 void setVisible(boolean visible) { 261 if (visible) { 262 if (!hoverShell.isVisible()) { 263 hoverShell.setVisible(true); 264 } 265 } else { 266 if (hoverShell.isVisible()) { 267 hoverShell.setVisible(false); 268 } 269 } 270 } 271 272 277 void setText(String t, Control hoverNear, Control targetControl) { 278 if (t == null) { 279 t = EMPTY; 280 } 281 if (!t.equals(text)) { 282 Point oldSize = getExtent(); 283 text = t; 284 hoverShell.redraw(); 285 Point newSize = getExtent(); 286 if (!oldSize.equals(newSize)) { 287 arrowOnLeft = hoverNear.getLocation().x <= targetControl 289 .getLocation().x; 290 setNewShape(); 291 } 292 } 293 294 if (hoverNear != null) { 295 Point extent = getExtent(); 296 int y = -extent.y - hah + 1; 297 int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw 298 / 2; 299 300 hoverShell.setLocation(hoverNear.toDisplay(x, y)); 301 } 302 303 } 304 305 308 boolean isVisible() { 309 return hoverShell.isVisible(); 310 } 311 312 315 Point getExtent() { 316 GC gc = new GC(hoverShell); 317 Point e = gc.textExtent(text); 318 gc.dispose(); 319 e.x += hm * 2; 320 e.y += hm * 2; 321 return e; 322 } 323 324 327 void setNewShape() { 328 Region oldRegion = region; 329 region = new Region(); 330 region.add(getPolygon(false)); 331 hoverShell.setRegion(region); 332 if (oldRegion != null) { 333 oldRegion.dispose(); 334 } 335 336 } 337 } 338 339 354 public DecoratedField(Composite parent, int style, 355 IControlCreator controlCreator) { 356 this.form = createForm(parent); 357 this.control = controlCreator.createControl(form, style); 358 359 addControlListeners(); 360 form.setTabList(new Control[] { control }); 361 362 FormData data = new FormData(); 364 data.left = new FormAttachment(0, 0); 365 data.top = new FormAttachment(0, 0); 366 data.right = new FormAttachment(100, 0); 367 data.bottom = new FormAttachment(100, 0); 368 control.setLayoutData(data); 369 370 } 371 372 400 public void addFieldDecoration(FieldDecoration decoration, int position, 401 boolean showOnFocus) { 402 final Label label; 403 FormData formData; 404 int i = indexForPosition(position); 405 if (decDatas[i] == null) { 406 formData = createFormDataForIndex(i, decoration.getImage()); 407 label = new Label(form, SWT.HORIZONTAL | SWT.VERTICAL | SWT.CENTER); 408 label.addMouseTrackListener(new MouseTrackListener() { 409 public void mouseHover(MouseEvent event) { 410 FieldDecorationData decData = (FieldDecorationData) event.widget 411 .getData(); 412 String desc = decData.decoration.getDescription(); 413 if (desc != null) { 414 showHoverText(desc, label); 415 } 416 } 417 418 public void mouseEnter(MouseEvent event) { 419 } 420 421 public void mouseExit(MouseEvent event) { 422 hideHover(); 423 } 424 }); 425 decDatas[i] = new FieldDecorationData(decoration, label, formData, 426 showOnFocus); 427 } else { 428 label = decDatas[i].label; 429 formData = decDatas[i].data; 430 decDatas[i].decoration = decoration; 431 decDatas[i].showOnFocus = showOnFocus; 432 } 433 label.setImage(decDatas[i].decoration.getImage()); 434 label.setData(decDatas[i]); 435 label.setLayoutData(formData); 436 label.setVisible(!showOnFocus); 437 438 updateControlAttachments(i, decDatas[i]); 441 } 442 443 448 private void updateControlAttachments(int index, FieldDecorationData decData) { 449 FormData formData = (FormData) control.getLayoutData(); 450 int newWidth = widthOf(decData.decoration.getImage()); 451 int opposing; 454 455 switch (index) { 456 case LEFT_TOP: 457 case LEFT_BOTTOM: 458 if (index == LEFT_TOP) { 459 opposing = LEFT_BOTTOM; 460 } else { 461 opposing = LEFT_TOP; 462 } 463 if (decDatas[opposing] == null) { 464 formData.left = new FormAttachment(decData.label); 467 } else if (decDatas[opposing].data.width < newWidth) { 468 formData.left = new FormAttachment(decData.label); 471 decDatas[opposing].data.left.alignment = SWT.CENTER; 473 decDatas[opposing].data.left.control = decData.label; 474 } else { 475 formData = null; 478 decData.data.left.alignment = SWT.CENTER; 481 decData.data.left.control = decDatas[opposing].label; 482 } 483 break; 484 490 case RIGHT_TOP: 491 case RIGHT_BOTTOM: 492 if (index == RIGHT_TOP) { 493 opposing = RIGHT_BOTTOM; 494 } else { 495 opposing = RIGHT_TOP; 496 } 497 if (decDatas[opposing] == null) { 498 formData.right = new FormAttachment(decData.label); 501 } else if (decDatas[opposing].data.width < newWidth) { 502 formData.right = new FormAttachment(decData.label); 505 decDatas[opposing].data.right.alignment = SWT.CENTER; 510 decDatas[opposing].data.right.control = decData.label; 511 } else { 512 formData = null; 515 decData.data.right.alignment = SWT.CENTER; 518 decData.data.right.control = decDatas[opposing].label; 519 } 520 break; 521 default: 522 return; 523 } 524 if (formData != null) { 525 control.setLayoutData(formData); 527 form.layout(); 528 } 529 } 530 531 537 public Control getControl() { 538 return control; 539 } 540 541 549 public Control getLayoutControl() { 550 return form; 551 } 552 553 557 private Composite createForm(Composite parent) { 558 Composite composite = new Composite(parent, SWT.NO_FOCUS); 559 composite.setBackgroundMode(SWT.INHERIT_DEFAULT); 561 composite.setLayout(new FormLayout()); 562 return composite; 563 } 564 565 568 private void addControlListeners() { 569 control.addDisposeListener(new DisposeListener() { 570 public void widgetDisposed(DisposeEvent event) { 571 if (hover != null) { 572 hover.dispose(); 573 } 574 } 575 }); 576 control.addFocusListener(new FocusListener() { 577 public void focusGained(FocusEvent event) { 578 controlFocusGained(); 579 } 580 581 public void focusLost(FocusEvent event) { 582 controlFocusLost(); 583 } 584 585 }); 586 } 587 588 608 private int indexForPosition(int position) { 609 switch (position) { 610 case SWT.LEFT | SWT.BOTTOM: 611 return LEFT_BOTTOM; 612 case SWT.RIGHT | SWT.TOP: 613 return RIGHT_TOP; 614 case SWT.RIGHT | SWT.BOTTOM: 615 return RIGHT_BOTTOM; 616 default: 617 return LEFT_TOP; 618 } 619 } 620 621 631 private FormData createFormDataForIndex(int index, Image image) { 632 Assert.isTrue(index >= 0 && index < DECORATION_SLOTS, 633 "Index out of range"); 635 FormData data = new FormData(); 636 switch (index) { 637 case LEFT_TOP: 638 data.left = new FormAttachment(0, 0); 639 data.top = new FormAttachment(0, 0); 640 break; 641 case LEFT_BOTTOM: 642 data.left = new FormAttachment(0, 0); 643 data.bottom = new FormAttachment(100, 0); 644 break; 645 case RIGHT_TOP: 646 data.right = new FormAttachment(100, 0); 647 data.top = new FormAttachment(0, 0); 648 break; 649 case RIGHT_BOTTOM: 650 data.right = new FormAttachment(100, 0); 651 data.bottom = new FormAttachment(100, 0); 652 break; 653 } 654 data.width = widthOf(image); 655 data.height = SWT.DEFAULT; 656 657 return data; 658 } 659 660 676 public void showHoverText(String text) { 677 showHoverText(text, control); 678 } 679 680 692 public void hideHover() { 693 if (hover != null) { 694 hover.setVisible(false); 695 } 696 } 697 698 702 private void controlFocusGained() { 703 for (int i = 0; i < DECORATION_SLOTS; i++) { 704 if (decDatas[i] != null && decDatas[i].showOnFocus) { 705 setVisible(decDatas[i], true); 706 } 707 } 708 } 709 710 714 private void controlFocusLost() { 715 for (int i = 0; i < DECORATION_SLOTS; i++) { 716 if (decDatas[i] != null && decDatas[i].showOnFocus) { 717 setVisible(decDatas[i], false); 718 } 719 } 720 } 721 722 730 public void showDecoration(FieldDecoration decoration) { 731 FieldDecorationData data = getDecorationData(decoration); 732 if (data == null) { 733 return; 734 } 735 data.visible = true; 737 if (!data.showOnFocus || control.isFocusControl()) { 740 setVisible(data, true); 741 } 742 } 743 744 752 public void hideDecoration(FieldDecoration decoration) { 753 FieldDecorationData data = getDecorationData(decoration); 754 if (data == null) { 755 return; 756 } 757 data.visible = false; 761 setVisible(data, false); 762 } 763 764 773 public void updateDecoration(FieldDecoration decoration) { 774 FieldDecorationData data = getDecorationData(decoration); 775 if (data == null) { 776 return; 777 } 778 if (data.label != null) { 779 data.label.setImage(decoration.getImage()); 780 if (data.label.getVisible() == true && hover != null) { 783 showHoverText(decoration.getDescription(), data.label); 784 } 785 } 786 } 787 788 795 private void setVisible(FieldDecorationData decData, boolean visible) { 796 if (visible && decData.visible) { 799 decData.label.setVisible(true); 800 } else { 801 decData.label.setVisible(false); 802 } 803 } 804 805 808 private FieldDecorationData getDecorationData(FieldDecoration dec) { 809 for (int i = 0; i < DECORATION_SLOTS; i++) { 810 if (decDatas[i] != null && dec == decDatas[i].decoration 811 && decDatas[i].label != null 812 && !decDatas[i].label.isDisposed()) { 813 return decDatas[i]; 814 } 815 } 816 return null; 817 } 818 819 823 private void showHoverText(String text, Control hoverNear) { 824 if (text == null) { 825 hideHover(); 826 return; 827 } 828 829 if (hover == null) { 830 hover = new Hover(hoverNear.getShell()); 831 } 832 hover.setText(text, hoverNear, control); 833 hover.setVisible(true); 834 } 835 836 859 public void setUseMaximumDecorationWidth(boolean useMaximumWidth) { 860 useMaxDecorationWidth = useMaximumWidth; 861 } 862 863 866 private int widthOf(Image image) { 867 if (image == null) { 868 return 0; 869 } 870 return useMaxDecorationWidth ? FieldDecorationRegistry.getDefault() 871 .getMaximumDecorationWidth() : image.getBounds().width; 872 } 873 } 874 | Popular Tags |