29
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2006, 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.ControlDecoration;
|
|
14
|
|
15
|
|
16 import dwt.DWT;
|
|
17 import dwt.events.DisposeEvent;
|
|
18 import dwt.events.DisposeListener;
|
|
19 import dwt.events.FocusEvent;
|
|
20 import dwt.events.FocusListener;
|
|
21 import dwt.events.MenuDetectEvent;
|
|
22 import dwt.events.MenuDetectListener;
|
|
23 import dwt.events.MouseAdapter;
|
|
24 import dwt.events.MouseEvent;
|
|
25 import dwt.events.MouseMoveListener;
|
|
26 import dwt.events.MouseTrackListener;
|
|
27 import dwt.events.PaintEvent;
|
|
28 import dwt.events.PaintListener;
|
|
29 import dwt.events.SelectionEvent;
|
|
30 import dwt.events.SelectionListener;
|
|
31 import dwt.graphics.GC;
|
|
32 import dwt.graphics.Image;
|
|
33 import dwt.graphics.Point;
|
|
34 import dwt.graphics.Rectangle;
|
|
35 import dwt.graphics.Region;
|
|
36 import dwt.widgets.Composite;
|
|
37 import dwt.widgets.Control;
|
|
38 import dwt.widgets.Display;
|
|
39 import dwt.widgets.Event;
|
|
40 import dwt.widgets.Listener;
|
|
41 import dwt.widgets.Shell;
|
|
42 import dwt.widgets.Widget;
|
|
43 import dwtx.core.runtime.ListenerList;
|
|
44
|
|
45 import dwt.dwthelper.utils;
|
|
46 import tango.io.Stdout;
|
|
47
|
|
48 /**
|
|
49 * ControlDecoration renders an image decoration near a control. It allows
|
|
50 * clients to specify an image and a position for the image relative to the
|
|
51 * control. A ControlDecoration may be assigned description text, which can
|
|
52 * optionally be shown when the user hovers over the image. Clients can decorate
|
|
53 * any kind of control.
|
|
54 * <p>
|
|
55 * Decoration images always appear on the left or right side of the field, never
|
|
56 * above or below it. Decorations can be positioned at the top, center, or
|
|
57 * bottom of either side of the control. Future implementations may provide
|
|
58 * additional positioning options for decorations.
|
|
59 * <p>
|
|
60 * ControlDecoration renders the image adjacent to the specified (already
|
|
61 * created) control, with no guarantee that it won't be clipped or otherwise
|
|
62 * obscured or overlapped by adjacent controls, including another
|
|
63 * ControlDecoration placed in the same location. Clients should ensure that
|
|
64 * there is adequate space adjacent to the control to show the decoration
|
|
65 * properly.
|
|
66 * <p>
|
|
67 * Clients using ControlDecoration should typically ensure that enough margin
|
|
68 * space is reserved for a decoration by altering the layout data margins,
|
|
69 * although this is not assumed or required by the ControlDecoration
|
|
70 * implementation.
|
|
71 * <p>
|
|
72 * This class is intended to be instantiated and used by clients. It is not
|
|
73 * intended to be subclassed by clients.
|
|
74 *
|
|
75 * @since 3.3
|
|
76 *
|
|
77 * @see FieldDecoration
|
|
78 * @see FieldDecorationRegistry
|
|
79 */
|
|
80 public class ControlDecoration {
|
|
81 /**
|
|
82 * Debug flag for tracing
|
|
83 */
|
|
84 private static bool DEBUG = false;
|
|
85
|
|
86 /**
|
|
87 * Cached platform flags for dealing with platform-specific issues.
|
|
88 */
|
34
|
89 private static bool CARBON(){
|
|
90 return "carbon".equals(DWT.getPlatform()); //$NON-NLS-1$
|
|
91 }
|
29
|
92
|
|
93 /**
|
|
94 * The associated control
|
|
95 */
|
|
96 private Control control;
|
|
97
|
|
98 /**
|
|
99 * The composite on which to render the decoration and hook mouse events, or
|
|
100 * null if we are hooking all parent composites.
|
|
101 */
|
|
102 private Composite composite;
|
|
103
|
|
104 /**
|
|
105 * The associated image.
|
|
106 */
|
|
107 private Image image;
|
|
108
|
|
109 /**
|
|
110 * The associated description text.
|
|
111 */
|
|
112 private String descriptionText;
|
|
113 /**
|
|
114 * The position of the decoration.
|
|
115 */
|
|
116 private int position;
|
|
117
|
|
118 /**
|
|
119 * The decoration's visibility flag
|
|
120 */
|
|
121 private bool visible = true;
|
|
122
|
|
123 /**
|
|
124 * bool indicating whether the decoration should only be shown when the
|
|
125 * control has focus
|
|
126 */
|
|
127 private bool showOnlyOnFocus = false;
|
|
128
|
|
129 /**
|
|
130 * bool indicating whether the decoration should show its description
|
|
131 * text in a hover when the user hovers over the decoration.
|
|
132 */
|
|
133 private bool showHover = true;
|
|
134
|
|
135 /**
|
|
136 * Margin width used between the decorator and the control.
|
|
137 */
|
|
138 private int marginWidth = 0;
|
|
139
|
|
140 /**
|
|
141 * Registered selection listeners.
|
|
142 */
|
|
143 private ListenerList selectionListeners;
|
|
144
|
|
145 /**
|
|
146 * Registered menu detect listeners.
|
|
147 */
|
|
148 private ListenerList menuDetectListeners;
|
|
149
|
|
150 /**
|
|
151 * The focus listener
|
|
152 */
|
|
153 private FocusListener focusListener;
|
|
154
|
|
155 /**
|
|
156 * The dispose listener
|
|
157 */
|
|
158 private DisposeListener disposeListener;
|
|
159
|
|
160 /**
|
|
161 * The paint listener installed for drawing the decoration
|
|
162 */
|
|
163 private PaintListener paintListener;
|
|
164
|
|
165 /**
|
|
166 * The mouse listener installed for tracking the hover
|
|
167 */
|
|
168 private MouseTrackListener mouseTrackListener;
|
|
169
|
|
170 /**
|
|
171 * The mouse move listener installed for tracking the hover
|
|
172 */
|
|
173 private MouseMoveListener mouseMoveListener;
|
|
174
|
|
175 /**
|
|
176 * The untyped listener installed for notifying external listeners
|
|
177 */
|
|
178 private Listener compositeListener;
|
|
179
|
|
180 /**
|
|
181 * Control that we last installed a move listener on. We only want one at a
|
|
182 * time.
|
|
183 */
|
|
184 private Control moveListeningTarget = null;
|
|
185
|
|
186 /**
|
|
187 * Debug counter used to match add and remove listeners
|
|
188 */
|
|
189 private int listenerInstalls = 0;
|
|
190
|
|
191 /**
|
|
192 * The current rectangle used for tracking mouse moves
|
|
193 */
|
|
194 private Rectangle decorationRectangle;
|
|
195
|
|
196 /**
|
|
197 * An internal flag tracking whether we have focus. We use this rather than
|
|
198 * isFocusControl() so that we can set the flag as soon as we get the focus
|
|
199 * callback, rather than having to do an asyncExec in the middle of a focus
|
|
200 * callback to ensure that isFocusControl() represents the outcome of the
|
|
201 * event.
|
|
202 */
|
|
203 private bool hasFocus = false;
|
|
204
|
|
205 /**
|
|
206 * The hover used for showing description text
|
|
207 */
|
|
208 private Hover hover;
|
|
209
|
|
210 /**
|
|
211 * The hover used to show a decoration image's description.
|
|
212 */
|
|
213 class Hover {
|
|
214 private static const String EMPTY = ""; //$NON-NLS-1$
|
|
215
|
|
216 /**
|
|
217 * Offset of info hover arrow from the left or right side.
|
|
218 */
|
|
219 private int hao = 10;
|
|
220
|
|
221 /**
|
|
222 * Width of info hover arrow.
|
|
223 */
|
|
224 private int haw = 8;
|
|
225
|
|
226 /**
|
|
227 * Height of info hover arrow.
|
|
228 */
|
|
229 private int hah = 10;
|
|
230
|
|
231 /**
|
|
232 * Margin around info hover text.
|
|
233 */
|
|
234 private int hm = 2;
|
|
235
|
|
236 /**
|
|
237 * This info hover's shell.
|
|
238 */
|
|
239 Shell hoverShell;
|
|
240
|
|
241 /**
|
|
242 * The info hover text.
|
|
243 */
|
|
244 String text = EMPTY;
|
|
245
|
|
246 /**
|
|
247 * The region used to manage the shell shape
|
|
248 */
|
|
249 Region region;
|
|
250
|
|
251 /**
|
|
252 * bool indicating whether the last computed polygon location had an
|
|
253 * arrow on left. (true if left, false if right).
|
|
254 */
|
|
255 bool arrowOnLeft = true;
|
|
256
|
|
257 /*
|
|
258 * Create a hover parented by the specified shell.
|
|
259 */
|
|
260 this(Shell parent) {
|
|
261 Display display = parent.getDisplay();
|
|
262 hoverShell = new Shell(parent, DWT.NO_TRIM | DWT.ON_TOP
|
|
263 | DWT.NO_FOCUS);
|
|
264 hoverShell.setBackground(display
|
|
265 .getSystemColor(DWT.COLOR_INFO_BACKGROUND));
|
|
266 hoverShell.setForeground(display
|
|
267 .getSystemColor(DWT.COLOR_INFO_FOREGROUND));
|
|
268 hoverShell.addPaintListener(new class PaintListener {
|
|
269 public void paintControl(PaintEvent pe) {
|
|
270 pe.gc.drawText(text, hm, hm);
|
|
271 if (!CARBON) {
|
|
272 pe.gc.drawPolygon(getPolygon(true));
|
|
273 }
|
|
274 }
|
|
275 });
|
|
276 hoverShell.addMouseListener(new class MouseAdapter {
|
|
277 public void mouseDown(MouseEvent e) {
|
|
278 hideHover();
|
|
279 }
|
|
280 });
|
|
281 }
|
|
282
|
|
283 /*
|
|
284 * Compute a polygon that represents a hover with an arrow pointer. If
|
|
285 * border is true, compute the polygon inset by 1-pixel border. Consult
|
|
286 * the arrowOnLeft flag to determine which side the arrow is on.
|
|
287 */
|
|
288 int[] getPolygon(bool border) {
|
|
289 Point e = getExtent();
|
|
290 int b = border ? 1 : 0;
|
|
291 if (arrowOnLeft) {
|
|
292 return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
|
|
293 hao + haw, e.y - b, hao + haw / 2, e.y + hah - b, hao,
|
|
294 e.y - b, 0, e.y - b, 0, 0 ];
|
|
295 }
|
|
296 return [ 0, 0, e.x - b, 0, e.x - b, e.y - b,
|
|
297 e.x - hao - b, e.y - b, e.x - hao - haw / 2, e.y + hah - b,
|
|
298 e.x - hao - haw, e.y - b, 0, e.y - b, 0, 0 ];
|
|
299 }
|
|
300
|
|
301 /*
|
|
302 * Dispose the hover, it is no longer needed. Dispose any resources
|
|
303 * allocated by the hover.
|
|
304 */
|
|
305 void dispose() {
|
|
306 if (!hoverShell.isDisposed()) {
|
|
307 hoverShell.dispose();
|
|
308 }
|
|
309 if (region !is null) {
|
|
310 region.dispose();
|
|
311 }
|
|
312 }
|
|
313
|
|
314 /*
|
|
315 * Set the visibility of the hover.
|
|
316 */
|
|
317 void setVisible(bool visible) {
|
|
318 if (visible) {
|
|
319 if (!hoverShell.isVisible()) {
|
|
320 hoverShell.setVisible(true);
|
|
321 }
|
|
322 } else {
|
|
323 if (hoverShell.isVisible()) {
|
|
324 hoverShell.setVisible(false);
|
|
325 }
|
|
326 }
|
|
327 }
|
|
328
|
|
329 /*
|
|
330 * Set the text of the hover to the specified text. Recompute the size
|
|
331 * and location of the hover to hover near the decoration rectangle,
|
|
332 * pointing the arrow toward the target control.
|
|
333 */
|
|
334 void setText(String t, Rectangle decorationRectangle,
|
|
335 Control targetControl) {
|
|
336 if (t is null) {
|
|
337 t = EMPTY;
|
|
338 }
|
|
339 if (!t.equals(text)) {
|
|
340 Point oldSize = getExtent();
|
|
341 text = t;
|
|
342 hoverShell.redraw();
|
|
343 Point newSize = getExtent();
|
|
344 if (!oldSize.opEquals(newSize)) {
|
|
345 // set a flag that indicates the direction of arrow
|
|
346 arrowOnLeft = decorationRectangle.x <= targetControl
|
|
347 .getLocation().x;
|
|
348 setNewShape();
|
|
349 }
|
|
350 }
|
|
351
|
|
352 Point extent = getExtent();
|
|
353 int y = -extent.y - hah + 1;
|
|
354 int x = arrowOnLeft ? -hao + haw / 2 : -extent.x + hao + haw / 2;
|
|
355
|
|
356 hoverShell.setLocation(control.getParent().toDisplay(
|
|
357 decorationRectangle.x + x, decorationRectangle.y + y));
|
|
358 }
|
|
359
|
|
360 /*
|
|
361 * Return whether or not the hover (shell) is visible.
|
|
362 */
|
|
363 bool isVisible() {
|
|
364 return hoverShell.isVisible();
|
|
365 }
|
|
366
|
|
367 /*
|
|
368 * Compute the extent of the hover for the current text.
|
|
369 */
|
|
370 Point getExtent() {
|
|
371 GC gc = new GC(hoverShell);
|
|
372 Point e = gc.textExtent(text);
|
|
373 gc.dispose();
|
|
374 e.x += hm * 2;
|
|
375 e.y += hm * 2;
|
|
376 return e;
|
|
377 }
|
|
378
|
|
379 /*
|
|
380 * Compute a new shape for the hover shell.
|
|
381 */
|
|
382 void setNewShape() {
|
|
383 Region oldRegion = region;
|
|
384 region = new Region();
|
|
385 region.add(getPolygon(false));
|
|
386 hoverShell.setRegion(region);
|
|
387 if (oldRegion !is null) {
|
|
388 oldRegion.dispose();
|
|
389 }
|
|
390
|
|
391 }
|
|
392 }
|
|
393
|
|
394 /**
|
|
395 * Construct a ControlDecoration for decorating the specified control at the
|
|
396 * specified position relative to the control. Render the decoration on top
|
|
397 * of any Control that happens to appear at the specified location.
|
|
398 * <p>
|
|
399 * DWT constants are used to specify the position of the decoration relative
|
|
400 * to the control. The position should include style bits describing both
|
|
401 * the vertical and horizontal orientation. <code>DWT.LEFT</code> and
|
|
402 * <code>DWT.RIGHT</code> describe the horizontal placement of the
|
|
403 * decoration relative to the control, and the constants
|
|
404 * <code>DWT.TOP</code>, <code>DWT.CENTER</code>, and
|
|
405 * <code>DWT.BOTTOM</code> describe the vertical alignment of the
|
|
406 * decoration relative to the control. Decorations always appear on either
|
|
407 * the left or right side of the control, never above or below it. For
|
|
408 * example, a decoration appearing on the left side of the field, at the
|
|
409 * top, is specified as DWT.LEFT | DWT.TOP. If no position style bits are
|
|
410 * specified, the control decoration will be positioned to the left and
|
|
411 * center of the control (<code>DWT.LEFT | DWT.CENTER</code>).
|
|
412 * </p>
|
|
413 *
|
|
414 * @param control
|
|
415 * the control to be decorated
|
|
416 * @param position
|
|
417 * bit-wise or of position constants (<code>DWT.TOP</code>,
|
|
418 * <code>DWT.BOTTOM</code>, <code>DWT.LEFT</code>,
|
|
419 * <code>DWT.RIGHT</code>, and <code>DWT.CENTER</code>).
|
|
420 */
|
|
421 public this(Control control, int position) {
|
|
422 this(control, position, null);
|
|
423
|
|
424 }
|
|
425
|
|
426 /**
|
|
427 * Construct a ControlDecoration for decorating the specified control at the
|
|
428 * specified position relative to the control. Render the decoration only on
|
|
429 * the specified Composite or its children. The decoration will be clipped
|
|
430 * if it does not appear within the visible bounds of the composite or its
|
|
431 * child composites.
|
|
432 * <p>
|
|
433 * DWT constants are used to specify the position of the decoration relative
|
|
434 * to the control. The position should include style bits describing both
|
|
435 * the vertical and horizontal orientation. <code>DWT.LEFT</code> and
|
|
436 * <code>DWT.RIGHT</code> describe the horizontal placement of the
|
|
437 * decoration relative to the control, and the constants
|
|
438 * <code>DWT.TOP</code>, <code>DWT.CENTER</code>, and
|
|
439 * <code>DWT.BOTTOM</code> describe the vertical alignment of the
|
|
440 * decoration relative to the control. Decorations always appear on either
|
|
441 * the left or right side of the control, never above or below it. For
|
|
442 * example, a decoration appearing on the left side of the field, at the
|
|
443 * top, is specified as DWT.LEFT | DWT.TOP. If no position style bits are
|
|
444 * specified, the control decoration will be positioned to the left and
|
|
445 * center of the control (<code>DWT.LEFT | DWT.CENTER</code>).
|
|
446 * </p>
|
|
447 *
|
|
448 * @param control
|
|
449 * the control to be decorated
|
|
450 * @param position
|
|
451 * bit-wise or of position constants (<code>DWT.TOP</code>,
|
|
452 * <code>DWT.BOTTOM</code>, <code>DWT.LEFT</code>,
|
|
453 * <code>DWT.RIGHT</code>, and <code>DWT.CENTER</code>).
|
|
454 * @param composite
|
|
455 * The DWT composite within which the decoration should be
|
|
456 * rendered. The decoration will be clipped to this composite,
|
|
457 * but it may be rendered on a child of the composite. The
|
|
458 * decoration will not be visible if the specified composite or
|
|
459 * its child composites are not visible in the space relative to
|
|
460 * the control, where the decoration is to be rendered. If this
|
|
461 * value is <code>null</code>, then the decoration will be
|
|
462 * rendered on whichever composite (or composites) are located in
|
|
463 * the specified position.
|
|
464 */
|
|
465 public this(Control control, int position, Composite composite) {
|
|
466 selectionListeners = new ListenerList();
|
|
467 menuDetectListeners = new ListenerList();
|
|
468 this.position = position;
|
|
469 this.control = control;
|
|
470 this.composite = composite;
|
|
471
|
|
472 addControlListeners();
|
|
473
|
|
474 }
|
|
475
|
|
476 /**
|
|
477 * Adds the listener to the collection of listeners who will be notified
|
|
478 * when the platform-specific context menu trigger has occurred, by sending
|
|
479 * it one of the messages defined in the <code>MenuDetectListener</code>
|
|
480 * interface.
|
|
481 * <p>
|
|
482 * The <code>widget</code> field in the SelectionEvent will contain the
|
|
483 * Composite on which the decoration is rendered that received the click.
|
|
484 * The <code>x</code> and <code>y</code> fields will be in coordinates
|
|
485 * relative to the display. The <code>data</code> field will contain the
|
|
486 * decoration that received the event.
|
|
487 * </p>
|
|
488 *
|
|
489 * @param listener
|
|
490 * the listener which should be notified
|
|
491 *
|
|
492 * @see dwt.events.MenuDetectListener
|
|
493 * @see dwt.events.MenuDetectEvent
|
|
494 * @see #removeMenuDetectListener
|
|
495 */
|
|
496 public void addMenuDetectListener(MenuDetectListener listener) {
|
|
497 menuDetectListeners.add(cast(Object)listener);
|
|
498 }
|
|
499
|
|
500 /**
|
|
501 * Removes the listener from the collection of listeners who will be
|
|
502 * notified when the platform-specific context menu trigger has occurred.
|
|
503 *
|
|
504 * @param listener
|
|
505 * the listener which should no longer be notified. This message
|
|
506 * has no effect if the listener was not previously added to the
|
|
507 * receiver.
|
|
508 *
|
|
509 * @see dwt.events.MenuDetectListener
|
|
510 * @see #addMenuDetectListener
|
|
511 */
|
|
512 public void removeMenuDetectListener(MenuDetectListener listener) {
|
|
513 menuDetectListeners.remove(cast(Object)listener);
|
|
514 }
|
|
515
|
|
516 /**
|
|
517 * Adds the listener to the collection of listeners who will be notified
|
|
518 * when the decoration is selected, by sending it one of the messages
|
|
519 * defined in the <code>SelectionListener</code> interface.
|
|
520 * <p>
|
|
521 * <code>widgetSelected</code> is called when the decoration is selected
|
|
522 * (by mouse click). <code>widgetDefaultSelected</code> is called when the
|
|
523 * decoration is double-clicked.
|
|
524 * </p>
|
|
525 * <p>
|
|
526 * The <code>widget</code> field in the SelectionEvent will contain the
|
|
527 * Composite on which the decoration is rendered that received the click.
|
|
528 * The <code>x</code> and <code>y</code> fields will be in coordinates
|
|
529 * relative to that widget. The <code>data</code> field will contain the
|
|
530 * decoration that received the event.
|
|
531 * </p>
|
|
532 *
|
|
533 * @param listener
|
|
534 * the listener which should be notified
|
|
535 *
|
|
536 * @see dwt.events.SelectionListener
|
|
537 * @see dwt.events.SelectionEvent
|
|
538 * @see #removeSelectionListener
|
|
539 */
|
|
540 public void addSelectionListener(SelectionListener listener) {
|
|
541 selectionListeners.add(cast(Object)listener);
|
|
542 }
|
|
543
|
|
544 /**
|
|
545 * Removes the listener from the collection of listeners who will be
|
|
546 * notified when the decoration is selected.
|
|
547 *
|
|
548 * @param listener
|
|
549 * the listener which should no longer be notified. This message
|
|
550 * has no effect if the listener was not previously added to the
|
|
551 * receiver.
|
|
552 *
|
|
553 * @see dwt.events.SelectionListener
|
|
554 * @see #addSelectionListener
|
|
555 */
|
|
556 public void removeSelectionListener(SelectionListener listener) {
|
|
557 selectionListeners.remove(cast(Object)listener);
|
|
558 }
|
|
559
|
|
560 /**
|
|
561 * Dispose this ControlDecoration. Unhook any listeners that have been
|
|
562 * installed on the target control. This method has no effect if the
|
|
563 * receiver is already disposed.
|
|
564 */
|
|
565 public void dispose() {
|
|
566 if (control is null) {
|
|
567 return;
|
|
568 }
|
|
569 if (hover !is null) {
|
|
570 hover.dispose();
|
|
571 hover = null;
|
|
572 }
|
|
573 removeControlListeners();
|
|
574 control = null;
|
|
575 }
|
|
576
|
|
577 /**
|
|
578 * Get the control that is decorated by the receiver.
|
|
579 *
|
|
580 * @return the Control decorated by the receiver. May be <code>null</code>
|
|
581 * if the control has been uninstalled.
|
|
582 */
|
|
583 public Control getControl() {
|
|
584 return control;
|
|
585 }
|
|
586
|
|
587 /**
|
|
588 * Add any listeners needed on the target control and on the composite where
|
|
589 * the decoration is to be rendered.
|
|
590 */
|
|
591 private void addControlListeners() {
|
|
592 disposeListener = new class DisposeListener {
|
|
593 public void widgetDisposed(DisposeEvent event) {
|
|
594 dispose();
|
|
595 }
|
|
596 };
|
|
597 printAddListener(control, "DISPOSE"); //$NON-NLS-1$
|
|
598 control.addDisposeListener(disposeListener);
|
|
599
|
|
600 focusListener = new class FocusListener {
|
|
601 public void focusGained(FocusEvent event) {
|
|
602 hasFocus = true;
|
|
603 if (showOnlyOnFocus) {
|
|
604 update();
|
|
605 }
|
|
606 }
|
|
607
|
|
608 public void focusLost(FocusEvent event) {
|
|
609 hasFocus = false;
|
|
610 if (showOnlyOnFocus) {
|
|
611 update();
|
|
612 }
|
|
613 }
|
|
614 };
|
|
615 printAddListener(control, "FOCUS"); //$NON-NLS-1$
|
|
616 control.addFocusListener(focusListener);
|
|
617
|
|
618 // Listener for painting the decoration
|
|
619 paintListener = new class PaintListener {
|
|
620 public void paintControl(PaintEvent event) {
|
|
621 Control control = cast(Control) event.widget;
|
|
622 Rectangle rect = getDecorationRectangle(control);
|
|
623 if (shouldShowDecoration()) {
|
|
624 event.gc.drawImage(getImage(), rect.x, rect.y);
|
|
625 }
|
|
626 }
|
|
627 };
|
|
628
|
|
629 // Listener for tracking the end of a hover. Only installed
|
|
630 // after a hover begins.
|
|
631 mouseMoveListener = new class MouseMoveListener {
|
|
632 public void mouseMove(MouseEvent event) {
|
|
633 if (showHover) {
|
|
634 if (!decorationRectangle.contains(event.x, event.y)) {
|
|
635 hideHover();
|
|
636 // No need to listen any longer
|
|
637 printRemoveListener(event.widget, "MOUSEMOVE"); //$NON-NLS-1$
|
|
638 (cast(Control) event.widget)
|
|
639 .removeMouseMoveListener(mouseMoveListener);
|
|
640 moveListeningTarget = null;
|
|
641 }
|
|
642 }
|
|
643 }
|
|
644 };
|
|
645
|
|
646 // Listener for tracking the beginning of a hover. Always installed.
|
|
647 mouseTrackListener = new class MouseTrackListener {
|
|
648 public void mouseExit(MouseEvent event) {
|
|
649 // Just in case we didn't catch it before.
|
|
650 Control target = cast(Control) event.widget;
|
|
651 if (target is moveListeningTarget) {
|
|
652 printRemoveListener(target, "MOUSEMOVE"); //$NON-NLS-1$
|
|
653 target.removeMouseMoveListener(mouseMoveListener);
|
|
654 moveListeningTarget = null;
|
|
655 }
|
|
656 hideHover();
|
|
657 }
|
|
658
|
|
659 public void mouseHover(MouseEvent event) {
|
|
660 if (showHover) {
|
|
661 decorationRectangle = getDecorationRectangle(cast(Control) event.widget);
|
|
662 if (decorationRectangle.contains(event.x, event.y)) {
|
|
663 showHoverText(getDescriptionText());
|
|
664 Control target = cast(Control) event.widget;
|
|
665 if (moveListeningTarget is null) {
|
|
666 printAddListener(target, "MOUSEMOVE"); //$NON-NLS-1$
|
|
667 target.addMouseMoveListener(mouseMoveListener);
|
|
668 moveListeningTarget = target;
|
|
669 } else if (target !is moveListeningTarget) {
|
|
670 printRemoveListener(moveListeningTarget,
|
|
671 "MOUSEMOVE"); //$NON-NLS-1$
|
|
672 moveListeningTarget
|
|
673 .removeMouseMoveListener(mouseMoveListener);
|
|
674 printAddListener(target, "MOUSEMOVE"); //$NON-NLS-1$
|
|
675 target.addMouseMoveListener(mouseMoveListener);
|
|
676 moveListeningTarget = target;
|
|
677 } else {
|
|
678 // It is already installed on this control.
|
|
679 }
|
|
680 }
|
|
681 }
|
|
682 }
|
|
683
|
|
684 public void mouseEnter(MouseEvent event) {
|
|
685 // Nothing to do until a hover occurs.
|
|
686 }
|
|
687 };
|
|
688
|
|
689 compositeListener = new class Listener {
|
|
690 public void handleEvent(Event event) {
|
|
691 // Don't forward events if decoration is not showing
|
|
692 if (!visible) {
|
|
693 return;
|
|
694 }
|
|
695 // Notify listeners if any are registered.
|
|
696 switch (event.type) {
|
|
697 case DWT.MouseDown:
|
|
698 if (!selectionListeners.isEmpty())
|
|
699 notifySelectionListeners(event);
|
|
700 break;
|
|
701 case DWT.MouseDoubleClick:
|
|
702 if (!selectionListeners.isEmpty())
|
|
703 notifySelectionListeners(event);
|
|
704 break;
|
|
705 case DWT.MenuDetect:
|
|
706 if (!menuDetectListeners.isEmpty())
|
|
707 notifyMenuDetectListeners(event);
|
|
708 break;
|
|
709 }
|
|
710 }
|
|
711 };
|
|
712
|
|
713 // We do not know which parent in the control hierarchy
|
|
714 // is providing the decoration space, so hook all the way up, until
|
|
715 // the shell or the specified parent composite is reached.
|
|
716 Composite c = control.getParent();
|
|
717 while (c !is null) {
|
|
718 installCompositeListeners(c);
|
|
719 if (composite !is null && composite is c) {
|
|
720 // We just installed on the specified composite, so stop.
|
|
721 c = null;
|
|
722 } else if (cast(Shell)c ) {
|
|
723 // We just installed on a shell, so don't go further
|
|
724 c = null;
|
|
725 } else {
|
|
726 c = c.getParent();
|
|
727 }
|
|
728 }
|
|
729 // force a redraw of the decoration area so our paint listener
|
|
730 // is notified.
|
|
731 update();
|
|
732 }
|
|
733
|
|
734 /*
|
|
735 * Install the listeners used to paint and track mouse events on the
|
|
736 * composite.
|
|
737 */
|
|
738 private void installCompositeListeners(Composite c) {
|
|
739 if (!c.isDisposed()) {
|
|
740 printAddListener(c, "PAINT"); //$NON-NLS-1$
|
|
741 c.addPaintListener(paintListener);
|
|
742 printAddListener(c, "MOUSETRACK"); //$NON-NLS-1$
|
|
743 c.addMouseTrackListener(mouseTrackListener);
|
|
744 printAddListener(c, "DWT.MenuDetect"); //$NON-NLS-1$
|
|
745 c.addListener(DWT.MenuDetect, compositeListener);
|
|
746 printAddListener(c, "DWT.MouseDown"); //$NON-NLS-1$
|
|
747 c.addListener(DWT.MouseDown, compositeListener);
|
|
748 printAddListener(c, "DWT.MouseDoubleClick"); //$NON-NLS-1$
|
|
749 c.addListener(DWT.MouseDoubleClick, compositeListener);
|
|
750 }
|
|
751 }
|
|
752
|
|
753 /*
|
|
754 * Remove the listeners used to paint and track mouse events on the
|
|
755 * composite.
|
|
756 */
|
|
757 private void removeCompositeListeners(Composite c) {
|
|
758 if (!c.isDisposed()) {
|
|
759 printRemoveListener(c, "PAINT"); //$NON-NLS-1$
|
|
760 c.removePaintListener(paintListener);
|
|
761 printRemoveListener(c, "MOUSETRACK"); //$NON-NLS-1$
|
|
762 c.removeMouseTrackListener(mouseTrackListener);
|
|
763 printRemoveListener(c, "DWT.MenuDetect"); //$NON-NLS-1$
|
|
764 c.removeListener(DWT.MenuDetect, compositeListener);
|
|
765 printRemoveListener(c, "DWT.MouseDown"); //$NON-NLS-1$
|
|
766 c.removeListener(DWT.MouseDown, compositeListener);
|
|
767 printRemoveListener(c, "DWT.MouseDoubleClick"); //$NON-NLS-1$
|
|
768 c.removeListener(DWT.MouseDoubleClick, compositeListener);
|
|
769 }
|
|
770 }
|
|
771
|
|
772 private void notifySelectionListeners(Event event) {
|
|
773 if (!(cast(Control)event.widget )) {
|
|
774 return;
|
|
775 }
|
|
776 if (getDecorationRectangle(cast(Control) event.widget).contains(event.x,
|
|
777 event.y)) {
|
|
778 SelectionEvent clientEvent = new SelectionEvent(event);
|
|
779 clientEvent.data = this;
|
|
780 if (getImage() !is null) {
|
|
781 clientEvent.height = getImage().getBounds().height;
|
|
782 clientEvent.width = getImage().getBounds().width;
|
|
783 }
|
|
784 Object[] listeners;
|
|
785 switch (event.type) {
|
|
786 case DWT.MouseDoubleClick:
|
|
787 if (event.button is 1) {
|
|
788 listeners = selectionListeners.getListeners();
|
|
789 for (int i = 0; i < listeners.length; i++) {
|
|
790 (cast(SelectionListener) listeners[i])
|
|
791 .widgetDefaultSelected(clientEvent);
|
|
792 }
|
|
793 }
|
|
794 break;
|
|
795 case DWT.MouseDown:
|
|
796 if (event.button is 1) {
|
|
797 listeners = selectionListeners.getListeners();
|
|
798 for (int i = 0; i < listeners.length; i++) {
|
|
799 (cast(SelectionListener) listeners[i])
|
|
800 .widgetSelected(clientEvent);
|
|
801 }
|
|
802 }
|
|
803 break;
|
|
804 }
|
|
805 }
|
|
806 }
|
|
807
|
|
808 private void notifyMenuDetectListeners(Event event) {
|
|
809 if (getDecorationRectangle(null).contains(event.x, event.y)) {
|
|
810 MenuDetectEvent clientEvent = new MenuDetectEvent(event);
|
|
811 clientEvent.data = this;
|
|
812 Object[] listeners = menuDetectListeners.getListeners();
|
|
813 for (int i = 0; i < listeners.length; i++) {
|
|
814 (cast(MenuDetectListener) listeners[i]).menuDetected(clientEvent);
|
|
815
|
|
816 }
|
|
817 }
|
|
818 }
|
|
819
|
|
820 /**
|
|
821 * Show the specified text using the same hover dialog as is used to show
|
|
822 * decorator descriptions. When {@link #setShowHover(bool)} has been set
|
|
823 * to <code>true</code>, a decoration's description text will be shown in
|
|
824 * an info hover over the field's control whenever the mouse hovers over the
|
|
825 * decoration. This method can be used to show a decoration's description
|
|
826 * text at other times (such as when the control receives focus), or to show
|
|
827 * other text associated with the field.
|
|
828 *
|
|
829 * @param text
|
|
830 * the text to be shown in the info hover, or <code>null</code>
|
|
831 * if no text should be shown.
|
|
832 */
|
|
833 public void showHoverText(String text) {
|
|
834 if (control is null) {
|
|
835 return;
|
|
836 }
|
|
837 showHoverText(text, control);
|
|
838 }
|
|
839
|
|
840 /**
|
|
841 * Hide any hover popups that are currently showing on the control. When
|
|
842 * {@link #setShowHover(bool)} has been set to <code>true</code>, a
|
|
843 * decoration's description text will be shown in an info hover over the
|
|
844 * field's control as long as the mouse hovers over the decoration, and will
|
|
845 * be hidden when the mouse exits the decoration. This method can be used to
|
|
846 * hide a hover, whether it was shown explicitly using
|
|
847 * {@link #showHoverText(String)}, or was showing because the user was
|
|
848 * hovering in the decoration.
|
|
849 * <p>
|
|
850 * This message has no effect if there is no current hover.
|
|
851 *
|
|
852 */
|
|
853 public void hideHover() {
|
|
854 if (hover !is null) {
|
|
855 hover.setVisible(false);
|
|
856 }
|
|
857 }
|
|
858
|
|
859 /**
|
|
860 * Show the control decoration. This message has no effect if the decoration
|
|
861 * is already showing. If {@link #setShowOnlyOnFocus(bool)} is set to
|
|
862 * <code>true</code>, the decoration will only be shown if the control
|
|
863 * has focus.
|
|
864 */
|
|
865 public void show() {
|
|
866 if (!visible) {
|
|
867 visible = true;
|
|
868 update();
|
|
869 }
|
|
870 }
|
|
871
|
|
872 /**
|
|
873 * Hide the control decoration. This message has no effect if the decoration
|
|
874 * is already hidden.
|
|
875 */
|
|
876 public void hide() {
|
|
877 if (visible) {
|
|
878 visible = false;
|
|
879 update();
|
|
880 }
|
|
881 }
|
|
882
|
|
883 /**
|
|
884 * Get the description text that may be shown in a hover for this
|
|
885 * decoration.
|
|
886 *
|
|
887 * @return the text to be shown as a description for the decoration, or
|
|
888 * <code>null</code> if none has been set.
|
|
889 */
|
|
890 public String getDescriptionText() {
|
|
891 return descriptionText;
|
|
892 }
|
|
893
|
|
894 /**
|
|
895 * Set the image shown in this control decoration. Update the rendered
|
|
896 * decoration.
|
|
897 *
|
|
898 * @param text
|
|
899 * the text to be shown as a description for the decoration, or
|
|
900 * <code>null</code> if none has been set.
|
|
901 */
|
|
902 public void setDescriptionText(String text) {
|
|
903 this.descriptionText = text;
|
|
904 update();
|
|
905 }
|
|
906
|
|
907 /**
|
|
908 * Get the image shown in this control decoration.
|
|
909 *
|
|
910 * @return the image to be shown adjacent to the control, or
|
|
911 * <code>null</code> if one has not been set.
|
|
912 */
|
|
913 public Image getImage() {
|
|
914 return image;
|
|
915 }
|
|
916
|
|
917 /**
|
|
918 * Set the image shown in this control decoration. Update the rendered
|
|
919 * decoration.
|
|
920 *
|
|
921 * @param image
|
|
922 * the image to be shown adjacent to the control
|
|
923 */
|
|
924 public void setImage(Image image) {
|
|
925 this.image = image;
|
|
926 update();
|
|
927 }
|
|
928
|
|
929 /**
|
|
930 * Get the bool that controls whether the decoration is shown only when
|
|
931 * the control has focus. The default value of this setting is
|
|
932 * <code>false</code>.
|
|
933 *
|
|
934 * @return <code>true</code> if the decoration should only be shown when
|
|
935 * the control has focus, and <code>false</code> if it should
|
|
936 * always be shown. Note that if the control is not capable of
|
|
937 * receiving focus (<code>DWT.NO_FOCUS</code>), then the
|
|
938 * decoration will never show when this value is <code>true</code>.
|
|
939 */
|
|
940 public bool getShowOnlyOnFocus() {
|
|
941 return showOnlyOnFocus;
|
|
942 }
|
|
943
|
|
944 /**
|
|
945 * Set the bool that controls whether the decoration is shown only when
|
|
946 * the control has focus. The default value of this setting is
|
|
947 * <code>false</code>.
|
|
948 *
|
|
949 * @param showOnlyOnFocus
|
|
950 * <code>true</code> if the decoration should only be shown
|
|
951 * when the control has focus, and <code>false</code> if it
|
|
952 * should always be shown. Note that if the control is not
|
|
953 * capable of receiving focus (<code>DWT.NO_FOCUS</code>),
|
|
954 * then the decoration will never show when this value is
|
|
955 * <code>true</code>.
|
|
956 */
|
|
957 public void setShowOnlyOnFocus(bool showOnlyOnFocus) {
|
|
958 this.showOnlyOnFocus = showOnlyOnFocus;
|
|
959 update();
|
|
960 }
|
|
961
|
|
962 /**
|
|
963 * Get the bool that controls whether the decoration's description text
|
|
964 * should be shown in a hover when the user hovers over the decoration. The
|
|
965 * default value of this setting is <code>true</code>.
|
|
966 *
|
|
967 * @return <code>true</code> if a hover popup containing the decoration's
|
|
968 * description text should be shown when the user hovers over the
|
|
969 * decoration, and <code>false</code> if a hover should not be
|
|
970 * shown.
|
|
971 */
|
|
972 public bool getShowHover() {
|
|
973 return showHover;
|
|
974 }
|
|
975
|
|
976 /**
|
|
977 * Set the bool that controls whether the decoration's description text
|
|
978 * should be shown in a hover when the user hovers over the decoration. The
|
|
979 * default value of this setting is <code>true</code>.
|
|
980 *
|
|
981 * @param showHover
|
|
982 * <code>true</code> if a hover popup containing the
|
|
983 * decoration's description text should be shown when the user
|
|
984 * hovers over the decoration, and <code>false</code> if a
|
|
985 * hover should not be shown.
|
|
986 */
|
|
987 public void setShowHover(bool showHover) {
|
|
988 this.showHover = showHover;
|
|
989 update();
|
|
990 }
|
|
991
|
|
992 /**
|
|
993 * Get the margin width in pixels that should be used between the decorator
|
|
994 * and the horizontal edge of the control. The default value of this setting
|
|
995 * is <code>0</code>.
|
|
996 *
|
|
997 * @return the number of pixels that should be reserved between the
|
|
998 * horizontal edge of the control and the adjacent edge of the
|
|
999 * decoration.
|
|
1000 */
|
|
1001 public int getMarginWidth() {
|
|
1002 return marginWidth;
|
|
1003 }
|
|
1004
|
|
1005 /**
|
|
1006 * Set the margin width in pixels that should be used between the decorator
|
|
1007 * and the horizontal edge of the control. The default value of this setting
|
|
1008 * is <code>0</code>.
|
|
1009 *
|
|
1010 * @param marginWidth
|
|
1011 * the number of pixels that should be reserved between the
|
|
1012 * horizontal edge of the control and the adjacent edge of the
|
|
1013 * decoration.
|
|
1014 */
|
|
1015 public void setMarginWidth(int marginWidth) {
|
|
1016 this.marginWidth = marginWidth;
|
|
1017 update();
|
|
1018 }
|
|
1019
|
|
1020 /**
|
|
1021 * Something has changed, requiring redraw. Redraw the decoration and update
|
|
1022 * the hover text if appropriate.
|
|
1023 */
|
|
1024 protected void update() {
|
|
1025 if (control is null || control.isDisposed()) {
|
|
1026 return;
|
|
1027 }
|
|
1028 Rectangle rect = getDecorationRectangle(control.getShell());
|
|
1029 // Redraw this rectangle in all children
|
|
1030 control.getShell()
|
|
1031 .redraw(rect.x, rect.y, rect.width, rect.height, true);
|
|
1032 control.getShell().update();
|
|
1033 if (hover !is null && getDescriptionText() !is null) {
|
|
1034 hover.setText(getDescriptionText(), getDecorationRectangle(control
|
|
1035 .getParent()), control);
|
|
1036 }
|
|
1037 }
|
|
1038
|
|
1039 /*
|
|
1040 * Show the specified text in the hover, positioning the hover near the
|
|
1041 * specified control.
|
|
1042 */
|
|
1043 private void showHoverText(String text, Control hoverNear) {
|
|
1044 // If we aren't to show a hover, don't do anything.
|
|
1045 if (!showHover) {
|
|
1046 return;
|
|
1047 }
|
|
1048 // If there is no text, don't do anything.
|
|
1049 if (text is null) {
|
|
1050 hideHover();
|
|
1051 return;
|
|
1052 }
|
|
1053
|
|
1054 // If there is no control, nothing to do
|
|
1055 if (control is null) {
|
|
1056 return;
|
|
1057 }
|
|
1058 // Create the hover if it's not showing
|
|
1059 if (hover is null) {
|
|
1060 hover = new Hover(hoverNear.getShell());
|
|
1061 }
|
|
1062 hover.setText(text, getDecorationRectangle(control.getParent()),
|
|
1063 control);
|
|
1064 hover.setVisible(true);
|
|
1065 }
|
|
1066
|
|
1067 /*
|
|
1068 * Remove any listeners installed on the controls.
|
|
1069 */
|
|
1070 private void removeControlListeners() {
|
|
1071 if (control is null) {
|
|
1072 return;
|
|
1073 }
|
|
1074 printRemoveListener(control, "FOCUS"); //$NON-NLS-1$
|
|
1075 control.removeFocusListener(focusListener);
|
|
1076 focusListener = null;
|
|
1077
|
|
1078 printRemoveListener(control, "DISPOSE"); //$NON-NLS-1$
|
|
1079 control.removeDisposeListener(disposeListener);
|
|
1080 disposeListener = null;
|
|
1081
|
|
1082 Composite c = control.getParent();
|
|
1083 while (c !is null) {
|
|
1084 removeCompositeListeners(c);
|
|
1085 if (composite !is null && composite is c) {
|
|
1086 // We previously installed listeners only to the specified
|
|
1087 // composite, so stop.
|
|
1088 c = null;
|
|
1089 } else if (cast(Shell)c ) {
|
|
1090 // We previously installed listeners only up to the first Shell
|
|
1091 // encountered, so stop.
|
|
1092 c = null;
|
|
1093 } else {
|
|
1094 c = c.getParent();
|
|
1095 }
|
|
1096 }
|
|
1097 paintListener = null;
|
|
1098 mouseTrackListener = null;
|
|
1099 compositeListener = null;
|
|
1100
|
|
1101 // We may have a remaining mouse move listener installed
|
|
1102 if (moveListeningTarget !is null) {
|
|
1103 printRemoveListener(moveListeningTarget, "MOUSEMOVE"); //$NON-NLS-1$
|
|
1104 moveListeningTarget.removeMouseMoveListener(mouseMoveListener);
|
|
1105 moveListeningTarget = null;
|
|
1106 mouseMoveListener = null;
|
|
1107 }
|
|
1108 if (DEBUG) {
|
|
1109 if (listenerInstalls > 0) {
|
|
1110 Stdout.formatln("LISTENER LEAK>>>CHECK TRACE ABOVE"); //$NON-NLS-1$
|
|
1111 } else if (listenerInstalls < 0) {
|
|
1112 Stdout.formatln("REMOVED UNREGISTERED LISTENERS>>>CHECK TRACE ABOVE"); //$NON-NLS-1$
|
|
1113 } else {
|
|
1114 Stdout.formatln("ALL INSTALLED LISTENERS WERE REMOVED."); //$NON-NLS-1$
|
|
1115 }
|
|
1116 }
|
|
1117 }
|
|
1118
|
|
1119 /**
|
|
1120 * Return the rectangle in which the decoration should be rendered, in
|
|
1121 * coordinates relative to the specified control. If the specified control
|
|
1122 * is null, return the rectangle in display coordinates.
|
|
1123 *
|
|
1124 * @param targetControl
|
|
1125 * the control whose coordinates should be used
|
|
1126 * @return the rectangle in which the decoration should be rendered
|
|
1127 */
|
|
1128 protected Rectangle getDecorationRectangle(Control targetControl) {
|
|
1129 if (getImage() is null || control is null) {
|
|
1130 return new Rectangle(0, 0, 0, 0);
|
|
1131 }
|
|
1132 // Compute the bounds first relative to the control's parent.
|
|
1133 Rectangle imageBounds = getImage().getBounds();
|
|
1134 Rectangle controlBounds = control.getBounds();
|
|
1135 int x, y;
|
|
1136 // Compute x
|
|
1137 if ((position & DWT.RIGHT) is DWT.RIGHT) {
|
|
1138 x = controlBounds.x + controlBounds.width + marginWidth;
|
|
1139 } else {
|
|
1140 // default is left
|
|
1141 x = controlBounds.x - imageBounds.width - marginWidth;
|
|
1142 }
|
|
1143 // Compute y
|
|
1144 if ((position & DWT.TOP) is DWT.TOP) {
|
|
1145 y = controlBounds.y;
|
|
1146 } else if ((position & DWT.BOTTOM) is DWT.BOTTOM) {
|
|
1147 y = controlBounds.y + control.getBounds().height
|
|
1148 - imageBounds.height;
|
|
1149 } else {
|
|
1150 // default is center
|
|
1151 y = controlBounds.y
|
|
1152 + (control.getBounds().height - imageBounds.height) / 2;
|
|
1153 }
|
|
1154
|
|
1155 // Now convert to coordinates relative to the target control.
|
|
1156 Point globalPoint = control.getParent().toDisplay(x, y);
|
|
1157 Point targetPoint;
|
|
1158 if (targetControl is null) {
|
|
1159 targetPoint = globalPoint;
|
|
1160 } else {
|
|
1161 targetPoint = targetControl.toControl(globalPoint);
|
|
1162 }
|
|
1163 return new Rectangle(targetPoint.x, targetPoint.y, imageBounds.width,
|
|
1164 imageBounds.height);
|
|
1165 }
|
|
1166
|
|
1167 /*
|
|
1168 * Return true if the decoration should be shown, false if it should not.
|
|
1169 */
|
|
1170 private bool shouldShowDecoration() {
|
|
1171 if (!visible) {
|
|
1172 return false;
|
|
1173 }
|
|
1174 if (control is null || control.isDisposed() || getImage() is null) {
|
|
1175 return false;
|
|
1176 }
|
|
1177
|
|
1178 if (!control.isVisible()) {
|
|
1179 return false;
|
|
1180 }
|
|
1181 if (showOnlyOnFocus) {
|
|
1182 return hasFocus;
|
|
1183 }
|
|
1184 return true;
|
|
1185 }
|
|
1186
|
|
1187 /*
|
|
1188 * If in debug mode, print info about adding the specified listener.
|
|
1189 */
|
|
1190 private void printAddListener(Widget widget, String listenerType) {
|
|
1191 listenerInstalls++;
|
|
1192 if (DEBUG) {
|
|
1193 Stdout.formatln("Added listener>>>{} to>>>{}", listenerType, widget); //$NON-NLS-1$//$NON-NLS-2$
|
|
1194 }
|
|
1195 }
|
|
1196
|
|
1197 /*
|
|
1198 * If in debug mode, print info about adding the specified listener.
|
|
1199 */
|
|
1200 private void printRemoveListener(Widget widget, String listenerType) {
|
|
1201 listenerInstalls--;
|
|
1202 if (DEBUG) {
|
|
1203 Stdout.formatln("Removed listener>>>{} from>>>{}", listenerType, widget); //$NON-NLS-1$//$NON-NLS-2$
|
|
1204 }
|
|
1205 }
|
|
1206 }
|