comparison dwtx/jface/fieldassist/DecoratedField.d @ 17:f459f9147650

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