KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > Link


1 /*******************************************************************************
2  * Copyright (c) 2000, 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  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13 import org.eclipse.swt.internal.win32.*;
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.graphics.*;
16 import org.eclipse.swt.events.*;
17 import org.eclipse.swt.accessibility.*;
18
19 /**
20  * Instances of this class represent a selectable
21  * user interface object that displays a text with
22  * links.
23  * <p>
24  * <dl>
25  * <dt><b>Styles:</b></dt>
26  * <dd>(none)</dd>
27  * <dt><b>Events:</b></dt>
28  * <dd>Selection</dd>
29  * </dl>
30  * <p>
31  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
32  * </p>
33  *
34  * @since 3.1
35  */

36 public class Link extends Control {
37     String JavaDoc text;
38     TextLayout layout;
39     Color linkColor, disabledColor;
40     Point [] offsets;
41     Point selection;
42     String JavaDoc [] ids;
43     int [] mnemonics;
44     int focusIndex, mouseDownIndex;
45     int font;
46     static final RGB LINK_FOREGROUND = new RGB (0, 51, 153);
47     static final int LinkProc;
48     static final TCHAR LinkClass = new TCHAR (0, OS.WC_LINK, true);
49     static {
50         if (OS.COMCTL32_MAJOR >= 6) {
51             WNDCLASS lpWndClass = new WNDCLASS ();
52             OS.GetClassInfo (0, LinkClass, lpWndClass);
53             LinkProc = lpWndClass.lpfnWndProc;
54         } else {
55             LinkProc = 0;
56         }
57     }
58     
59 /**
60  * Constructs a new instance of this class given its parent
61  * and a style value describing its behavior and appearance.
62  * <p>
63  * The style value is either one of the style constants defined in
64  * class <code>SWT</code> which is applicable to instances of this
65  * class, or must be built by <em>bitwise OR</em>'ing together
66  * (that is, using the <code>int</code> "|" operator) two or more
67  * of those <code>SWT</code> style constants. The class description
68  * lists the style constants that are applicable to the class.
69  * Style bits are also inherited from superclasses.
70  * </p>
71  *
72  * @param parent a composite control which will be the parent of the new instance (cannot be null)
73  * @param style the style of control to construct
74  *
75  * @exception IllegalArgumentException <ul>
76  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
77  * </ul>
78  * @exception SWTException <ul>
79  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
80  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
81  * </ul>
82  *
83  * @see Widget#checkSubclass
84  * @see Widget#getStyle
85  */

86 public Link (Composite parent, int style) {
87     super (parent, style);
88 }
89
90 /**
91  * Adds the listener to the collection of listeners who will
92  * be notified when the control is selected by the user, by sending
93  * it one of the messages defined in the <code>SelectionListener</code>
94  * interface.
95  * <p>
96  * <code>widgetSelected</code> is called when the control is selected by the user.
97  * <code>widgetDefaultSelected</code> is not called.
98  * </p>
99  *
100  * @param listener the listener which should be notified
101  *
102  * @exception IllegalArgumentException <ul>
103  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
104  * </ul>
105  * @exception SWTException <ul>
106  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
107  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
108  * </ul>
109  *
110  * @see SelectionListener
111  * @see #removeSelectionListener
112  * @see SelectionEvent
113  */

114 public void addSelectionListener (SelectionListener listener) {
115     checkWidget ();
116     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
117     TypedListener typedListener = new TypedListener (listener);
118     addListener (SWT.Selection, typedListener);
119     addListener (SWT.DefaultSelection, typedListener);
120 }
121
122 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
123     if (handle == 0) return 0;
124     if (LinkProc != 0) return OS.CallWindowProc (LinkProc, hwnd, msg, wParam, lParam);
125     return OS.DefWindowProc (hwnd, msg, wParam, lParam);
126 }
127
128 public Point computeSize (int wHint, int hHint, boolean changed) {
129     checkWidget ();
130     if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
131     if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
132     int width, height;
133     if (OS.COMCTL32_MAJOR >= 6) {
134         int hDC = OS.GetDC (handle);
135         int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
136         int oldFont = OS.SelectObject (hDC, newFont);
137         TCHAR buffer = new TCHAR (getCodePage (), parse (text), false);
138         RECT rect = new RECT ();
139         int flags = OS.DT_CALCRECT | OS.DT_NOPREFIX;
140         if (wHint != SWT.DEFAULT) {
141             flags |= OS.DT_WORDBREAK;
142             rect.right = wHint;
143         }
144         OS.DrawText (hDC, buffer, buffer.length (), rect, flags);
145         width = rect.right - rect.left;
146         height = rect.bottom;
147         if (newFont != 0) OS.SelectObject (hDC, oldFont);
148         OS.ReleaseDC (handle, hDC);
149     } else {
150         int layoutWidth = layout.getWidth ();
151         //TEMPORARY CODE
152
if (wHint == 0) {
153             layout.setWidth (1);
154             Rectangle rect = layout.getBounds ();
155             width = 0;
156             height = rect.height;
157         } else {
158             layout.setWidth (wHint);
159             Rectangle rect = layout.getBounds ();
160             width = rect.width;
161             height = rect.height;
162         }
163         layout.setWidth (layoutWidth);
164     }
165     if (wHint != SWT.DEFAULT) width = wHint;
166     if (hHint != SWT.DEFAULT) height = hHint;
167     int border = getBorderWidth ();
168     width += border * 2;
169     height += border * 2;
170     return new Point (width, height);
171 }
172
173 void createHandle () {
174     super.createHandle ();
175     state |= THEME_BACKGROUND;
176     if (OS.COMCTL32_MAJOR < 6) {
177         layout = new TextLayout (display);
178         if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
179             linkColor = Color.win32_new (display, OS.GetSysColor (OS.COLOR_HOTLIGHT));
180         } else {
181             linkColor = new Color (display, LINK_FOREGROUND);
182         }
183         disabledColor = Color.win32_new (display, OS.GetSysColor (OS.COLOR_GRAYTEXT));
184         offsets = new Point [0];
185         ids = new String JavaDoc [0];
186         mnemonics = new int [0];
187         selection = new Point (-1, -1);
188         focusIndex = mouseDownIndex = -1;
189     }
190 }
191
192 void createWidget () {
193     super.createWidget ();
194     text = "";
195     if (OS.COMCTL32_MAJOR < 6) {
196         if ((style & SWT.MIRRORED) != 0) {
197             layout.setOrientation (SWT.RIGHT_TO_LEFT);
198         }
199         initAccessible ();
200     }
201 }
202
203 void drawWidget (GC gc, RECT rect) {
204     drawBackground (gc.handle, rect);
205     int selStart = selection.x;
206     int selEnd = selection.y;
207     if (selStart > selEnd) {
208         selStart = selection.y;
209         selEnd = selection.x;
210     }
211     // temporary code to disable text selection
212
selStart = selEnd = -1;
213     if (!OS.IsWindowEnabled (handle)) gc.setForeground (disabledColor);
214     layout.draw (gc, 0, 0, selStart, selEnd, null, null);
215     if (hasFocus () && focusIndex != -1) {
216         Rectangle [] rects = getRectangles (focusIndex);
217         for (int i = 0; i < rects.length; i++) {
218             Rectangle rectangle = rects [i];
219             gc.drawFocus (rectangle.x, rectangle.y, rectangle.width, rectangle.height);
220         }
221     }
222     if (hooks (SWT.Paint) || filters (SWT.Paint)) {
223         Event event = new Event ();
224         event.gc = gc;
225         event.x = rect.left;
226         event.y = rect.top;
227         event.width = rect.right - rect.left;
228         event.height = rect.bottom - rect.top;
229         sendEvent (SWT.Paint, event);
230         event.gc = null;
231     }
232 }
233
234 void enableWidget (boolean enabled) {
235     if (OS.COMCTL32_MAJOR >= 6) {
236         LITEM item = new LITEM ();
237         item.mask = OS.LIF_ITEMINDEX | OS.LIF_STATE;
238         item.stateMask = OS.LIS_ENABLED;
239         item.state = enabled ? OS.LIS_ENABLED : 0;
240         while (OS.SendMessage (handle, OS.LM_SETITEM, 0, item) != 0) {
241             item.iLink++;
242         }
243     } else {
244         TextStyle linkStyle = new TextStyle (null, enabled ? linkColor : disabledColor, null);
245         linkStyle.underline = true;
246         for (int i = 0; i < offsets.length; i++) {
247             Point point = offsets [i];
248             layout.setStyle (linkStyle, point.x, point.y);
249         }
250         redraw ();
251     }
252     /*
253     * Feature in Windows. For some reason, setting
254     * LIS_ENABLED state using LM_SETITEM causes the
255     * SysLink to become enabled. To be specific,
256     * calling IsWindowEnabled() returns true. The
257     * fix is disable the SysLink after LM_SETITEM.
258     */

259     super.enableWidget (enabled);
260 }
261
262 void initAccessible () {
263     Accessible accessible = getAccessible ();
264     accessible.addAccessibleListener (new AccessibleAdapter () {
265         public void getName (AccessibleEvent e) {
266             e.result = parse (text);
267         }
268     });
269         
270     accessible.addAccessibleControlListener (new AccessibleControlAdapter () {
271         public void getChildAtPoint (AccessibleControlEvent e) {
272             e.childID = ACC.CHILDID_SELF;
273         }
274         
275         public void getLocation (AccessibleControlEvent e) {
276             Rectangle rect = display.map (getParent (), null, getBounds ());
277             e.x = rect.x;
278             e.y = rect.y;
279             e.width = rect.width;
280             e.height = rect.height;
281         }
282         
283         public void getChildCount (AccessibleControlEvent e) {
284             e.detail = 0;
285         }
286         
287         public void getRole (AccessibleControlEvent e) {
288             e.detail = ACC.ROLE_LINK;
289         }
290         
291         public void getState (AccessibleControlEvent e) {
292             e.detail = ACC.STATE_FOCUSABLE;
293             if (hasFocus ()) e.detail |= ACC.STATE_FOCUSED;
294         }
295         
296         public void getDefaultAction (AccessibleControlEvent e) {
297             e.result = SWT.getMessage ("SWT_Press"); //$NON-NLS-1$
298
}
299         
300         public void getSelection (AccessibleControlEvent e) {
301             if (hasFocus ()) e.childID = ACC.CHILDID_SELF;
302         }
303         
304         public void getFocus (AccessibleControlEvent e) {
305             if (hasFocus ()) e.childID = ACC.CHILDID_SELF;
306         }
307     });
308 }
309
310 String JavaDoc getNameText () {
311     return getText ();
312 }
313
314 Rectangle [] getRectangles (int linkIndex) {
315     int lineCount = layout.getLineCount ();
316     Rectangle [] rects = new Rectangle [lineCount];
317     int [] lineOffsets = layout.getLineOffsets ();
318     Point point = offsets [linkIndex];
319     int lineStart = 1;
320     while (point.x > lineOffsets [lineStart]) lineStart++;
321     int lineEnd = 1;
322     while (point.y > lineOffsets [lineEnd]) lineEnd++;
323     int index = 0;
324     if (lineStart == lineEnd) {
325         rects [index++] = layout.getBounds (point.x, point.y);
326     } else {
327         rects [index++] = layout.getBounds (point.x, lineOffsets [lineStart]-1);
328         rects [index++] = layout.getBounds (lineOffsets [lineEnd-1], point.y);
329         if (lineEnd - lineStart > 1) {
330             for (int i = lineStart; i < lineEnd - 1; i++) {
331                 rects [index++] = layout.getLineBounds (i);
332             }
333         }
334     }
335     if (rects.length != index) {
336         Rectangle [] tmp = new Rectangle [index];
337         System.arraycopy (rects, 0, tmp, 0, index);
338         rects = tmp;
339     }
340     return rects;
341 }
342
343 /**
344  * Returns the receiver's text, which will be an empty
345  * string if it has never been set.
346  *
347  * @return the receiver's text
348  *
349  * @exception SWTException <ul>
350  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
351  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
352  * </ul>
353  */

354 public String JavaDoc getText () {
355     checkWidget ();
356     return text;
357 }
358
359 String JavaDoc parse (String JavaDoc string) {
360     int length = string.length ();
361     offsets = new Point [length / 4];
362     ids = new String JavaDoc [length / 4];
363     mnemonics = new int [length / 4 + 1];
364     StringBuffer JavaDoc result = new StringBuffer JavaDoc ();
365     char [] buffer = new char [length];
366     string.getChars (0, string.length (), buffer, 0);
367     int index = 0, state = 0, linkIndex = 0;
368     int start = 0, tagStart = 0, linkStart = 0, endtagStart = 0, refStart = 0;
369     while (index < length) {
370         char c = Character.toLowerCase (buffer [index]);
371         switch (state) {
372             case 0:
373                 if (c == '<') {
374                     tagStart = index;
375                     state++;
376                 }
377                 break;
378             case 1:
379                 if (c == 'a') state++;
380                 break;
381             case 2:
382                 switch (c) {
383                     case 'h':
384                         state = 7;
385                         break;
386                     case '>':
387                         linkStart = index + 1;
388                         state++;
389                         break;
390                     default:
391                         if (Character.isWhitespace(c)) break;
392                         else state = 13;
393                 }
394                 break;
395             case 3:
396                 if (c == '<') {
397                     endtagStart = index;
398                     state++;
399                 }
400                 break;
401             case 4:
402                 state = c == '/' ? state + 1 : 3;
403                 break;
404             case 5:
405                 state = c == 'a' ? state + 1 : 3;
406                 break;
407             case 6:
408                 if (c == '>') {
409                     mnemonics [linkIndex] = parseMnemonics (buffer, start, tagStart, result);
410                     int offset = result.length ();
411                     parseMnemonics (buffer, linkStart, endtagStart, result);
412                     offsets [linkIndex] = new Point (offset, result.length () - 1);
413                     if (ids [linkIndex] == null) {
414                         ids [linkIndex] = new String JavaDoc (buffer, linkStart, endtagStart - linkStart);
415                     }
416                     linkIndex++;
417                     start = tagStart = linkStart = endtagStart = refStart = index + 1;
418                     state = 0;
419                 } else {
420                     state = 3;
421                 }
422                 break;
423             case 7:
424                 state = c == 'r' ? state + 1 : 0;
425                 break;
426             case 8:
427                 state = c == 'e' ? state + 1 : 0;
428                 break;
429             case 9:
430                 state = c == 'f' ? state + 1 : 0;
431                 break;
432             case 10:
433                 state = c == '=' ? state + 1 : 0;
434                 break;
435             case 11:
436                 if (c == '"') {
437                     state++;
438                     refStart = index + 1;
439                 } else {
440                     state = 0;
441                 }
442                 break;
443             case 12:
444                 if (c == '"') {
445                     ids[linkIndex] = new String JavaDoc (buffer, refStart, index - refStart);
446                     state = 2;
447                 }
448                 break;
449             case 13:
450                 if (Character.isWhitespace (c)) {
451                     state = 0;
452                 } else if (c == '='){
453                     state++;
454                 }
455                 break;
456             case 14:
457                 state = c == '"' ? state + 1 : 0;
458                 break;
459             case 15:
460                 if (c == '"') state = 2;
461                 break;
462             default:
463                 state = 0;
464                 break;
465         }
466         index++;
467     }
468     if (start < length) {
469         int tmp = parseMnemonics (buffer, start, tagStart, result);
470         int mnemonic = parseMnemonics (buffer, linkStart, index, result);
471         if (mnemonic == -1) mnemonic = tmp;
472         mnemonics [linkIndex] = mnemonic;
473     } else {
474         mnemonics [linkIndex] = -1;
475     }
476     if (offsets.length != linkIndex) {
477         Point [] newOffsets = new Point [linkIndex];
478         System.arraycopy (offsets, 0, newOffsets, 0, linkIndex);
479         offsets = newOffsets;
480         String JavaDoc [] newIDs = new String JavaDoc [linkIndex];
481         System.arraycopy (ids, 0, newIDs, 0, linkIndex);
482         ids = newIDs;
483         int [] newMnemonics = new int [linkIndex + 1];
484         System.arraycopy (mnemonics, 0, newMnemonics, 0, linkIndex + 1);
485         mnemonics = newMnemonics;
486     }
487     return result.toString ();
488 }
489
490 int parseMnemonics (char[] buffer, int start, int end, StringBuffer JavaDoc result) {
491     int mnemonic = -1, index = start;
492     while (index < end) {
493         if (buffer [index] == '&') {
494             if (index + 1 < end && buffer [index + 1] == '&') {
495                 result.append (buffer [index]);
496                 index++;
497             } else {
498                 mnemonic = result.length();
499             }
500         } else {
501             result.append (buffer [index]);
502         }
503         index++;
504     }
505     return mnemonic;
506 }
507
508 void releaseWidget () {
509     super.releaseWidget ();
510     if (layout != null) layout.dispose ();
511     layout = null;
512     if (linkColor != null) linkColor.dispose ();
513     linkColor = null;
514     disabledColor = null;
515     offsets = null;
516     ids = null;
517     mnemonics = null;
518     text = null;
519 }
520
521 /**
522  * Removes the listener from the collection of listeners who will
523  * be notified when the control is selected by the user.
524  *
525  * @param listener the listener which should no longer be notified
526  *
527  * @exception IllegalArgumentException <ul>
528  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
529  * </ul>
530  * @exception SWTException <ul>
531  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
532  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
533  * </ul>
534  *
535  * @see SelectionListener
536  * @see #addSelectionListener
537  */

538 public void removeSelectionListener (SelectionListener listener) {
539     checkWidget ();
540     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
541     if (eventTable == null) return;
542     eventTable.unhook (SWT.Selection, listener);
543     eventTable.unhook (SWT.DefaultSelection, listener);
544 }
545
546 /**
547  * Sets the receiver's text.
548  * <p>
549  * The string can contain both regular text and hyperlinks. A hyperlink
550  * is delimited by an anchor tag, &lt;A&gt; and &lt;/A&gt;. Within an
551  * anchor, a single HREF attribute is supported. When a hyperlink is
552  * selected, the text field of the selection event contains either the
553  * text of the hyperlink or the value of its HREF, if one was specified.
554  * In the rare case of identical hyperlinks within the same string, the
555  * HREF tag can be used to distinguish between them. The string may
556  * include the mnemonic character and line delimiters.
557  * </p>
558  *
559  * @param string the new text
560  *
561  * @exception IllegalArgumentException <ul>
562  * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
563  * </ul>
564  * @exception SWTException <ul>
565  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
566  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
567  * </ul>
568  */

569 public void setText (String JavaDoc string) {
570     checkWidget ();
571     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
572     if (string.equals (text)) return;
573     text = string;
574     if (OS.COMCTL32_MAJOR >= 6) {
575         boolean enabled = OS.IsWindowEnabled (handle);
576         /*
577         * Bug in Windows. For some reason, when SetWindowText()
578         * is used to set the text of a link control to the empty
579         * string, the old text remains. The fix is to set the
580         * text to a space instead.
581         */

582         if (string.length () == 0) string = " "; //$NON-NLS-1$
583
TCHAR buffer = new TCHAR (getCodePage (), string, true);
584         OS.SetWindowText (handle, buffer);
585         parse (text);
586         enableWidget (enabled);
587     } else {
588         layout.setText (parse (text));
589         focusIndex = offsets.length > 0 ? 0 : -1;
590         selection.x = selection.y = -1;
591         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
592         if (offsets.length > 0) {
593             bits |= OS.WS_TABSTOP;
594         } else {
595             bits &= ~OS.WS_TABSTOP;
596         }
597         OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
598         boolean enabled = OS.IsWindowEnabled (handle);
599         TextStyle linkStyle = new TextStyle (null, enabled ? linkColor : disabledColor, null);
600         linkStyle.underline = true;
601         for (int i = 0; i < offsets.length; i++) {
602             Point point = offsets [i];
603             layout.setStyle (linkStyle, point.x, point.y);
604         }
605         TextStyle mnemonicStyle = new TextStyle (null, null, null);
606         mnemonicStyle.underline = true;
607         for (int i = 0; i < mnemonics.length; i++) {
608             int mnemonic = mnemonics [i];
609             if (mnemonic != -1) {
610                 layout.setStyle (mnemonicStyle, mnemonic, mnemonic);
611             }
612         }
613         redraw ();
614     }
615 }
616
617 int widgetStyle () {
618     int bits = super.widgetStyle ();
619     return bits | OS.WS_TABSTOP;
620 }
621
622 TCHAR windowClass () {
623     return OS.COMCTL32_MAJOR >= 6 ? LinkClass : display.windowClass;
624 }
625
626 int windowProc () {
627     return LinkProc != 0 ? LinkProc : display.windowProc;
628 }
629
630 LRESULT WM_CHAR (int wParam, int lParam) {
631     LRESULT result = super.WM_CHAR (wParam, lParam);
632     if (result != null) return result;
633     if (OS.COMCTL32_MAJOR < 6) {
634         if (focusIndex == -1) return result;
635         switch (wParam) {
636             case ' ':
637             case SWT.CR:
638                 Event event = new Event ();
639                 event.text = ids [focusIndex];
640                 sendEvent (SWT.Selection, event);
641                 break;
642             case SWT.TAB:
643                 boolean next = OS.GetKeyState (OS.VK_SHIFT) >= 0;
644                 if (next) {
645                     if (focusIndex < offsets.length - 1) {
646                         focusIndex++;
647                         redraw ();
648                     }
649                 } else {
650                     if (focusIndex > 0) {
651                         focusIndex--;
652                         redraw ();
653                     }
654                 }
655                 break;
656         }
657     } else {
658         switch (wParam) {
659             case ' ':
660             case SWT.CR:
661             case SWT.TAB:
662                 /*
663                 * NOTE: Call the window proc with WM_KEYDOWN rather than WM_CHAR
664                 * so that the key that was ignored during WM_KEYDOWN is processed.
665                 * This allows the application to cancel an operation that is normally
666                 * performed in WM_KEYDOWN from WM_CHAR.
667                 */

668                 int code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
669                 return new LRESULT (code);
670         }
671         
672     }
673     return result;
674 }
675
676 LRESULT WM_GETDLGCODE (int wParam, int lParam) {
677     LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
678     if (result != null) return result;
679     int index, count, code = 0;
680     if (OS.COMCTL32_MAJOR >= 6) {
681         LITEM item = new LITEM ();
682         item.mask = OS.LIF_ITEMINDEX | OS.LIF_STATE;
683         item.stateMask = OS.LIS_FOCUSED;
684         index = 0;
685         while (OS.SendMessage (handle, OS.LM_GETITEM, 0, item) != 0) {
686             if ((item.state & OS.LIS_FOCUSED) != 0) {
687                 index = item.iLink;
688             }
689             item.iLink++;
690         }
691         count = item.iLink;
692         code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
693     } else {
694         index = focusIndex;
695         count = offsets.length;
696     }
697     if (count == 0) {
698         return new LRESULT (code | OS.DLGC_STATIC);
699     }
700     boolean next = OS.GetKeyState (OS.VK_SHIFT) >= 0;
701     if (next && index < count - 1) {
702         return new LRESULT (code | OS.DLGC_WANTTAB);
703     }
704     if (!next && index > 0) {
705         return new LRESULT (code | OS.DLGC_WANTTAB);
706     }
707     return result;
708 }
709
710 LRESULT WM_GETFONT (int wParam, int lParam) {
711     LRESULT result = super.WM_GETFONT (wParam, lParam);
712     if (result != null) return result;
713     int code = callWindowProc (handle, OS.WM_GETFONT, wParam, lParam);
714     if (code != 0) return new LRESULT (code);
715     if (font == 0) font = defaultFont ();
716     return new LRESULT (font);
717 }
718
719 LRESULT WM_KEYDOWN (int wParam, int lParam) {
720     LRESULT result = super.WM_KEYDOWN (wParam, lParam);
721     if (result != null) return result;
722     if (OS.COMCTL32_MAJOR >= 6) {
723         switch (wParam) {
724             case OS.VK_SPACE:
725             case OS.VK_RETURN:
726             case OS.VK_TAB:
727                 /*
728                 * Ensure that the window proc does not process VK_SPACE,
729                 * VK_RETURN or VK_TAB so that it can be handled in WM_CHAR.
730                 * This allows the application to cancel an operation that
731                 * is normally performed in WM_KEYDOWN from WM_CHAR.
732                 */

733                 return LRESULT.ZERO;
734         }
735     }
736     return result;
737 }
738
739 LRESULT WM_KILLFOCUS (int wParam, int lParam) {
740     LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
741     if (OS.COMCTL32_MAJOR < 6) redraw ();
742     return result;
743 }
744
745 LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
746     LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
747     if (result == LRESULT.ZERO) return result;
748     if (OS.COMCTL32_MAJOR < 6) {
749         if (focusIndex != -1) setFocus ();
750         int x = lParam & 0xFFFF;
751         int y = lParam >> 16;
752         int offset = layout.getOffset (x, y, null);
753         int oldSelectionX = selection.x;
754         int oldSelectionY = selection.y;
755         selection.x = offset;
756         selection.y = -1;
757         if (oldSelectionX != -1 && oldSelectionY != -1) {
758             if (oldSelectionX > oldSelectionY) {
759                 int temp = oldSelectionX;
760                 oldSelectionX = oldSelectionY;
761                 oldSelectionY = temp;
762             }
763             Rectangle rect = layout.getBounds (oldSelectionX, oldSelectionY);
764             redraw (rect.x, rect.y, rect.width, rect.height, false);
765         }
766         for (int j = 0; j < offsets.length; j++) {
767             Rectangle [] rects = getRectangles (j);
768             for (int i = 0; i < rects.length; i++) {
769                 Rectangle rect = rects [i];
770                 if (rect.contains (x, y)) {
771                     if (j != focusIndex) {
772                         redraw ();
773                     }
774                     focusIndex = mouseDownIndex = j;
775                     return result;
776                 }
777             }
778         }
779     }
780     return result;
781 }
782
783 LRESULT WM_LBUTTONUP (int wParam, int lParam) {
784     LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
785     if (result == LRESULT.ZERO) return result;
786     if (OS.COMCTL32_MAJOR < 6) {
787         if (mouseDownIndex == -1) return result;
788         int x = lParam & 0xFFFF;
789         int y = lParam >> 16;
790         Rectangle [] rects = getRectangles (mouseDownIndex);
791         for (int i = 0; i < rects.length; i++) {
792             Rectangle rect = rects [i];
793             if (rect.contains (x, y)) {
794                 Event event = new Event ();
795                 event.text = ids [mouseDownIndex];
796                 sendEvent (SWT.Selection, event);
797                 break;
798             }
799         }
800     }
801     mouseDownIndex = -1;
802     return result;
803 }
804
805 LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
806     LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
807     if (OS.COMCTL32_MAJOR < 6) {
808         int x = lParam & 0xFFFF;
809         int y = lParam >> 16;
810         if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
811             int oldSelection = selection.y;
812             selection.y = layout.getOffset (x, y, null);
813             if (selection.y != oldSelection) {
814                 int newSelection = selection.y;
815                 if (oldSelection > newSelection) {
816                     int temp = oldSelection;
817                     oldSelection = newSelection;
818                     newSelection = temp;
819                 }
820                 Rectangle rect = layout.getBounds (oldSelection, newSelection);
821                 redraw (rect.x, rect.y, rect.width, rect.height, false);
822             }
823         } else {
824             for (int j = 0; j < offsets.length; j++) {
825                 Rectangle [] rects = getRectangles (j);
826                 for (int i = 0; i < rects.length; i++) {
827                     Rectangle rect = rects [i];
828                     if (rect.contains (x, y)) {
829                         setCursor (display.getSystemCursor (SWT.CURSOR_HAND));
830                         return result;
831                     }
832                 }
833             }
834             setCursor (null);
835         }
836     }
837     return result;
838 }
839
840 LRESULT WM_PAINT (int wParam, int lParam) {
841     if (OS.COMCTL32_MAJOR >= 6) {
842         return super.WM_PAINT (wParam, lParam);
843     }
844     PAINTSTRUCT ps = new PAINTSTRUCT ();
845     GCData data = new GCData ();
846     data.ps = ps;
847     data.hwnd = handle;
848     GC gc = new_GC (data);
849     if (gc != null) {
850         int width = ps.right - ps.left;
851         int height = ps.bottom - ps.top;
852         if (width != 0 && height != 0) {
853             RECT rect = new RECT ();
854             OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
855             drawWidget (gc, rect);
856         }
857         gc.dispose ();
858     }
859     return LRESULT.ZERO;
860 }
861
862 LRESULT WM_PRINTCLIENT (int wParam, int lParam) {
863     LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
864     if (OS.COMCTL32_MAJOR < 6) {
865         RECT rect = new RECT ();
866         OS.GetClientRect (handle, rect);
867         GCData data = new GCData ();
868         data.device = display;
869         data.foreground = getForegroundPixel ();
870         GC gc = GC.win32_new (wParam, data);
871         drawWidget (gc, rect);
872         gc.dispose ();
873     }
874     return result;
875 }
876
877 LRESULT WM_SETFOCUS (int wParam, int lParam) {
878     LRESULT result = super.WM_SETFOCUS (wParam, lParam);
879     if (OS.COMCTL32_MAJOR < 6) redraw ();
880     return result;
881 }
882
883 LRESULT WM_SETFONT (int wParam, int lParam) {
884     if (OS.COMCTL32_MAJOR < 6) {
885         layout.setFont (Font.win32_new (display, wParam));
886     }
887     if (lParam != 0) OS.InvalidateRect (handle, null, true);
888     return super.WM_SETFONT (font = wParam, lParam);
889 }
890
891 LRESULT WM_SIZE (int wParam, int lParam) {
892     LRESULT result = super.WM_SIZE (wParam, lParam);
893     if (OS.COMCTL32_MAJOR < 6) {
894         RECT rect = new RECT ();
895         OS.GetClientRect (handle, rect);
896         layout.setWidth (rect.right > 0 ? rect.right : -1);
897         redraw ();
898     }
899     return result;
900 }
901
902 LRESULT wmColorChild (int wParam, int lParam) {
903     LRESULT result = super.wmColorChild (wParam, lParam);
904     /*
905     * Feature in Windows. When a SysLink is disabled, it does
906     * not gray out the non-link portion of the text. The fix
907     * is to set the text color to the system gray color.
908     */

909     if (OS.COMCTL32_MAJOR >= 6) {
910         if (!OS.IsWindowEnabled (handle)) {
911             OS.SetTextColor (wParam, OS.GetSysColor (OS.COLOR_GRAYTEXT));
912             if (result == null) {
913                 int backPixel = getBackgroundPixel ();
914                 OS.SetBkColor (wParam, backPixel);
915                 int hBrush = findBrush (backPixel, OS.BS_SOLID);
916                 return new LRESULT (hBrush);
917             }
918         }
919     }
920     return result;
921 }
922
923 LRESULT wmNotifyChild (NMHDR hdr, int wParam, int lParam) {
924     if (OS.COMCTL32_MAJOR >= 6) {
925         switch (hdr.code) {
926             case OS.NM_RETURN:
927             case OS.NM_CLICK:
928                 NMLINK item = new NMLINK ();
929                 OS.MoveMemory (item, lParam, NMLINK.sizeof);
930                 Event event = new Event ();
931                 event.text = ids [item.iLink];
932                 sendEvent (SWT.Selection, event);
933                 break;
934         }
935     }
936     return super.wmNotifyChild (hdr, wParam, lParam);
937 }
938 }
939
Popular Tags