comparison org.eclipse.jface/src/org/eclipse/jface/fieldassist/DecoratedField.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2005, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module org.eclipse.jface.fieldassist.DecoratedField;
14
15 import org.eclipse.jface.fieldassist.FieldDecoration;
16 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
17 import org.eclipse.jface.fieldassist.IControlCreator;
18
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.DisposeEvent;
21 import org.eclipse.swt.events.DisposeListener;
22 import org.eclipse.swt.events.FocusEvent;
23 import org.eclipse.swt.events.FocusListener;
24 import org.eclipse.swt.events.MouseAdapter;
25 import org.eclipse.swt.events.MouseEvent;
26 import org.eclipse.swt.events.MouseTrackListener;
27 import org.eclipse.swt.events.PaintEvent;
28 import org.eclipse.swt.events.PaintListener;
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.Region;
33 import org.eclipse.swt.layout.FormAttachment;
34 import org.eclipse.swt.layout.FormData;
35 import org.eclipse.swt.layout.FormLayout;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.swt.widgets.Control;
38 import org.eclipse.swt.widgets.Display;
39 import org.eclipse.swt.widgets.Label;
40 import org.eclipse.swt.widgets.Shell;
41 import org.eclipse.core.runtime.Assert;
42
43 import java.lang.all;
44 import java.util.Set;
45
46 /**
47 * DecoratedField manages image decorations around a control. It allows clients
48 * to specify an image decoration and a position for the decoration relative to
49 * the field. Decorations may be assigned descriptions, which are shown when the
50 * user hovers over the decoration. Clients can decorate any kind of control by
51 * supplying a {@link IControlCreator} to create the control that is decorated.
52 * <p>
53 * Decorations always appear on either horizontal side of the field, never above
54 * or below it. Decorations can be positioned at the top or bottom of either
55 * side. Future implementations may provide additional positioning options for
56 * decorations.
57 * <p>
58 * By default, DecoratedField will consult the {@link FieldDecorationRegistry}
59 * to determine how much space should be reserved for each decoration. This
60 * allows fields with decorations from different sources to align properly on
61 * the same dialog, since the registry tracks the size of all decorations
62 * registered. Therefore, it is recommended, but not required, that clients of
63 * DecoratedField register the decorations used. In cases where alignment
64 * between different fields is not a concern, clients can use
65 * <code>setUseMaximumDecorationWidth(false)</code> and need not register
66 * their decorations.
67 * <p>
68 * This class is not intended to be subclassed.
69 *
70 * @since 3.2
71 * @deprecated As of 3.3, clients should use {@link ControlDecoration} instead.
72 */
73 public class DecoratedField {
74
75 /**
76 * Cached platform flags for dealing with platform-specific issues.
77 */
78 private static bool CARBON(){
79 return "carbon".equals(SWT.getPlatform()); //$NON-NLS-1$
80 }
81
82 /**
83 * Constants describing the array indices used to hold the decorations in
84 * array slots.
85 */
86
87 private static const int LEFT_TOP = 0;
88
89 private static const int LEFT_BOTTOM = 1;
90
91 private static const int RIGHT_TOP = 2;
92
93 private static const int RIGHT_BOTTOM = 3;
94
95 private static const int DECORATION_SLOTS = 4;
96
97 /**
98 * Simple data structure class for specifying the internals for a field
99 * decoration. This class contains data specific to the implementation of
100 * field decorations as labels attached to the field. Clients should use
101 * <code>FieldDecoration</code> for specifying a decoration.
102 */
103 private class FieldDecorationData {
104
105 /* Package */FieldDecoration decoration;
106
107 /* Package */Label label;
108
109 /* Package */FormData data;
110
111 /* Package */bool showOnFocus;
112
113 /* Package */bool visible = true;
114
115 /**
116 * Create a decoration data representing the specified decoration, using
117 * the specified label and form data for its representation.
118 *
119 * @param decoration
120 * the decoration whose data is kept.
121 * @param label
122 * the label used to represent the decoration.
123 * @param formData
124 * the form data used to attach the decoration to its field.
125 * @param showOnFocus
126 * a bool specifying whether the decoration should only be
127 * shown when the field has focus.
128 */
129 this(FieldDecoration decoration, Label label,
130 FormData formData, bool showOnFocus) {
131 this.decoration = decoration;
132 this.label = label;
133 this.data = formData;
134 this.showOnFocus = showOnFocus;
135 }
136 }
137
138 /**
139 * Decorations keyed by position.
140 */
141 private FieldDecorationData[] decDatas;
142
143 /**
144 * The associated control
145 */
146 private Control control;
147
148 /**
149 * The composite with form layout used to manage decorations.
150 */
151 private Composite form;
152
153 /**
154 * The bool that indicates whether the maximum decoration width is used
155 * when allocating space for decorations.
156 */
157 private bool useMaxDecorationWidth = true;
158
159 /**
160 * The hover used for showing description text
161 */
162 private Hover hover;
163
164 /**
165 * The hover used to show a decoration image's description.
166 */
167 class Hover {
168 private static const String EMPTY = ""; //$NON-NLS-1$
169
170 /**
171 * Offset of info hover arrow from the left or right side.
172 */
173 private int hao = 10;
174
175 /**
176 * Width of info hover arrow.
177 */
178 private int haw = 8;
179
180 /**
181 * Height of info hover arrow.
182 */
183 private int hah = 10;
184
185 /**
186 * Margin around info hover text.
187 */
188 private int hm = 2;
189
190 /**
191 * This info hover's shell.
192 */
193 Shell hoverShell;
194
195 /**
196 * The info hover text.
197 */
198 String text = EMPTY;
199
200 /**
201 * The region used to manage the shell shape
202 */
203 Region region;
204
205 /**
206 * Boolean indicating whether the last computed polygon location had an
207 * arrow on left. (true if left, false if right).
208 */
209 bool arrowOnLeft = true;
210
211 /*
212 * Create a hover parented by the specified shell.
213 */
214 this(Shell parent) {
215 final Display display = parent.getDisplay();
216 hoverShell = new Shell(parent, SWT.NO_TRIM | SWT.ON_TOP
217 | SWT.NO_FOCUS | SWT.TOOL);
218 hoverShell.setBackground(display
219 .getSystemColor(SWT.COLOR_INFO_BACKGROUND));
220 hoverShell.setForeground(display
221 .getSystemColor(SWT.COLOR_INFO_FOREGROUND));
222 hoverShell.addPaintListener(new class PaintListener {
223 public void paintControl(PaintEvent pe) {
224 pe.gc.drawString(text, hm, hm);
225 if (!CARBON) {
226 pe.gc.drawPolygon(getPolygon(true));
227 }
228 }
229 });
230 hoverShell.addMouseListener(new class MouseAdapter {
231 public void mouseDown(MouseEvent e) {
232 hideHover();
233 }
234 });
235 }
236
237 /*
238 * Compute a polygon that represents a hover with an arrow pointer. If
239 * border is true, compute the polygon inset by 1-pixel border. Consult
240 * the arrowOnLeft flag to determine which side the arrow is on.
241 */
242 int[] getPolygon(bool border) {
243 Point e = getExtent();
244 int b = border ? 1 : 0;
245 if (arrowOnLeft) {
246 return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
247 hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao,
248 e.y - b, 0, e.y - b, 0, 0 ];
249 }
250 return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
251 e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b,
252 e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0 ];
253 }
254
255 /*
256 * Dispose the hover, it is no longer needed. Dispose any resources
257 * allocated by the hover.
258 */
259 void dispose() {
260 if (!hoverShell.isDisposed()) {
261 hoverShell.dispose();
262 }
263 if (region !is null) {
264 region.dispose();
265 }
266 }
267
268 /*
269 * Set the visibility of the hover.
270 */
271 void setVisible(bool visible) {
272 if (visible) {
273 if (!hoverShell.isVisible()) {
274 hoverShell.setVisible(true);
275 }
276 } else {
277 if (hoverShell.isVisible()) {
278 hoverShell.setVisible(false);
279 }
280 }
281 }
282
283 /*
284 * Set the text of the hover to the specified text. Recompute the size
285 * and location of the hover to hover near the specified control,
286 * pointing the arrow toward the target control.
287 */
288 void setText(String t, Control hoverNear, Control targetControl) {
289 if (t is null) {
290 t = EMPTY;
291 }
292 if (!t.equals(text)) {
293 Point oldSize = getExtent();
294 text = t;
295 hoverShell.redraw();
296 Point newSize = getExtent();
297 if (!oldSize.opEquals(newSize)) {
298 // set a flag that indicates the direction of arrow
299 arrowOnLeft = hoverNear.getLocation().x <= targetControl
300 .getLocation().x;
301 setNewShape();
302 }
303 }
304
305 if (hoverNear !is null) {
306 Point extent = getExtent();
307 int y = -extent.y - hah + 1;
308 int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw
309 / 2;
310
311 hoverShell.setLocation(hoverNear.toDisplay(x, y));
312 }
313
314 }
315
316 /*
317 * Return whether or not the hover (shell) is visible.
318 */
319 bool isVisible() {
320 return hoverShell.isVisible();
321 }
322
323 /*
324 * Compute the extent of the hover for the current text.
325 */
326 Point getExtent() {
327 GC gc = new GC(hoverShell);
328 Point e = gc.textExtent(text);
329 gc.dispose();
330 e.x += hm * 2;
331 e.y += hm * 2;
332 return e;
333 }
334
335 /*
336 * Compute a new shape for the hover shell.
337 */
338 void setNewShape() {
339 Region oldRegion = region;
340 region = new Region();
341 region.add(getPolygon(false));
342 hoverShell.setRegion(region);
343 if (oldRegion !is null) {
344 oldRegion.dispose();
345 }
346
347 }
348 }
349
350 /**
351 * Construct a decorated field which is parented by the specified composite
352 * and has the given style bits. Use the controlCreator to create the
353 * specific kind of control that is decorated inside the field.
354 *
355 * @param parent
356 * the parent of the decorated field.
357 * @param style
358 * the desired style bits for the field.
359 * @param controlCreator
360 * the IControlCreator used to specify the specific kind of
361 * control that is to be decorated.
362 *
363 * @see IControlCreator
364 */
365 public this(Composite parent, int style,
366 IControlCreator controlCreator) {
367 decDatas = new FieldDecorationData[DECORATION_SLOTS];
368 this.form = createForm(parent);
369 this.control = controlCreator.createControl(form, style);
370
371 addControlListeners();
372 form.setTabList([ control ]);
373
374 // Set up the initial layout data.
375 FormData data = new FormData();
376 data.left = new FormAttachment(0, 0);
377 data.top = new FormAttachment(0, 0);
378 data.right = new FormAttachment(100, 0);
379 data.bottom = new FormAttachment(100, 0);
380 control.setLayoutData(data);
381
382 }
383
384 /**
385 * Adds an image decoration to the field.
386 *
387 * @param decoration
388 * A FieldDecoration describing the image and description for the
389 * decoration
390 *
391 * @param position
392 * The SWT constant indicating the position of the decoration
393 * relative to the field's control. The position should include
394 * style bits describing both the vertical and horizontal
395 * orientation. <code>SWT.LEFT</code> and
396 * <code>SWT.RIGHT</code> describe the horizontal placement of
397 * the decoration relative to the field, and the constants
398 * <code>SWT.TOP</code> and <code>SWT.BOTTOM</code> describe
399 * the vertical alignment of the decoration relative to the
400 * field. Decorations always appear on either horizontal side of
401 * the field, never above or below it. For example, a decoration
402 * appearing on the left side of the field, at the top, is
403 * specified as SWT.LEFT | SWT.TOP. If an image decoration
404 * already exists in the specified position, it will be replaced
405 * by the one specified.
406 * @param showOnFocus
407 * <code>true</code> if the decoration should only be shown
408 * when the associated control has focus, <code>false</code> if
409 * it should always be shown.
410 *
411 */
412 public void addFieldDecoration(FieldDecoration decoration, int position,
413 bool showOnFocus) {
414 Label label;
415 FormData formData;
416 int i = indexForPosition(position);
417 if (decDatas[i] is null) {
418 formData = createFormDataForIndex(i, decoration.getImage());
419 label = new Label(form, SWT.HORIZONTAL | SWT.VERTICAL | SWT.CENTER);
420 label.addMouseTrackListener(new class(label) MouseTrackListener {
421 Label label_;
422 this(Label a){
423 label_=a;
424 }
425 public void mouseHover(MouseEvent event) {
426 FieldDecorationData decData = cast(FieldDecorationData) event.widget
427 .getData();
428 String desc = decData.decoration.getDescription();
429 if (desc !is null) {
430 showHoverText(desc, label_);
431 }
432 }
433
434 public void mouseEnter(MouseEvent event) {
435 }
436
437 public void mouseExit(MouseEvent event) {
438 hideHover();
439 }
440 });
441 decDatas[i] = new FieldDecorationData(decoration, label, formData,
442 showOnFocus);
443 } else {
444 label = decDatas[i].label;
445 formData = decDatas[i].data;
446 decDatas[i].decoration = decoration;
447 decDatas[i].showOnFocus = showOnFocus;
448 }
449 label.setImage(decDatas[i].decoration.getImage());
450 label.setData(decDatas[i]);
451 label.setLayoutData(formData);
452 label.setVisible(!showOnFocus);
453
454 // Since sizes may have changed or there could be a new position
455 // defined, we need to update layout data on the control.
456 updateControlAttachments(i, decDatas[i]);
457 }
458
459 /*
460 * A decoration at the specified index has been added. Update the control's
461 * attachments if it has not previously been attached on that side or if it
462 * was attached to a decoration with a lesser width.
463 */
464 private void updateControlAttachments(int index, FieldDecorationData decData) {
465 FormData formData = cast(FormData) control.getLayoutData();
466 int newWidth = widthOf(decData.decoration.getImage());
467 // opposing represents the location of the decoration above or below
468 // the one in question.
469 int opposing;
470
471 switch (index) {
472 case LEFT_TOP:
473 case LEFT_BOTTOM:
474 if (index is LEFT_TOP) {
475 opposing = LEFT_BOTTOM;
476 } else {
477 opposing = LEFT_TOP;
478 }
479 if (decDatas[opposing] is null) {
480 // No decorator on the opposing side.
481 // Attach the control to this decorator
482 formData.left = new FormAttachment(decData.label);
483 } else if (decDatas[opposing].data.width < newWidth) {
484 // Decorator on opposing side is the smaller one. Attach
485 // control to the new one.
486 formData.left = new FormAttachment(decData.label);
487 // Center align the smaller one relative to the larger one.
488 decDatas[opposing].data.left.alignment = SWT.CENTER;
489 decDatas[opposing].data.left.control = decData.label;
490 } else {
491 // The new decorator is the smaller one. Keep the
492 // control attached to the opposing one.
493 formData = null;
494 // Horizontally center the smaller one relative to the larger
495 // one.
496 decData.data.left.alignment = SWT.CENTER;
497 decData.data.left.control = decDatas[opposing].label;
498 }
499 break;
500 /*
501 * The only real difference in right side cases is that we are attaching
502 * the right side of the control to the wider decoration rather than the
503 * left side of the control. Other concerns (horizontally aligning the
504 * smaller decoration relative to the larger one) are the same.
505 */
506 case RIGHT_TOP:
507 case RIGHT_BOTTOM:
508 if (index is RIGHT_TOP) {
509 opposing = RIGHT_BOTTOM;
510 } else {
511 opposing = RIGHT_TOP;
512 }
513 if (decDatas[opposing] is null) {
514 // No decorator on the opposing side.
515 // Attach the control to this decorator.
516 formData.right = new FormAttachment(decData.label);
517 } else if (decDatas[opposing].data.width < newWidth) {
518 // Decorator on opposing side is the smaller one. Attach
519 // control to the new one.
520 formData.right = new FormAttachment(decData.label);
521 // Center align the smaller one to the larger one.
522 // Note that this could be done using the left or right
523 // attachment, we use the right since it is already
524 // created for all right-side decorations.
525 decDatas[opposing].data.right.alignment = SWT.CENTER;
526 decDatas[opposing].data.right.control = decData.label;
527 } else {
528 // The new decorator is the smaller one. Keep the
529 // control attached to the opposing one.
530 formData = null;
531 // Horizontally center align the smaller one to the
532 // larger one.
533 decData.data.right.alignment = SWT.CENTER;
534 decData.data.right.control = decDatas[opposing].label;
535 }
536 break;
537 default:
538 return;
539 }
540 if (formData !is null) {
541 // Form data was updated.
542 control.setLayoutData(formData);
543 form.layout();
544 }
545 }
546
547 /**
548 * Get the control that is decorated by the receiver.
549 *
550 * @return the Control decorated by the receiver, or <code>null</code> if
551 * none has been created yet.
552 */
553 public Control getControl() {
554 return control;
555 }
556
557 /**
558 * Get the control that represents the decorated field. This composite
559 * should be used to lay out the field within its parent.
560 *
561 * @return the Control that should be layed out in the field's parent's
562 * layout. This is typically not the control itself, since
563 * additional controls are used to represent the decorations.
564 */
565 public Control getLayoutControl() {
566 return form;
567 }
568
569 /**
570 * Create the parent composite and a form layout that will be used to manage
571 * decorations.
572 */
573 private Composite createForm(Composite parent) {
574 Composite composite = new Composite(parent, SWT.NO_FOCUS);
575 // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=126553
576 composite.setBackgroundMode(SWT.INHERIT_DEFAULT);
577 composite.setLayout(new FormLayout());
578 return composite;
579 }
580
581 /**
582 * Add any listeners needed on the target control.
583 */
584 private void addControlListeners() {
585 control.addDisposeListener(new class DisposeListener {
586 public void widgetDisposed(DisposeEvent event) {
587 if (hover !is null) {
588 hover.dispose();
589 }
590 }
591 });
592 control.addFocusListener(new class FocusListener {
593 public void focusGained(FocusEvent event) {
594 controlFocusGained();
595 }
596
597 public void focusLost(FocusEvent event) {
598 controlFocusLost();
599 }
600
601 });
602 }
603
604 /*
605 * Return the index in the array of decoration datas that represents the
606 * specified SWT position.
607 *
608 * @param position The SWT constant indicating the position of the
609 * decoration relative to the field's control. The position should include
610 * style bits describing both the vertical and horizontal orientation.
611 * <code>SWT.LEFT</code> and <code>SWT.RIGHT</code> describe the
612 * horizontal placement of the decoration relative to the field, and the
613 * constants <code>SWT.TOP</code> and <code>SWT.BOTTOM</code> describe
614 * the vertical alignment of the decoration relative to the field.
615 * Decorations always appear on either horizontal side of the field, never
616 * above or below it. For example, a decoration appearing on the left side
617 * of the field, at the top, is specified as SWT.LEFT | SWT.TOP.
618 *
619 * @return index the index in the array of decorations that represents the
620 * specified SWT position. If the position is not an expected position, the
621 * index representing the top left position will be returned.
622 *
623 */
624 private int indexForPosition(int position) {
625 switch (position) {
626 case SWT.LEFT | SWT.BOTTOM:
627 return LEFT_BOTTOM;
628 case SWT.RIGHT | SWT.TOP:
629 return RIGHT_TOP;
630 case SWT.RIGHT | SWT.BOTTOM:
631 return RIGHT_BOTTOM;
632 default:
633 return LEFT_TOP;
634 }
635 }
636
637 /*
638 * Create a form data that will place the decoration at the specified
639 * position.
640 *
641 * @param index the index in the decDatas describing the position of the
642 * decoration.
643 *
644 * @param image the image shown in the decoration.
645 *
646 */
647 private FormData createFormDataForIndex(int index, Image image) {
648 Assert.isTrue(index >= 0 && index < DECORATION_SLOTS,
649 "Index out of range"); //$NON-NLS-1$
650
651 FormData data = new FormData();
652 switch (index) {
653 case LEFT_TOP:
654 data.left = new FormAttachment(0, 0);
655 data.top = new FormAttachment(0, 0);
656 break;
657 case LEFT_BOTTOM:
658 data.left = new FormAttachment(0, 0);
659 data.bottom = new FormAttachment(100, 0);
660 break;
661 case RIGHT_TOP:
662 data.right = new FormAttachment(100, 0);
663 data.top = new FormAttachment(0, 0);
664 break;
665 case RIGHT_BOTTOM:
666 data.right = new FormAttachment(100, 0);
667 data.bottom = new FormAttachment(100, 0);
668 break;
669 default:
670 }
671 data.width = widthOf(image);
672 data.height = SWT.DEFAULT;
673
674 return data;
675 }
676
677 /**
678 * Show the specified text using the same hover dialog as is used to show
679 * decorator descriptions. Normally, a decoration's description text will be
680 * shown in an info hover over the field's control whenever the mouse hovers
681 * over the decoration. This method can be used to show a decoration's
682 * description text at other times (such as when the control receives
683 * focus), or to show other text associated with the field.
684 *
685 * <p>
686 * If there is currently a hover visible, the hover's text will be replaced
687 * with the specified text.
688 *
689 * @param text
690 * the text to be shown in the info hover, or <code>null</code>
691 * if no text should be shown.
692 */
693 public void showHoverText(String text) {
694 showHoverText(text, control);
695 }
696
697 /**
698 * Hide any hover popups that are currently showing on the control.
699 * Normally, a decoration's description text will be shown in an info hover
700 * over the field's control as long as the mouse hovers over the decoration,
701 * and will be hidden when the mouse exits the control. This method can be
702 * used to hide a hover that was shown using <code>showHoverText</code>,
703 * or to programatically hide the current decoration hover.
704 *
705 * <p>
706 * This message has no effect if there is no current hover.
707 *
708 */
709 public void hideHover() {
710 if (hover !is null) {
711 hover.setVisible(false);
712 }
713 }
714
715 /*
716 * The target control gained focus. Any decorations that should show only
717 * when they have the focus should be shown here.
718 */
719 private void controlFocusGained() {
720 for (int i = 0; i < DECORATION_SLOTS; i++) {
721 if (decDatas[i] !is null && decDatas[i].showOnFocus) {
722 setVisible(decDatas[i], true);
723 }
724 }
725 }
726
727 /*
728 * The target control lost focus. Any decorations that should show only when
729 * they have the focus should be hidden here.
730 */
731 private void controlFocusLost() {
732 for (int i = 0; i < DECORATION_SLOTS; i++) {
733 if (decDatas[i] !is null && decDatas[i].showOnFocus) {
734 setVisible(decDatas[i], false);
735 }
736 }
737 }
738
739 /**
740 * Show the specified decoration. This message has no effect if the
741 * decoration is already showing, or was not already added to the field
742 * using <code>addFieldDecoration</code>.
743 *
744 * @param decoration
745 * the decoration to be shown.
746 */
747 public void showDecoration(FieldDecoration decoration) {
748 FieldDecorationData data = getDecorationData(decoration);
749 if (data is null) {
750 return;
751 }
752 // record the fact that client would like it to be visible
753 data.visible = true;
754 // even if it is supposed to be shown, if the field does not have focus,
755 // do not show it (yet)
756 if (!data.showOnFocus || control.isFocusControl()) {
757 setVisible(data, true);
758 }
759 }
760
761 /**
762 * Hide the specified decoration. This message has no effect if the
763 * decoration is already hidden, or was not already added to the field using
764 * <code>addFieldDecoration</code>.
765 *
766 * @param decoration
767 * the decoration to be hidden.
768 */
769 public void hideDecoration(FieldDecoration decoration) {
770 FieldDecorationData data = getDecorationData(decoration);
771 if (data is null) {
772 return;
773 }
774 // Store the desired visibility in the decData. We remember the
775 // client's instructions so that changes in visibility caused by
776 // field focus changes won't violate the client's visibility setting.
777 data.visible = false;
778 setVisible(data, false);
779 }
780
781 /**
782 * Update the specified decoration. This message should be used if the image
783 * or description in the decoration have changed. This message has no
784 * immediate effect if the decoration is not visible, and no effect at all
785 * if the decoration was not previously added to the field.
786 *
787 * @param decoration
788 * the decoration to be hidden.
789 */
790 public void updateDecoration(FieldDecoration decoration) {
791 FieldDecorationData data = getDecorationData(decoration);
792 if (data is null) {
793 return;
794 }
795 if (data.label !is null) {
796 data.label.setImage(decoration.getImage());
797 // If the decoration is being shown, and a hover is active,
798 // update the hover text to display the new description.
799 if (data.label.getVisible() is true && hover !is null) {
800 showHoverText(decoration.getDescription(), data.label);
801 }
802 }
803 }
804
805 /*
806 * Set the visibility of the specified decoration data. This method does not
807 * change the visibility value stored in the decData, but instead consults
808 * it to determine how the visibility should be changed. This method is
809 * called any time visibility of a decoration might change, whether by
810 * client API or focus changes.
811 */
812 private void setVisible(FieldDecorationData decData, bool visible) {
813 // Check the decData visibility flag, since it contains the client's
814 // instructions for visibility.
815 if (visible && decData.visible) {
816 decData.label.setVisible(true);
817 } else {
818 decData.label.setVisible(false);
819 }
820 }
821
822 /*
823 * Get the FieldDecorationData that corresponds to the given decoration.
824 */
825 private FieldDecorationData getDecorationData(FieldDecoration dec) {
826 for (int i = 0; i < DECORATION_SLOTS; i++) {
827 if (decDatas[i] !is null && dec is decDatas[i].decoration
828 && decDatas[i].label !is null
829 && !decDatas[i].label.isDisposed()) {
830 return decDatas[i];
831 }
832 }
833 return null;
834 }
835
836 /*
837 * Show the specified text in the hover, positioning the hover near the
838 * specified control.
839 */
840 private void showHoverText(String text, Control hoverNear) {
841 if (text is null) {
842 hideHover();
843 return;
844 }
845
846 if (hover is null) {
847 hover = new Hover(hoverNear.getShell());
848 }
849 hover.setText(text, hoverNear, control);
850 hover.setVisible(true);
851 }
852
853 /**
854 * Set a bool that indicates whether the receiver should use the
855 * decoration registry's maximum decoration width when allocating space for
856 * decorations. The default value is <code>true</code>. Using the maximum
857 * decoration width is useful so that decorated fields on the same dialog
858 * that have different decoration widths will all align. This also allows
859 * client dialogs to align non-decorated fields with decorated fields by
860 * consulting the maximum decoration width.
861 * </p>
862 * <p>
863 * Clients may wish to set this value to <code>false</code> in cases where
864 * space usage is more important than alignment of fields. This value must
865 * be set before the decorations are added in order to ensure proper
866 * alignment.
867 * </p>
868 *
869 * @param useMaximumWidth
870 * <code>true</code> if the maximum decoration width should be
871 * used as the size for all decorations, <code>false</code> if
872 * only the decoration size should be used.
873 *
874 * @see FieldDecorationRegistry#getMaximumDecorationWidth()
875 */
876 public void setUseMaximumDecorationWidth(bool useMaximumWidth) {
877 useMaxDecorationWidth = useMaximumWidth;
878 }
879
880 /*
881 * Return the width appropriate for the specified decoration image.
882 */
883 private int widthOf(Image image) {
884 if (image is null) {
885 return 0;
886 }
887 return useMaxDecorationWidth ? FieldDecorationRegistry.getDefault()
888 .getMaximumDecorationWidth() : image.getBounds().width;
889 }
890 }