]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ToolTip.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / ToolTip.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15
16
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.*;
21 import org.eclipse.swt.internal.win32.*;
22
23 /**
24  * Instances of this class represent popup windows that are used
25  * to inform or warn the user.
26  * <dl>
27  * <dt><b>Styles:</b></dt>
28  * <dd>BALLOON, ICON_ERROR, ICON_INFORMATION, ICON_WARNING</dd>
29  * <dt><b>Events:</b></dt>
30  * <dd>Selection</dd>
31  * </dl>
32  * <p>
33  * Note: Only one of the styles ICON_ERROR, ICON_INFORMATION,
34  * and ICON_WARNING may be specified.
35  * </p><p>
36  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
37  * </p>
38  *
39  * @see <a href="http://www.eclipse.org/swt/snippets/#tooltips">Tool Tips snippets</a>
40  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
41  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
42  *
43  * @since 3.2
44  * @noextend This class is not intended to be subclassed by clients.
45  */
46 public class ToolTip extends Widget {
47         Shell parent;
48         TrayItem item;
49         String text = "", message = "";
50         int id, x, y;
51         boolean autoHide = true, hasLocation, visible;
52         static final int TIMER_ID = 100;
53
54 /**
55  * Constructs a new instance of this class given its parent
56  * and a style value describing its behavior and appearance.
57  * <p>
58  * The style value is either one of the style constants defined in
59  * class <code>SWT</code> which is applicable to instances of this
60  * class, or must be built by <em>bitwise OR</em>'ing together
61  * (that is, using the <code>int</code> "|" operator) two or more
62  * of those <code>SWT</code> style constants. The class description
63  * lists the style constants that are applicable to the class.
64  * Style bits are also inherited from superclasses.
65  * </p>
66  *
67  * @param parent a composite control which will be the parent of the new instance (cannot be null)
68  * @param style the style of control to construct
69  *
70  * @exception IllegalArgumentException <ul>
71  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
72  * </ul>
73  * @exception SWTException <ul>
74  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
75  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
76  * </ul>
77  *
78  * @see SWT#BALLOON
79  * @see SWT#ICON_ERROR
80  * @see SWT#ICON_INFORMATION
81  * @see SWT#ICON_WARNING
82  * @see Widget#checkSubclass
83  * @see Widget#getStyle
84  */
85 public ToolTip (Shell parent, int style) {
86         super (parent, checkStyle (style));
87         this.parent = parent;
88         checkOrientation (parent);
89         parent.createToolTip (this);
90 }
91
92 static int checkStyle (int style) {
93         int mask = SWT.ICON_ERROR | SWT.ICON_INFORMATION | SWT.ICON_WARNING;
94         if ((style & mask) == 0) return style;
95         return checkBits (style, SWT.ICON_INFORMATION, SWT.ICON_WARNING, SWT.ICON_ERROR, 0, 0, 0);
96 }
97
98 /**
99  * Adds the listener to the collection of listeners who will
100  * be notified when the receiver is selected by the user, by sending
101  * it one of the messages defined in the <code>SelectionListener</code>
102  * interface.
103  * <p>
104  * <code>widgetSelected</code> is called when the receiver is selected.
105  * <code>widgetDefaultSelected</code> is not called.
106  * </p>
107  *
108  * @param listener the listener which should be notified when the receiver is selected by the user
109  *
110  * @exception IllegalArgumentException <ul>
111  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
112  * </ul>
113  * @exception SWTException <ul>
114  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
115  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
116  * </ul>
117  *
118  * @see SelectionListener
119  * @see #removeSelectionListener
120  * @see SelectionEvent
121  */
122 public void addSelectionListener (SelectionListener listener) {
123         checkWidget ();
124         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
125         TypedListener typedListener = new TypedListener(listener);
126         addListener (SWT.Selection,typedListener);
127         addListener (SWT.DefaultSelection,typedListener);
128 }
129
130 @Override
131 void destroyWidget () {
132         if (parent != null) parent.destroyToolTip (this);
133         releaseHandle ();
134 }
135
136 /**
137  * Returns <code>true</code> if the receiver is automatically
138  * hidden by the platform, and <code>false</code> otherwise.
139  *
140  * @return the receiver's auto hide state
141  *
142  * @exception SWTException <ul>
143  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
144  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
145  * </ul>
146  *
147  */
148 public boolean getAutoHide () {
149         checkWidget();
150         return autoHide;
151 }
152
153 /**
154  * Returns the receiver's message, which will be an empty
155  * string if it has never been set.
156  *
157  * @return the receiver's message
158  *
159  * @exception SWTException <ul>
160  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
161  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
162  * </ul>
163  */
164 public String getMessage () {
165         checkWidget();
166         return message;
167 }
168
169 /**
170  * Returns the receiver's parent, which must be a <code>Shell</code>.
171  *
172  * @return the receiver's parent
173  *
174  * @exception SWTException <ul>
175  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
176  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
177  * </ul>
178  */
179 public Shell getParent () {
180         checkWidget ();
181         return parent;
182 }
183
184 /**
185  * Returns the receiver's text, which will be an empty
186  * string if it has never been set.
187  *
188  * @return the receiver's text
189  *
190  * @exception SWTException <ul>
191  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
192  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
193  * </ul>
194  */
195 public String getText () {
196         checkWidget();
197         return text;
198 }
199
200 /**
201  * Returns <code>true</code> if the receiver is visible, and
202  * <code>false</code> otherwise.
203  * <p>
204  * If one of the receiver's ancestors is not visible or some
205  * other condition makes the receiver not visible, this method
206  * may still indicate that it is considered visible even though
207  * it may not actually be showing.
208  * </p>
209  *
210  * @return the receiver's visibility state
211  *
212  * @exception SWTException <ul>
213  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
214  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
215  * </ul>
216  */
217 public boolean getVisible () {
218         checkWidget();
219         if (item != null) return visible;
220         long hwndToolTip = hwndToolTip ();
221         if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
222                 TOOLINFO lpti = new TOOLINFO ();
223                 lpti.cbSize = TOOLINFO.sizeof;
224                 if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
225                         return (lpti.uFlags & OS.TTF_IDISHWND) == 0 && lpti.uId == id;
226                 }
227         }
228         return false;
229 }
230
231 int getWidth () {
232         long hwnd = parent.handle;
233         long hmonitor = OS.MonitorFromWindow (hwnd, OS.MONITOR_DEFAULTTONEAREST);
234         MONITORINFO lpmi = new MONITORINFO ();
235         lpmi.cbSize = MONITORINFO.sizeof;
236         OS.GetMonitorInfo (hmonitor, lpmi);
237         int maxWidth = lpmi.rcWork_right - lpmi.rcWork_left;
238         return maxWidth / 4;
239 }
240
241 long hwndToolTip () {
242         return (style & SWT.BALLOON) != 0 ? parent.balloonTipHandle () : parent.toolTipHandle ();
243 }
244
245 /**
246  * Returns <code>true</code> if the receiver is visible and all
247  * of the receiver's ancestors are visible and <code>false</code>
248  * otherwise.
249  *
250  * @return the receiver's visibility state
251  *
252  * @exception SWTException <ul>
253  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
254  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
255  * </ul>
256  *
257  * @see #getVisible
258  */
259 public boolean isVisible () {
260         checkWidget ();
261         if (item != null) return getVisible () && item.getVisible ();
262         return getVisible ();
263 }
264
265 @Override
266 void releaseHandle () {
267         super.releaseHandle ();
268         parent = null;
269         item = null;
270         id = -1;
271 }
272
273 @Override
274 void releaseWidget () {
275         super.releaseWidget ();
276         if (item == null) {
277                 if (autoHide) {
278                         long hwndToolTip = hwndToolTip ();
279                         if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
280                                 TOOLINFO lpti = new TOOLINFO ();
281                                 lpti.cbSize = TOOLINFO.sizeof;
282                                 if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
283                                         if ((lpti.uFlags & OS.TTF_IDISHWND) == 0) {
284                                                 if (lpti.uId == id) {
285                                                         OS.SendMessage (hwndToolTip, OS.TTM_TRACKACTIVATE, 0, lpti);
286                                                         OS.SendMessage (hwndToolTip, OS.TTM_POP, 0, 0);
287                                                         OS.KillTimer (hwndToolTip, TIMER_ID);
288                                                 }
289                                         }
290                                 }
291                         }
292                 }
293         }
294         if (item != null && item.toolTip == this) {
295                 item.toolTip = null;
296         }
297         item = null;
298         text = message = null;
299 }
300
301 /**
302  * Removes the listener from the collection of listeners who will
303  * be notified when the receiver is selected by the user.
304  *
305  * @param listener the listener which should no longer be notified
306  *
307  * @exception IllegalArgumentException <ul>
308  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
309  * </ul>
310  * @exception SWTException <ul>
311  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313  * </ul>
314  *
315  * @see SelectionListener
316  * @see #addSelectionListener
317  */
318 public void removeSelectionListener (SelectionListener listener) {
319         checkWidget ();
320         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
321         if (eventTable == null) return;
322         eventTable.unhook (SWT.Selection, listener);
323         eventTable.unhook (SWT.DefaultSelection,listener);
324 }
325
326 /**
327  * Makes the receiver hide automatically when <code>true</code>,
328  * and remain visible when <code>false</code>.
329  *
330  * @param autoHide the auto hide state
331  *
332  * @exception SWTException <ul>
333  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
334  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
335  * </ul>
336  *
337  * @see #getVisible
338  * @see #setVisible
339  */
340 public void setAutoHide (boolean autoHide) {
341         checkWidget ();
342         this.autoHide = autoHide;
343         //TODO - update when visible
344 }
345
346 /**
347  * Sets the location of the receiver, which must be a tooltip,
348  * to the point specified by the arguments which are relative
349  * to the display.
350  * <p>
351  * Note that this is different from most widgets where the
352  * location of the widget is relative to the parent.
353  * </p>
354  *
355  * @param x the new x coordinate for the receiver
356  * @param y the new y coordinate for the receiver
357  *
358  * @exception SWTException <ul>
359  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
360  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
361  * </ul>
362  */
363 public void setLocation (int x, int y) {
364         checkWidget ();
365         setLocationInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y));
366 }
367
368 void setLocationInPixels (int x, int y) {
369         this.x = x;
370         this.y = y;
371         hasLocation = true;
372         //TODO - update when visible
373 }
374
375 /**
376  * Sets the location of the receiver, which must be a tooltip,
377  * to the point specified by the argument which is relative
378  * to the display.
379  * <p>
380  * Note that this is different from most widgets where the
381  * location of the widget is relative to the parent.
382  * </p><p>
383  * Note that the platform window manager ultimately has control
384  * over the location of tooltips.
385  * </p>
386  *
387  * @param location the new location for the receiver
388  *
389  * @exception IllegalArgumentException <ul>
390  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
391  * </ul>
392  * @exception SWTException <ul>
393  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
394  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
395  * </ul>
396  */
397 public void setLocation (Point location) {
398         checkWidget ();
399         if (location == null) error (SWT.ERROR_NULL_ARGUMENT);
400         location = DPIUtil.autoScaleUp(location);
401         setLocationInPixels(location.x, location.y);
402 }
403
404 /**
405  * Sets the receiver's message.
406  *
407  * @param string the new message
408  *
409  * @exception IllegalArgumentException <ul>
410  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
411  * </ul>
412  * @exception SWTException <ul>
413  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
414  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
415  * </ul>
416  */
417 public void setMessage (String string) {
418         checkWidget ();
419         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
420         message = string;
421         updateMessage();
422 }
423
424 /**
425  * Sets the receiver's text.
426  *
427  * @param string the new text
428  *
429  * @exception IllegalArgumentException <ul>
430  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
431  * </ul>
432  * @exception SWTException <ul>
433  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
434  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
435  * </ul>
436  */
437 public void setText (String string) {
438         checkWidget ();
439         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
440         text = string;
441         //TODO - update when visible
442         //TODO - support text direction (?)
443 }
444
445 void updateMessage () {
446         long hwnd = hwndToolTip();
447         if (OS.SendMessage (hwnd, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
448                 TOOLINFO lpti = new TOOLINFO ();
449                 lpti.cbSize = TOOLINFO.sizeof;
450                 if (OS.SendMessage (hwnd, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
451                         if (message != null && message.length() > 0) {
452                                 long hHeap = OS.GetProcessHeap ();
453                                 TCHAR buffer = new TCHAR (0, message, true);
454                                 int byteCount = buffer.length () * TCHAR.sizeof;
455                                 lpti.lpszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
456                                 OS.MoveMemory (lpti.lpszText, buffer, byteCount);
457                                 OS.SendMessage (hwnd, OS.TTM_UPDATETIPTEXT, 0, lpti);
458                                 OS.HeapFree(hHeap, 0, lpti.lpszText);
459                         }
460                         else {
461                                 /*
462                                  * Bug 498895: When empty message string is set, then
463                                  * underlying native tool-tip object goes into dirty state &
464                                  * becomes unusable. Hence reset TOOLINFO#lpszText message
465                                  * text field to -1 (which is the default initial value of
466                                  * this field when fetch using TTM_GETCURRENTTOOL API call)
467                                  * to set empty message string at native level successfully.
468                                  */
469                                 lpti.lpszText =  -1;
470                                 OS.SendMessage (hwnd, OS.TTM_UPDATETIPTEXT, 0, lpti);
471                         }
472                 }
473         }
474 }
475
476 /**
477  * Marks the receiver as visible if the argument is <code>true</code>,
478  * and marks it invisible otherwise.
479  * <p>
480  * If one of the receiver's ancestors is not visible or some
481  * other condition makes the receiver not visible, marking
482  * it visible may not actually cause it to be displayed.
483  * </p>
484  *
485  * @param visible the new visibility state
486  *
487  * @exception SWTException <ul>
488  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
489  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
490  * </ul>
491  */
492 public void setVisible (boolean visible) {
493         checkWidget ();
494         if (visible == getVisible ()) return;
495         if (item == null) {
496                 long hwnd = parent.handle;
497                 TOOLINFO lpti = new TOOLINFO ();
498                 lpti.cbSize = TOOLINFO.sizeof;
499                 lpti.uId = id;
500                 lpti.hwnd = hwnd;
501                 long hwndToolTip = hwndToolTip ();
502                 Shell shell = parent.getShell ();
503                 if (text.length () != 0) {
504                         int icon = OS.TTI_NONE;
505                         if ((style & SWT.ICON_INFORMATION) != 0) icon = OS.TTI_INFO;
506                         if ((style & SWT.ICON_WARNING) != 0) icon = OS.TTI_WARNING;
507                         if ((style & SWT.ICON_ERROR) != 0) icon = OS.TTI_ERROR;
508                         shell.setToolTipTitle (hwndToolTip, text, icon);
509                 } else {
510                         shell.setToolTipTitle (hwndToolTip, null, 0);
511                 }
512                 OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, getWidth ());
513                 if (visible) {
514                         int nX = x, nY = y;
515                         if (!hasLocation) {
516                                 POINT pt = new POINT ();
517                                 if (OS.GetCursorPos (pt)) {
518                                         nX = pt.x;
519                                         nY = pt.y;
520                                 }
521                         }
522                         long lParam = OS.MAKELPARAM (nX, nY);
523                         OS.SendMessage (hwndToolTip, OS.TTM_TRACKPOSITION, 0, lParam);
524
525                         /*
526                         * Feature in Windows.  Windows will not show a tool tip
527                         * if the cursor is outside the parent window (even on XP,
528                         * TTM_POPUP will not do this).  The fix is to temporarily
529                         * move the cursor into the tool window, show the tool tip,
530                         * and then restore the cursor.
531                         */
532                         POINT pt = new POINT ();
533                         OS.GetCursorPos (pt);
534                         RECT rect = new RECT ();
535                         OS.GetClientRect (hwnd, rect);
536                         OS.MapWindowPoints (hwnd, 0, rect, 2);
537                         if (!OS.PtInRect (rect, pt)) {
538                                 long hCursor = OS.GetCursor ();
539                                 OS.SetCursor (0);
540                                 OS.SetCursorPos (rect.left, rect.top);
541                                 OS.SendMessage (hwndToolTip, OS.TTM_TRACKACTIVATE, 1, lpti);
542                                 OS.SetCursorPos (pt.x, pt.y);
543                                 OS.SetCursor (hCursor);
544                         } else {
545                                 OS.SendMessage (hwndToolTip, OS.TTM_TRACKACTIVATE, 1, lpti);
546                         }
547
548                         int time = (int)OS.SendMessage (hwndToolTip, OS.TTM_GETDELAYTIME, OS.TTDT_AUTOPOP, 0);
549                         OS.SetTimer (hwndToolTip, TIMER_ID, time, 0);
550                         updateMessage();
551                 } else {
552                         OS.SendMessage (hwndToolTip, OS.TTM_TRACKACTIVATE, 0, lpti);
553                         OS.SendMessage (hwndToolTip, OS.TTM_POP, 0, 0);
554                         OS.KillTimer (hwndToolTip, TIMER_ID);
555                 }
556                 return;
557         }
558         if (item != null) {
559                 if (visible) {
560                         NOTIFYICONDATA iconData = new NOTIFYICONDATA ();
561                         char [] szInfoTitle = iconData.szInfoTitle;
562                         int length1 = Math.min (szInfoTitle.length - 1, text.length ());
563                         text.getChars (0, length1, szInfoTitle, 0);
564                         char [] szInfo = iconData.szInfo;
565                         int length2 = Math.min (szInfo.length - 1, message.length ());
566                         message.getChars (0, length2, szInfo, 0);
567                         Display display = item.getDisplay ();
568                         iconData.cbSize = NOTIFYICONDATA.sizeof;
569                         iconData.uID = item.id;
570                         iconData.hWnd = display.hwndMessage;
571                         iconData.uFlags = OS.NIF_INFO;
572                         if ((style & SWT.ICON_INFORMATION) != 0) iconData.dwInfoFlags = OS.NIIF_INFO;
573                         if ((style & SWT.ICON_WARNING) != 0) iconData.dwInfoFlags = OS.NIIF_WARNING;
574                         if ((style & SWT.ICON_ERROR) != 0) iconData.dwInfoFlags = OS.NIIF_ERROR;
575                         sendEvent (SWT.Show);
576                         this.visible = OS.Shell_NotifyIcon (OS.NIM_MODIFY, iconData);
577                 } else {
578                         //TODO - hide the tray item
579                 }
580         }
581 }
582 }