]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/List.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / List.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 a selectable user interface
25  * object that displays a list of strings and issues notification
26  * when a string is selected.  A list may be single or multi select.
27  * <dl>
28  * <dt><b>Styles:</b></dt>
29  * <dd>SINGLE, MULTI</dd>
30  * <dt><b>Events:</b></dt>
31  * <dd>Selection, DefaultSelection</dd>
32  * </dl>
33  * <p>
34  * Note: Only one of SINGLE and MULTI 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/#list">List 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  * @noextend This class is not intended to be subclassed by clients.
43  */
44 public class List extends Scrollable {
45         static final int INSET = 3;
46         static final long ListProc;
47         static final TCHAR ListClass = new TCHAR (0, "LISTBOX", true);
48         boolean addedUCC = false; // indicates whether Bidi UCC were added; 'state & HAS_AUTO_DIRECTION' isn't a sufficient indicator
49         static {
50                 WNDCLASS lpWndClass = new WNDCLASS ();
51                 OS.GetClassInfo (0, ListClass, lpWndClass);
52                 ListProc = lpWndClass.lpfnWndProc;
53         }
54
55 /**
56  * Constructs a new instance of this class given its parent
57  * and a style value describing its behavior and appearance.
58  * <p>
59  * The style value is either one of the style constants defined in
60  * class <code>SWT</code> which is applicable to instances of this
61  * class, or must be built by <em>bitwise OR</em>'ing together
62  * (that is, using the <code>int</code> "|" operator) two or more
63  * of those <code>SWT</code> style constants. The class description
64  * lists the style constants that are applicable to the class.
65  * Style bits are also inherited from superclasses.
66  * </p>
67  *
68  * @param parent a composite control which will be the parent of the new instance (cannot be null)
69  * @param style the style of control to construct
70  *
71  * @exception IllegalArgumentException <ul>
72  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
73  * </ul>
74  * @exception SWTException <ul>
75  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
76  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
77  * </ul>
78  *
79  * @see SWT#SINGLE
80  * @see SWT#MULTI
81  * @see Widget#checkSubclass
82  * @see Widget#getStyle
83  */
84 public List (Composite parent, int style) {
85         super (parent, checkStyle (style));
86 }
87 /**
88  * Adds the argument to the end of the receiver's list.
89  * <p>
90  * Note: If control characters like '\n', '\t' etc. are used
91  * in the string, then the behavior is platform dependent.
92  * </p>
93  * @param string the new item
94  *
95  * @exception IllegalArgumentException <ul>
96  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
97  * </ul>
98  * @exception SWTException <ul>
99  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
100  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
101  * </ul>
102  *
103  * @see #add(String,int)
104  */
105 public void add (String string) {
106         checkWidget ();
107         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
108         TCHAR buffer = new TCHAR (getCodePage (), string, true);
109         int result = (int)OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
110         if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
111         if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
112         if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
113 }
114 /**
115  * Adds the argument to the receiver's list at the given
116  * zero-relative index.
117  * <p>
118  * Note: To add an item at the end of the list, use the
119  * result of calling <code>getItemCount()</code> as the
120  * index or use <code>add(String)</code>.
121  * </p><p>
122  * Also note, if control characters like '\n', '\t' etc. are used
123  * in the string, then the behavior is platform dependent.
124  * </p>
125  *
126  * @param string the new item
127  * @param index the index for the item
128  *
129  * @exception IllegalArgumentException <ul>
130  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
131  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
132  * </ul>
133  * @exception SWTException <ul>
134  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
135  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
136  * </ul>
137  *
138  * @see #add(String)
139  */
140 public void add (String string, int index) {
141         checkWidget ();
142         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
143         if (index == -1) error (SWT.ERROR_INVALID_RANGE);
144         TCHAR buffer = new TCHAR (getCodePage (), string, true);
145         int result = (int)OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer);
146         if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
147         if (result == OS.LB_ERR) {
148                 int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
149                 if (0 <= index && index <= count) {
150                         error (SWT.ERROR_ITEM_NOT_ADDED);
151                 } else {
152                         error (SWT.ERROR_INVALID_RANGE);
153                 }
154         }
155         if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer.chars, true);
156 }
157
158 /**
159  * Adds the listener to the collection of listeners who will
160  * be notified when the user changes the receiver's selection, by sending
161  * it one of the messages defined in the <code>SelectionListener</code>
162  * interface.
163  * <p>
164  * <code>widgetSelected</code> is called when the selection changes.
165  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
166  * </p>
167  *
168  * @param listener the listener which should be notified when the user changes the receiver's selection
169  *
170  * @exception IllegalArgumentException <ul>
171  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
172  * </ul>
173  * @exception SWTException <ul>
174  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
175  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
176  * </ul>
177  *
178  * @see SelectionListener
179  * @see #removeSelectionListener
180  * @see SelectionEvent
181  */
182 public void addSelectionListener(SelectionListener listener) {
183         checkWidget ();
184         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
185         TypedListener typedListener = new TypedListener (listener);
186         addListener (SWT.Selection,typedListener);
187         addListener (SWT.DefaultSelection,typedListener);
188 }
189
190 @Override
191 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
192         if (handle == 0) return 0;
193         boolean redraw = false;
194         switch (msg) {
195                 case OS.WM_HSCROLL:
196                 case OS.WM_VSCROLL: {
197                         redraw = findImageControl () != null && getDrawing() && OS.IsWindowVisible (handle);
198                         if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
199                         break;
200                 }
201         }
202         long code = OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam);
203         switch (msg) {
204                 case OS.WM_HSCROLL:
205                 case OS.WM_VSCROLL: {
206                         if (redraw) {
207                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
208                                 OS.InvalidateRect (handle, null, true);
209                         }
210                         break;
211                 }
212         }
213         return code;
214 }
215
216 static int checkStyle (int style) {
217         return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
218 }
219
220 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
221         checkWidget ();
222         int width = 0, height = 0;
223         if (wHint == SWT.DEFAULT) {
224                 if ((style & SWT.H_SCROLL) != 0) {
225                         width = (int)OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
226                         width -= INSET;
227                 } else {
228                         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
229                         long newFont, oldFont = 0;
230                         long hDC = OS.GetDC (handle);
231                         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
232                         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
233                         RECT rect = new RECT ();
234                         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
235                         char [] buffer = new char [64 + 1];
236                         for (int i=0; i<count; i++) {
237                                 int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
238                                 if (length != OS.LB_ERR) {
239                                         if (length + 1 > buffer.length) {
240                                                 buffer = new char [length + 1];
241                                         }
242                                         int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
243                                         if (result != OS.LB_ERR) {
244                                                 OS.DrawText (hDC, buffer, length, rect, flags);
245                                                 width = Math.max (width, rect.right - rect.left);
246                                         }
247                                 }
248                         }
249                         if (newFont != 0) OS.SelectObject (hDC, oldFont);
250                         OS.ReleaseDC (handle, hDC);
251                 }
252         }
253         if (hHint == SWT.DEFAULT) {
254                 int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
255                 int itemHeight = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
256                 height = count * itemHeight;
257         }
258         if (width == 0) width = DEFAULT_WIDTH;
259         if (height == 0) height = DEFAULT_HEIGHT;
260         if (wHint != SWT.DEFAULT) width = wHint;
261         if (hHint != SWT.DEFAULT) height = hHint;
262         int border = getBorderWidthInPixels ();
263         width += border * 2 + INSET;
264         height += border * 2;
265         if ((style & SWT.V_SCROLL) != 0) {
266                 width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
267         }
268         if ((style & SWT.H_SCROLL) != 0) {
269                 height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
270         }
271         return new Point (width, height);
272 }
273
274 @Override
275 int defaultBackground () {
276         return OS.GetSysColor (OS.COLOR_WINDOW);
277 }
278
279 /**
280  * Deselects the items at the given zero-relative indices in the receiver.
281  * If the item at the given zero-relative index in the receiver
282  * is selected, it is deselected.  If the item at the index
283  * was not selected, it remains deselected. Indices that are out
284  * of range and duplicate indices are ignored.
285  *
286  * @param indices the array of indices for the items to deselect
287  *
288  * @exception IllegalArgumentException <ul>
289  *    <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
290  * </ul>
291  * @exception SWTException <ul>
292  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
293  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
294  * </ul>
295  */
296 public void deselect (int [] indices) {
297         checkWidget ();
298         if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
299         if (indices.length == 0) return;
300         if ((style & SWT.SINGLE) != 0) {
301                 int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
302                 if (oldIndex == OS.LB_ERR) return;
303                 for (int i=0; i<indices.length; i++) {
304                         if (oldIndex == indices [i]) {
305                                 OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
306                                 return;
307                         }
308                 }
309                 return;
310         }
311         for (int i=0; i<indices.length; i++) {
312                 int index = indices [i];
313                 if (index != -1) {
314                         OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
315                 }
316         }
317 }
318
319 /**
320  * Deselects the item at the given zero-relative index in the receiver.
321  * If the item at the index was already deselected, it remains
322  * deselected. Indices that are out of range are ignored.
323  *
324  * @param index the index of the item to deselect
325  *
326  * @exception SWTException <ul>
327  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
328  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
329  * </ul>
330  */
331 public void deselect (int index) {
332         checkWidget ();
333         if (index == -1) return;
334         if ((style & SWT.SINGLE) != 0) {
335                 int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
336                 if (oldIndex == OS.LB_ERR) return;
337                 if (oldIndex == index) OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
338                 return;
339         }
340         OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
341 }
342
343 /**
344  * Deselects the items at the given zero-relative indices in the receiver.
345  * If the item at the given zero-relative index in the receiver
346  * is selected, it is deselected.  If the item at the index
347  * was not selected, it remains deselected.  The range of the
348  * indices is inclusive. Indices that are out of range are ignored.
349  *
350  * @param start the start index of the items to deselect
351  * @param end the end index of the items to deselect
352  *
353  * @exception SWTException <ul>
354  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
355  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
356  * </ul>
357  */
358 public void deselect (int start, int end) {
359         checkWidget ();
360         if (start > end) return;
361         if ((style & SWT.SINGLE) != 0) {
362                 int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
363                 if (oldIndex == OS.LB_ERR) return;
364                 if (start <= oldIndex && oldIndex <= end) {
365                         OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
366                 }
367                 return;
368         }
369         /*
370         * Ensure that at least one item is contained in
371         * the range from start to end.  Note that when
372         * start = end, LB_SELITEMRANGEEX deselects the
373         * item.
374         */
375         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
376         if (start < 0 && end < 0) return;
377         if (start >= count && end >= count) return;
378         start = Math.min (count - 1, Math.max (0, start));
379         end = Math.min (count - 1, Math.max (0, end));
380         OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start);
381 }
382
383 /**
384  * Deselects all selected items in the receiver.
385  *
386  * @exception SWTException <ul>
387  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
388  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
389  * </ul>
390  */
391 public void deselectAll () {
392         checkWidget ();
393         if ((style & SWT.SINGLE) != 0) {
394                 OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
395         } else {
396                 OS.SendMessage (handle, OS.LB_SETSEL, 0, -1);
397         }
398 }
399
400 /**
401  * Returns the zero-relative index of the item which currently
402  * has the focus in the receiver, or -1 if no item has focus.
403  *
404  * @return the index of the selected item
405  *
406  * @exception SWTException <ul>
407  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
408  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
409  * </ul>
410  */
411 public int getFocusIndex () {
412         checkWidget ();
413         int result = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
414         if (result == 0) {
415                 int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
416                 if (count == 0) return -1;
417         }
418         return result;
419 }
420
421 /**
422  * Returns the item at the given, zero-relative index in the
423  * receiver. Throws an exception if the index is out of range.
424  *
425  * @param index the index of the item to return
426  * @return the item at the given index
427  *
428  * @exception IllegalArgumentException <ul>
429  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
430  * </ul>
431  * @exception SWTException <ul>
432  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
433  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
434  * </ul>
435  */
436 public String getItem (int index) {
437         checkWidget ();
438         int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
439         if (length != OS.LB_ERR) {
440                 char [] buffer = new char [length + 1];
441                 int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
442                 if (result != OS.LB_ERR) return ((state & HAS_AUTO_DIRECTION) != 0) ? new String (buffer, 1, length - 1) : new String (buffer, 0, length);
443         }
444         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
445         if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
446         error (SWT.ERROR_INVALID_RANGE);
447         return "";
448 }
449
450 /**
451  * Returns the number of items contained in the receiver.
452  *
453  * @return the number of items
454  *
455  * @exception SWTException <ul>
456  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
457  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
458  * </ul>
459  */
460 public int getItemCount () {
461         checkWidget ();
462         int result = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
463         if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
464         return result;
465 }
466
467 /**
468  * Returns the height of the area which would be used to
469  * display <em>one</em> of the items in the list.
470  *
471  * @return the height of one item
472  *
473  * @exception SWTException <ul>
474  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
475  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
476  * </ul>
477  */
478 public int getItemHeight () {
479         checkWidget ();
480         return DPIUtil.autoScaleDown(getItemHeightInPixels());
481 }
482
483 int getItemHeightInPixels () {
484         int result = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
485         if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
486         return result;
487 }
488
489 /**
490  * Returns a (possibly empty) array of <code>String</code>s which
491  * are the items in the receiver.
492  * <p>
493  * Note: This is not the actual structure used by the receiver
494  * to maintain its list of items, so modifying the array will
495  * not affect the receiver.
496  * </p>
497  *
498  * @return the items in the receiver's list
499  *
500  * @exception SWTException <ul>
501  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
502  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
503  * </ul>
504  */
505 public String [] getItems () {
506         checkWidget ();
507         int count = getItemCount ();
508         String [] result = new String [count];
509         for (int i=0; i<count; i++) result [i] = getItem (i);
510         return result;
511 }
512
513 /**
514  * Returns an array of <code>String</code>s that are currently
515  * selected in the receiver.  The order of the items is unspecified.
516  * An empty array indicates that no items are selected.
517  * <p>
518  * Note: This is not the actual structure used by the receiver
519  * to maintain its selection, so modifying the array will
520  * not affect the receiver.
521  * </p>
522  * @return an array representing the selection
523  *
524  * @exception SWTException <ul>
525  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
526  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
527  * </ul>
528  */
529 public String [] getSelection () {
530         checkWidget ();
531         int [] indices = getSelectionIndices ();
532         String [] result = new String [indices.length];
533         for (int i=0; i<indices.length; i++) {
534                 result [i] = getItem (indices [i]);
535         }
536         return result;
537 }
538
539 /**
540  * Returns the number of selected items contained in the receiver.
541  *
542  * @return the number of selected items
543  *
544  * @exception SWTException <ul>
545  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
546  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
547  * </ul>
548  */
549 public int getSelectionCount () {
550         checkWidget ();
551         if ((style & SWT.SINGLE) != 0) {
552                 int result = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
553                 if (result == OS.LB_ERR) return 0;
554                 return 1;
555         }
556         int result = (int)OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
557         if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
558         return result;
559 }
560
561 /**
562  * Returns the zero-relative index of the item which is currently
563  * selected in the receiver, or -1 if no item is selected.
564  *
565  * @return the index of the selected item or -1
566  *
567  * @exception SWTException <ul>
568  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
569  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
570  * </ul>
571  */
572 public int getSelectionIndex () {
573         checkWidget ();
574         if ((style & SWT.SINGLE) != 0) {
575                 return (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
576         }
577         int count = (int)OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
578         if (count == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
579         if (count == 0) return -1;
580         int index = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
581         int result = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
582         if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
583         if (result != 0) return index;
584         int [] buffer = new int[1];
585         result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer);
586         if (result != 1) error (SWT.ERROR_CANNOT_GET_SELECTION);
587         return buffer [0];
588 }
589
590 /**
591  * Returns the zero-relative indices of the items which are currently
592  * selected in the receiver.  The order of the indices is unspecified.
593  * The array is empty if no items are selected.
594  * <p>
595  * Note: This is not the actual structure used by the receiver
596  * to maintain its selection, so modifying the array will
597  * not affect the receiver.
598  * </p>
599  * @return the array of indices of the selected items
600  *
601  * @exception SWTException <ul>
602  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
603  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
604  * </ul>
605  */
606 public int [] getSelectionIndices () {
607         checkWidget ();
608         if ((style & SWT.SINGLE) != 0) {
609                 int result = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
610                 if (result == OS.LB_ERR) return new int [0];
611                 return new int [] {result};
612         }
613         int length = (int)OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
614         if (length == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
615         int [] indices = new int [length];
616         int result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices);
617         if (result != length) error (SWT.ERROR_CANNOT_GET_SELECTION);
618         return indices;
619 }
620
621 /**
622  * Returns the zero-relative index of the item which is currently
623  * at the top of the receiver. This index can change when items are
624  * scrolled or new items are added or removed.
625  *
626  * @return the index of the top item
627  *
628  * @exception SWTException <ul>
629  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
630  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
631  * </ul>
632  */
633 public int getTopIndex () {
634         checkWidget ();
635         return (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
636 }
637
638 /**
639  * Gets the index of an item.
640  * <p>
641  * The list is searched starting at 0 until an
642  * item is found that is equal to the search item.
643  * If no item is found, -1 is returned.  Indexing
644  * is zero based.
645  *
646  * @param string the search item
647  * @return the index of the item
648  *
649  * @exception IllegalArgumentException <ul>
650  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
651  * </ul>
652  * @exception SWTException <ul>
653  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
654  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
655  * </ul>
656  */
657 public int indexOf (String string) {
658         return indexOf (string, 0);
659 }
660
661 /**
662  * Searches the receiver's list starting at the given,
663  * zero-relative index until an item is found that is equal
664  * to the argument, and returns the index of that item. If
665  * no item is found or the starting index is out of range,
666  * returns -1.
667  *
668  * @param string the search item
669  * @param start the zero-relative index at which to start the search
670  * @return the index of the item
671  *
672  * @exception IllegalArgumentException <ul>
673  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
674  * </ul>
675  * @exception SWTException <ul>
676  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
677  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
678  * </ul>
679  */
680 public int indexOf (String string, int start) {
681         checkWidget ();
682         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
683
684         /*
685         * Bug in Windows.  For some reason, LB_FINDSTRINGEXACT
686         * will not find empty strings even though it is legal
687         * to insert an empty string into a list.  The fix is
688         * to search the list, an item at a time.
689         */
690         if (string.length () == 0) {
691                 int count = getItemCount ();
692                 for (int i=start; i<count; i++) {
693                         if (string.equals (getItem (i))) return i;
694                 }
695                 return -1;
696         }
697
698         /* Use LB_FINDSTRINGEXACT to search for the item */
699         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
700         if (!(0 <= start && start < count)) return -1;
701         int index = start - 1, last;
702         TCHAR buffer = new TCHAR (getCodePage (), string, true);
703         do {
704                 index = (int)OS.SendMessage (handle, OS.LB_FINDSTRINGEXACT, last = index, buffer);
705                 if (index == OS.LB_ERR || index <= last) return -1;
706         } while (!string.equals (getItem (index)));
707         return index;
708 }
709
710 /**
711  * Returns <code>true</code> if the item is selected,
712  * and <code>false</code> otherwise.  Indices out of
713  * range are ignored.
714  *
715  * @param index the index of the item
716  * @return the selection state of the item at the index
717  *
718  * @exception SWTException <ul>
719  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
720  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
721  * </ul>
722  */
723 public boolean isSelected (int index) {
724         checkWidget ();
725         int result = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
726         return (result != 0) && (result != OS.LB_ERR);
727 }
728
729 /**
730  * Removes the items from the receiver at the given
731  * zero-relative indices.
732  *
733  * @param indices the array of indices of the items
734  *
735  * @exception IllegalArgumentException <ul>
736  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
737  *    <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
738  * </ul>
739  * @exception SWTException <ul>
740  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
741  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
742  * </ul>
743  */
744 public void remove (int [] indices) {
745         checkWidget ();
746         if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
747         if (indices.length == 0) return;
748         int [] newIndices = new int [indices.length];
749         System.arraycopy (indices, 0, newIndices, 0, indices.length);
750         sort (newIndices);
751         int start = newIndices [newIndices.length - 1], end = newIndices [0];
752         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
753         if (!(0 <= start && start <= end && end < count)) {
754                 error (SWT.ERROR_INVALID_RANGE);
755         }
756         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
757         RECT rect = null;
758         long hDC = 0, oldFont = 0, newFont = 0;
759         int newWidth = 0;
760         if ((style & SWT.H_SCROLL) != 0) {
761                 rect = new RECT ();
762                 hDC = OS.GetDC (handle);
763                 newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
764                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
765         }
766         int i = 0, topCount = 0, last = -1;
767         while (i < newIndices.length) {
768                 int index = newIndices [i];
769                 if (index != last) {
770                         char [] buffer = null;
771                         int length = 0;
772                         if ((style & SWT.H_SCROLL) != 0) {
773                                 length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
774                                 if (length == OS.LB_ERR) break;
775                                 buffer = new char [length + 1];
776                                 int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
777                                 if (result == OS.LB_ERR) break;
778                         }
779                         int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
780                         if (result == OS.LB_ERR) break;
781                         if ((style & SWT.H_SCROLL) != 0) {
782                                 int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
783                                 OS.DrawText (hDC, buffer, length, rect, flags);
784                                 newWidth = Math.max (newWidth, rect.right - rect.left);
785                         }
786                         if (index < topIndex) topCount++;
787                         last = index;
788                 }
789                 i++;
790         }
791         if ((style & SWT.H_SCROLL) != 0) {
792                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
793                 OS.ReleaseDC (handle, hDC);
794                 setScrollWidth (newWidth, false);
795         }
796         if (topCount > 0) {
797                 topIndex -= topCount;
798         }
799         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
800         if (i < newIndices.length) error (SWT.ERROR_ITEM_NOT_REMOVED);
801 }
802
803 /**
804  * Removes the item from the receiver at the given
805  * zero-relative index.
806  *
807  * @param index the index for the item
808  *
809  * @exception IllegalArgumentException <ul>
810  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
811  * </ul>
812  * @exception SWTException <ul>
813  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
814  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
815  * </ul>
816  */
817 public void remove (int index) {
818         checkWidget ();
819         char [] buffer = null;
820         if ((style & SWT.H_SCROLL) != 0) {
821                 int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
822                 if (length == OS.LB_ERR) {
823                         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
824                         if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
825                         error (SWT.ERROR_INVALID_RANGE);
826                 }
827                 buffer = new char [length + 1];
828                 int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
829                 if (result == OS.LB_ERR) {
830                         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
831                         if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
832                         error (SWT.ERROR_INVALID_RANGE);
833                 }
834         }
835         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
836         int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
837         if (result == OS.LB_ERR) {
838                 int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
839                 if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
840                 error (SWT.ERROR_INVALID_RANGE);
841         }
842         if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, false);
843         if (index < topIndex) {
844                 topIndex -= 1;
845         }
846         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
847 }
848
849 /**
850  * Removes the items from the receiver which are
851  * between the given zero-relative start and end
852  * indices (inclusive).
853  *
854  * @param start the start of the range
855  * @param end the end of the range
856  *
857  * @exception IllegalArgumentException <ul>
858  *    <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
859  * </ul>
860  * @exception SWTException <ul>
861  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
862  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
863  * </ul>
864  */
865 public void remove (int start, int end) {
866         checkWidget ();
867         if (start > end) return;
868         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
869         if (!(0 <= start && start <= end && end < count)) {
870                 error (SWT.ERROR_INVALID_RANGE);
871         }
872         if (start == 0 && end == count - 1) {
873                 removeAll ();
874                 return;
875         }
876         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
877         RECT rect = null;
878         long hDC = 0, oldFont = 0, newFont = 0;
879         int newWidth = 0;
880         if ((style & SWT.H_SCROLL) != 0) {
881                 rect = new RECT ();
882                 hDC = OS.GetDC (handle);
883                 newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
884                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
885         }
886         int index = start;
887         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
888         while (index <= end) {
889                 char [] buffer = null;
890                 int length = 0;
891                 if ((style & SWT.H_SCROLL) != 0) {
892                         length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0);
893                         if (length == OS.LB_ERR) break;
894                         buffer = new char [length + 1];
895                         int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer);
896                         if (result == OS.LB_ERR) break;
897                 }
898                 int result = (int)OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0);
899                 if (result == OS.LB_ERR) break;
900                 if ((style & SWT.H_SCROLL) != 0) {
901                         OS.DrawText (hDC, buffer, length, rect, flags);
902                         newWidth = Math.max (newWidth, rect.right - rect.left);
903                 }
904                 index++;
905         }
906         if ((style & SWT.H_SCROLL) != 0) {
907                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
908                 OS.ReleaseDC (handle, hDC);
909                 setScrollWidth (newWidth, false);
910         }
911         if (end < topIndex) {
912                 topIndex -= end - start + 1;
913         }
914         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
915         if (index <= end) error (SWT.ERROR_ITEM_NOT_REMOVED);
916 }
917
918 /**
919  * Searches the receiver's list starting at the first item
920  * until an item is found that is equal to the argument,
921  * and removes that item from the list.
922  *
923  * @param string the item to remove
924  *
925  * @exception IllegalArgumentException <ul>
926  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
927  *    <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
928  * </ul>
929  * @exception SWTException <ul>
930  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
931  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
932  * </ul>
933  */
934 public void remove (String string) {
935         checkWidget ();
936         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
937         int index = indexOf (string, 0);
938         if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
939         remove (index);
940 }
941
942 /**
943  * Removes all of the items from the receiver.
944  * 
945  * @exception SWTException <ul>
946  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
947  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
948  * </ul>
949  */
950 public void removeAll () {
951         checkWidget ();
952         OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
953         if ((style & SWT.H_SCROLL) != 0) {
954                 OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
955         }
956 }
957
958 /**
959  * Removes the listener from the collection of listeners who will
960  * be notified when the user changes the receiver's selection.
961  *
962  * @param listener the listener which should no longer be notified
963  *
964  * @exception IllegalArgumentException <ul>
965  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
966  * </ul>
967  * @exception SWTException <ul>
968  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
969  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
970  * </ul>
971  *
972  * @see SelectionListener
973  * @see #addSelectionListener
974  */
975 public void removeSelectionListener(SelectionListener listener) {
976         checkWidget ();
977         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
978         if (eventTable == null) return;
979         eventTable.unhook (SWT.Selection, listener);
980         eventTable.unhook (SWT.DefaultSelection,listener);
981 }
982
983 /**
984  * Selects the items at the given zero-relative indices in the receiver.
985  * The current selection is not cleared before the new items are selected.
986  * <p>
987  * If the item at a given index is not selected, it is selected.
988  * If the item at a given index was already selected, it remains selected.
989  * Indices that are out of range and duplicate indices are ignored.
990  * If the receiver is single-select and multiple indices are specified,
991  * then all indices are ignored.
992  *
993  * @param indices the array of indices for the items to select
994  *
995  * @exception IllegalArgumentException <ul>
996  *    <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
997  * </ul>
998  * @exception SWTException <ul>
999  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1000  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1001  * </ul>
1002  *
1003  * @see List#setSelection(int[])
1004  */
1005 public void select (int [] indices) {
1006         checkWidget ();
1007         if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
1008         int length = indices.length;
1009         if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1010         select (indices, false);
1011 }
1012
1013 void select (int [] indices, boolean scroll) {
1014         int i = 0;
1015         while (i < indices.length) {
1016                 int index = indices [i];
1017                 if (index != -1) {
1018                         select (index, false);
1019                 }
1020                 i++;
1021         }
1022         if (scroll) showSelection ();
1023 }
1024
1025 /**
1026  * Selects the item at the given zero-relative index in the receiver's
1027  * list.  If the item at the index was already selected, it remains
1028  * selected. Indices that are out of range are ignored.
1029  *
1030  * @param index the index of the item to select
1031  *
1032  * @exception SWTException <ul>
1033  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1034  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1035  * </ul>
1036  */
1037 public void select (int index) {
1038         checkWidget ();
1039         select (index, false);
1040 }
1041
1042 void select (int index, boolean scroll) {
1043         if (index < 0) return;
1044         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1045         if (index >= count) return;
1046         if (scroll) {
1047                 if ((style & SWT.SINGLE) != 0) {
1048                         OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
1049                 } else {
1050                         OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
1051                 }
1052                 return;
1053         }
1054         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1055         RECT itemRect = new RECT (), selectedRect = null;
1056         OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect);
1057         boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
1058         if (redraw) {
1059                 OS.UpdateWindow (handle);
1060                 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
1061         }
1062         int focusIndex = -1;
1063         if ((style & SWT.SINGLE) != 0) {
1064                 int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
1065                 if (oldIndex != -1) {
1066                         selectedRect = new RECT ();
1067                         OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect);
1068                 }
1069                 OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
1070         } else {
1071                 focusIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1072                 OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
1073         }
1074         if ((style & SWT.MULTI) != 0) {
1075                 if (focusIndex != -1) {
1076                         OS.SendMessage (handle, OS.LB_SETCARETINDEX, focusIndex, 0);
1077                 }
1078         }
1079         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
1080         if (redraw) {
1081                 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
1082                 OS.ValidateRect (handle, null);
1083                 OS.InvalidateRect (handle, itemRect, true);
1084                 if (selectedRect != null) {
1085                         OS.InvalidateRect (handle, selectedRect, true);
1086                 }
1087         }
1088 }
1089
1090 /**
1091  * Selects the items in the range specified by the given zero-relative
1092  * indices in the receiver. The range of indices is inclusive.
1093  * The current selection is not cleared before the new items are selected.
1094  * <p>
1095  * If an item in the given range is not selected, it is selected.
1096  * If an item in the given range was already selected, it remains selected.
1097  * Indices that are out of range are ignored and no items will be selected
1098  * if start is greater than end.
1099  * If the receiver is single-select and there is more than one item in the
1100  * given range, then all indices are ignored.
1101  *
1102  * @param start the start of the range
1103  * @param end the end of the range
1104  *
1105  * @exception SWTException <ul>
1106  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1107  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1108  * </ul>
1109  *
1110  * @see List#setSelection(int,int)
1111  */
1112 public void select (int start, int end) {
1113         checkWidget ();
1114         if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
1115         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1116         if (count == 0 || start >= count) return;
1117         start = Math.max (0, start);
1118         end = Math.min (end, count - 1);
1119         if ((style & SWT.SINGLE) != 0) {
1120                 select (start, false);
1121         } else {
1122                 select (start, end, false);
1123         }
1124 }
1125
1126 void select (int start, int end, boolean scroll) {
1127         /*
1128         * Note that when start = end, LB_SELITEMRANGEEX
1129         * deselects the item.
1130         */
1131         if (start == end) {
1132                 select (start, scroll);
1133                 return;
1134         }
1135         OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end);
1136         if (scroll) showSelection ();
1137 }
1138
1139 /**
1140  * Selects all of the items in the receiver.
1141  * <p>
1142  * If the receiver is single-select, do nothing.
1143  *
1144  * @exception SWTException <ul>
1145  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1146  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1147  * </ul>
1148  */
1149 public void selectAll () {
1150         checkWidget ();
1151         if ((style & SWT.SINGLE) != 0) return;
1152         OS.SendMessage (handle, OS.LB_SETSEL, 1, -1);
1153 }
1154
1155 void setFocusIndex (int index) {
1156 //      checkWidget ();
1157         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1158         if (!(0 <= index && index < count)) return;
1159         OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
1160 }
1161
1162 @Override
1163 public void setFont (Font font) {
1164         checkWidget ();
1165         super.setFont (font);
1166         if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
1167 }
1168
1169 /**
1170  * Sets the text of the item in the receiver's list at the given
1171  * zero-relative index to the string argument.
1172  *
1173  * @param index the index for the item
1174  * @param string the new text for the item
1175  *
1176  * @exception IllegalArgumentException <ul>
1177  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1178  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1179  * </ul>
1180  * @exception SWTException <ul>
1181  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1182  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1183  * </ul>
1184  */
1185 public void setItem (int index, String string) {
1186         checkWidget ();
1187         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1188         int topIndex = getTopIndex ();
1189         boolean isSelected = isSelected (index);
1190         remove (index);
1191         add (string, index);
1192         if (isSelected) select (index, false);
1193         setTopIndex (topIndex);
1194 }
1195
1196 /**
1197  * Sets the receiver's items to be the given array of items.
1198  *
1199  * @param items the array of items
1200  *
1201  * @exception IllegalArgumentException <ul>
1202  *    <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1203  *    <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1204  * </ul>
1205  * @exception SWTException <ul>
1206  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1207  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1208  * </ul>
1209  */
1210 public void setItems (String... items) {
1211         checkWidget ();
1212         if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1213         for (int i=0; i<items.length; i++) {
1214                 if (items [i] == null) error (SWT.ERROR_INVALID_ARGUMENT);
1215         }
1216         long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
1217         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, ListProc);
1218         boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
1219         if (redraw) {
1220                 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
1221         }
1222         RECT rect = null;
1223         long hDC = 0, oldFont = 0, newFont = 0;
1224         int newWidth = 0;
1225         if ((style & SWT.H_SCROLL) != 0) {
1226                 rect = new RECT ();
1227                 hDC = OS.GetDC (handle);
1228                 newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1229                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1230                 OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
1231         }
1232         int length = items.length;
1233         OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
1234         OS.SendMessage (handle, OS.LB_INITSTORAGE, length, length * 32);
1235         int index = 0;
1236         int cp = getCodePage ();
1237         while (index < length) {
1238                 String string = items [index];
1239                 TCHAR buffer = new TCHAR (cp, string, true);
1240                 int result = (int)OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
1241                 if (result == OS.LB_ERR || result == OS.LB_ERRSPACE) break;
1242                 if ((style & SWT.H_SCROLL) != 0) {
1243                         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1244                         OS.DrawText (hDC, buffer, -1, rect, flags);
1245                         newWidth = Math.max (newWidth, rect.right - rect.left);
1246                 }
1247                 index++;
1248         }
1249         if ((style & SWT.H_SCROLL) != 0) {
1250                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
1251                 OS.ReleaseDC (handle, hDC);
1252                 OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0);
1253         }
1254         if (redraw) {
1255                 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
1256                 /*
1257                 * This code is intentionally commented.  The window proc
1258                 * for the list box implements WM_SETREDRAW to invalidate
1259                 * and erase the widget.  This is undocumented behavior.
1260                 * The commented code below shows what is actually happening
1261                 * and reminds us that we are relying on this undocumented
1262                 * behavior.
1263                 */
1264 //              int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
1265 //              OS.RedrawWindow (handle, null, 0, flags);
1266         }
1267         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
1268         if (index < items.length) error (SWT.ERROR_ITEM_NOT_ADDED);
1269 }
1270
1271 void setScrollWidth () {
1272         int newWidth = 0;
1273         RECT rect = new RECT ();
1274         long newFont, oldFont = 0;
1275         long hDC = OS.GetDC (handle);
1276         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1277         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1278         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1279         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1280         for (int i=0; i<count; i++) {
1281                 int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
1282                 if (length != OS.LB_ERR) {
1283                         char [] buffer = new char [length + 1];
1284                         int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
1285                         if (result != OS.LB_ERR) {
1286                                 OS.DrawText (hDC, buffer, length, rect, flags);
1287                                 newWidth = Math.max (newWidth, rect.right - rect.left);
1288                         }
1289                 }
1290         }
1291         if (newFont != 0) OS.SelectObject (hDC, oldFont);
1292         OS.ReleaseDC (handle, hDC);
1293         OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0);
1294 }
1295
1296 void setScrollWidth (char[] buffer, boolean grow) {
1297         RECT rect = new RECT ();
1298         long newFont, oldFont = 0;
1299         long hDC = OS.GetDC (handle);
1300         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1301         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1302         int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1303         OS.DrawText (hDC, buffer, -1, rect, flags);
1304         if (newFont != 0) OS.SelectObject (hDC, oldFont);
1305         OS.ReleaseDC (handle, hDC);
1306         setScrollWidth (rect.right - rect.left, grow);
1307 }
1308
1309 void setScrollWidth (int newWidth, boolean grow) {
1310         newWidth += INSET;
1311         int width = (int)OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
1312         if (grow) {
1313                 if (newWidth <= width) return;
1314                 OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth, 0);
1315         } else {
1316                 if (newWidth < width) return;
1317                 setScrollWidth ();
1318         }
1319 }
1320
1321 /**
1322  * Selects the items at the given zero-relative indices in the receiver.
1323  * The current selection is cleared before the new items are selected,
1324  * and if necessary the receiver is scrolled to make the new selection visible.
1325  * <p>
1326  * Indices that are out of range and duplicate indices are ignored.
1327  * If the receiver is single-select and multiple indices are specified,
1328  * then all indices are ignored.
1329  *
1330  * @param indices the indices of the items to select
1331  *
1332  * @exception IllegalArgumentException <ul>
1333  *    <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1334  * </ul>
1335  * @exception SWTException <ul>
1336  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1337  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1338  * </ul>
1339  *
1340  * @see List#deselectAll()
1341  * @see List#select(int[])
1342  */
1343 public void setSelection(int [] indices) {
1344         checkWidget ();
1345         if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
1346         deselectAll ();
1347         int length = indices.length;
1348         if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1349         select (indices, true);
1350         if ((style & SWT.MULTI) != 0) {
1351                 int focusIndex = indices [0];
1352                 if (focusIndex >= 0) setFocusIndex (focusIndex);
1353         }
1354 }
1355
1356 /**
1357  * Sets the receiver's selection to be the given array of items.
1358  * The current selection is cleared before the new items are selected,
1359  * and if necessary the receiver is scrolled to make the new selection visible.
1360  * <p>
1361  * Items that are not in the receiver are ignored.
1362  * If the receiver is single-select and multiple items are specified,
1363  * then all items are ignored.
1364  *
1365  * @param items the array of items
1366  *
1367  * @exception IllegalArgumentException <ul>
1368  *    <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
1369  * </ul>
1370  * @exception SWTException <ul>
1371  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1372  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1373  * </ul>
1374  *
1375  * @see List#deselectAll()
1376  * @see List#select(int[])
1377  * @see List#setSelection(int[])
1378  */
1379 public void setSelection (String [] items) {
1380         checkWidget ();
1381         if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1382         deselectAll ();
1383         int length = items.length;
1384         if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1385         int focusIndex = -1;
1386         for (int i=length-1; i>=0; --i) {
1387                 String string = items [i];
1388                 int index = 0;
1389                 if (string != null) {
1390                         int localFocus = -1;
1391                         while ((index = indexOf (string, index)) != -1) {
1392                                 if (localFocus == -1) localFocus = index;
1393                                 select (index, false);
1394                                 if ((style & SWT.SINGLE) != 0 && isSelected (index)) {
1395                                         showSelection ();
1396                                         return;
1397                                 }
1398                                 index++;
1399                         }
1400                         if (localFocus != -1) focusIndex = localFocus;
1401                 }
1402         }
1403         if ((style & SWT.MULTI) != 0) {
1404                 if (focusIndex >= 0) setFocusIndex (focusIndex);
1405         }
1406 }
1407
1408 /**
1409  * Selects the item at the given zero-relative index in the receiver.
1410  * If the item at the index was already selected, it remains selected.
1411  * The current selection is first cleared, then the new item is selected,
1412  * and if necessary the receiver is scrolled to make the new selection visible.
1413  * Indices that are out of range are ignored.
1414  *
1415  * @param index the index of the item to select
1416  *
1417  * @exception SWTException <ul>
1418  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1419  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1420  * </ul>
1421  * @see List#deselectAll()
1422  * @see List#select(int)
1423  */
1424 public void setSelection (int index) {
1425         checkWidget ();
1426         deselectAll ();
1427         select (index, true);
1428         if ((style & SWT.MULTI) != 0) {
1429                 if (index >= 0) setFocusIndex (index);
1430         }
1431 }
1432
1433 /**
1434  * Selects the items in the range specified by the given zero-relative
1435  * indices in the receiver. The range of indices is inclusive.
1436  * The current selection is cleared before the new items are selected,
1437  * and if necessary the receiver is scrolled to make the new selection visible.
1438  * <p>
1439  * Indices that are out of range are ignored and no items will be selected
1440  * if start is greater than end.
1441  * If the receiver is single-select and there is more than one item in the
1442  * given range, then all indices are ignored.
1443  *
1444  * @param start the start index of the items to select
1445  * @param end the end index of the items to select
1446  *
1447  * @exception SWTException <ul>
1448  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1449  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1450  * </ul>
1451  *
1452  * @see List#deselectAll()
1453  * @see List#select(int,int)
1454  */
1455 public void setSelection (int start, int end) {
1456         checkWidget ();
1457         deselectAll ();
1458         if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
1459         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1460         if (count == 0 || start >= count) return;
1461         start = Math.max (0, start);
1462         end = Math.min (end, count - 1);
1463         if ((style & SWT.SINGLE) != 0) {
1464                 select (start, true);
1465         } else {
1466                 select (start, end, true);
1467                 setFocusIndex (start);
1468         }
1469 }
1470
1471 /**
1472  * Sets the zero-relative index of the item which is currently
1473  * at the top of the receiver. This index can change when items
1474  * are scrolled or new items are added and removed.
1475  *
1476  * @param index the index of the top item
1477  *
1478  * @exception SWTException <ul>
1479  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1480  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1481  * </ul>
1482  */
1483 public void setTopIndex (int index) {
1484         checkWidget ();
1485         int result = (int)OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
1486         if (result == OS.LB_ERR) {
1487                 int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1488                 index = Math.min (count - 1, Math.max (0, index));
1489                 OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
1490         }
1491 }
1492
1493 /**
1494  * Shows the selection.  If the selection is already showing in the receiver,
1495  * this method simply returns.  Otherwise, the items are scrolled until
1496  * the selection is visible.
1497  *
1498  * @exception SWTException <ul>
1499  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1500  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1501  * </ul>
1502  */
1503 public void showSelection () {
1504         checkWidget ();
1505         int index;
1506         if ((style & SWT.SINGLE) != 0) {
1507                 index = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
1508         } else {
1509                 int [] indices = new int [1];
1510                 int result = (int)OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices);
1511                 index = indices [0];
1512                 if (result != 1) index = -1;
1513         }
1514         if (index == -1) return;
1515         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1516         if (count == 0) return;
1517         int height = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
1518         forceResize ();
1519         RECT rect = new RECT ();
1520         OS.GetClientRect (handle, rect);
1521         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1522         int visibleCount = Math.max (rect.bottom / height, 1);
1523         int bottomIndex = Math.min (topIndex + visibleCount, count) - 1;
1524         if (topIndex <= index && index <= bottomIndex) return;
1525         int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1);
1526         OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0);
1527 }
1528
1529 @Override
1530 void updateMenuLocation (Event event) {
1531         Rectangle clientArea = getClientAreaInPixels ();
1532         int x = clientArea.x, y = clientArea.y;
1533         int focusIndex = getFocusIndex();
1534         if (focusIndex != -1) {
1535                 RECT rect = new RECT ();
1536                 long newFont, oldFont = 0;
1537                 long hDC = OS.GetDC (handle);
1538                 newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1539                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1540                 int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1541                 char [] buffer = new char [64 + 1];
1542                 int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, focusIndex, 0);
1543                 if (length != OS.LB_ERR) {
1544                         if (length + 1 > buffer.length) {
1545                                 buffer = new char [length + 1];
1546                         }
1547                         int result = (int)OS.SendMessage (handle, OS.LB_GETTEXT, focusIndex, buffer);
1548                         if (result != OS.LB_ERR) {
1549                                 OS.DrawText (hDC, buffer, length, rect, flags);
1550                         }
1551                 }
1552                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
1553                 OS.ReleaseDC (handle, hDC);
1554                 x = Math.max (x, rect.right / 2);
1555                 x = Math.min (x, clientArea.x + clientArea.width);
1556
1557                 OS.SendMessage (handle, OS.LB_GETITEMRECT, focusIndex, rect);
1558                 y = Math.max (y, rect.bottom);
1559                 y = Math.min (y, clientArea.y + clientArea.height);
1560         }
1561         Point pt = toDisplayInPixels (x, y);
1562         event.setLocationInPixels(pt.x, pt.y);
1563 }
1564
1565 @Override
1566 boolean updateTextDirection (int textDirection) {
1567         if (textDirection == AUTO_TEXT_DIRECTION) {
1568                 /* If auto is already in effect, there's nothing to do. */
1569                 if ((state & HAS_AUTO_DIRECTION) != 0) return false;
1570                 state |= HAS_AUTO_DIRECTION;
1571         } else {
1572                 state &= ~HAS_AUTO_DIRECTION;
1573                 if (!addedUCC /*(state & HAS_AUTO_DIRECTION) == 0*/) {
1574                         return super.updateTextDirection (textDirection);
1575                 }
1576         }
1577         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1578         if (count == OS.LB_ERR) return false;
1579         int selection = (int)OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
1580         addedUCC = false;
1581         while (count-- > 0) {
1582                 int length = (int)OS.SendMessage (handle, OS.LB_GETTEXTLEN, count, 0);
1583                 if (length == OS.LB_ERR) break;
1584                 if (length == 0) continue;
1585                 char [] buffer = new char [length + 1];
1586                 if (OS.SendMessage (handle, OS.LB_GETTEXT, count, buffer) == OS.LB_ERR) break;
1587                 if (OS.SendMessage (handle, OS.LB_DELETESTRING, count, 0) == OS.LB_ERR) break;
1588                 if ((state & HAS_AUTO_DIRECTION) == 0) {
1589                         /* Should remove UCC */
1590                         System.arraycopy(buffer, 1, buffer, 0, length);
1591                 }
1592                 /* Adding UCC is handled in OS.LB_INSERTSTRING */
1593                 if (OS.SendMessage (handle, OS.LB_INSERTSTRING, count, buffer) == OS.LB_ERR) break;
1594         }
1595         if (selection != OS.LB_ERR) {
1596                 OS.SendMessage (handle, OS.LB_SETCURSEL, selection, 0);
1597         }
1598         return textDirection == AUTO_TEXT_DIRECTION || super.updateTextDirection (textDirection);
1599 }
1600
1601 @Override
1602 int widgetStyle () {
1603         int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT;
1604         if ((style & SWT.SINGLE) != 0) return bits;
1605         if ((style & SWT.MULTI) != 0) {
1606                 if ((style & SWT.SIMPLE) != 0) return bits | OS.LBS_MULTIPLESEL;
1607                 return bits | OS.LBS_EXTENDEDSEL;
1608         }
1609         return bits;
1610 }
1611
1612 @Override
1613 TCHAR windowClass () {
1614         return ListClass;
1615 }
1616
1617 @Override
1618 long windowProc () {
1619         return ListProc;
1620 }
1621
1622 @Override
1623 long windowProc (long hwnd, int msg, long wParam, long lParam) {
1624         /* Below code is to support auto text direction. */
1625         if (handle != 0 && lParam != 0 && (state & HAS_AUTO_DIRECTION) != 0) {
1626                 switch (msg) {
1627                         case OS.LB_ADDSTRING:
1628                         case OS.LB_INSERTSTRING:
1629                         case OS.LB_FINDSTRINGEXACT:
1630                                 int length = OS.wcslen (lParam); // we are always Unicode here
1631                                 int cp = getCodePage ();
1632                                 TCHAR buffer = new TCHAR (cp, length);
1633                                 OS.MoveMemory (buffer, lParam, buffer.length () * TCHAR.sizeof);
1634                                 String string = buffer.toString (0, length);
1635                                 int direction = BidiUtil.resolveTextDirection (string);
1636                                 if (direction == SWT.NONE) {
1637                                         /*
1638                                          * Force adding a UCC even when no strong characters are found.
1639                                          * Otherwise, the List items would retain the old direction,
1640                                          * which might be inappropriate for the new text.
1641                                          */
1642                                         direction = (style & SWT.RIGHT_TO_LEFT) != 0 ? SWT.RIGHT_TO_LEFT : SWT.LEFT_TO_RIGHT;
1643                                 }
1644                                 string = (direction == SWT.RIGHT_TO_LEFT ? RLE : LRE) + string;
1645                                 buffer = new TCHAR (cp, string, true);
1646                                 long hHeap = OS.GetProcessHeap ();
1647                                 length = buffer.length() * TCHAR.sizeof;
1648                                 long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, length);
1649                                 OS.MoveMemory (pszText, buffer, length);
1650                                 long code = super.windowProc (hwnd, msg, wParam, pszText);
1651                                 OS.HeapFree (hHeap, 0, pszText);
1652                                 addedUCC = true;
1653                                 return code;
1654                 }
1655         }
1656         return super.windowProc (hwnd, msg, wParam, lParam);
1657 }
1658
1659 @Override
1660 LRESULT WM_CHAR (long wParam, long lParam) {
1661         LRESULT result = super.WM_CHAR (wParam, lParam);
1662         if (result != null) return result;
1663         /*
1664         * Feature in Windows.  The Windows list box does not implement
1665         * the control key interface for multi-select list boxes, making
1666         * it inaccessible from the keyboard.  The fix is to implement
1667         * the key processing.
1668         */
1669         if (OS.GetKeyState (OS.VK_CONTROL) < 0 && OS.GetKeyState (OS.VK_SHIFT) >= 0) {
1670                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1671                 if ((bits & OS.LBS_EXTENDEDSEL) != 0) {
1672                         switch ((int)wParam) {
1673                                 case OS.VK_SPACE: {
1674                                         int index = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1675                                         int code = (int)OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
1676                                         if (code == OS.LB_ERR) break;
1677                                         OS.SendMessage (handle, OS.LB_SETSEL, code != 0 ? 0 : 1, index);
1678                                         OS.SendMessage (handle, OS.LB_SETANCHORINDEX, index, 0);
1679                                         sendSelectionEvent (SWT.Selection);
1680                                         return LRESULT.ZERO;
1681                                 }
1682                         }
1683                 }
1684         }
1685         return result;
1686 }
1687
1688 @Override
1689 LRESULT WM_KEYDOWN (long wParam, long lParam) {
1690         LRESULT result = super.WM_KEYDOWN (wParam, lParam);
1691         if (result != null) return result;
1692         /*
1693         * Feature in Windows.  The Windows list box does not implement
1694         * the control key interface for multi-select list boxes, making
1695         * it inaccessible from the keyboard.  The fix is to implement
1696         * the key processing.
1697         */
1698         if (OS.GetKeyState (OS.VK_CONTROL) < 0 && OS.GetKeyState (OS.VK_SHIFT) >= 0) {
1699                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1700                 if ((bits & OS.LBS_EXTENDEDSEL) != 0) {
1701                         int newIndex = -1;
1702                         switch ((int)wParam) {
1703                                 case OS.VK_SPACE: {
1704                                         /*
1705                                         * Ensure that the window proc does not process VK_SPACE
1706                                         * so that it can be handled in WM_CHAR.  This allows the
1707                                         * application to cancel an operation that is normally
1708                                         * performed in WM_KEYDOWN from WM_CHAR.
1709                                         */
1710                                         return LRESULT.ZERO;
1711                                 }
1712                                 case OS.VK_UP:
1713                                 case OS.VK_DOWN: {
1714                                         int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1715                                         newIndex = Math.max (0, oldIndex + (((int)wParam) == OS.VK_UP ? -1 : 1));
1716                                         break;
1717                                 }
1718                                 case OS.VK_PRIOR: {
1719                                         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1720                                         int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1721                                         if (oldIndex != topIndex) {
1722                                                 newIndex = topIndex;
1723                                         } else {
1724                                                 forceResize ();
1725                                                 RECT rect = new RECT ();
1726                                                 OS.GetClientRect (handle, rect);
1727                                                 int itemHeight = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
1728                                                 int pageSize = Math.max (2, (rect.bottom / itemHeight));
1729                                                 newIndex = Math.max (0, topIndex - (pageSize - 1));
1730                                         }
1731                                         break;
1732                                 }
1733                                 case OS.VK_NEXT: {
1734                                         int topIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1735                                         int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1736                                         forceResize ();
1737                                         RECT rect = new RECT ();
1738                                         OS.GetClientRect (handle, rect);
1739                                         int itemHeight = (int)OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
1740                                         int pageSize = Math.max (2, (rect.bottom / itemHeight));
1741                                         int bottomIndex = topIndex + pageSize - 1;
1742                                         if (oldIndex != bottomIndex) {
1743                                                 newIndex = bottomIndex;
1744                                         } else {
1745                                                 newIndex = bottomIndex + pageSize - 1;
1746                                         }
1747                                         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1748                                         if (count != OS.LB_ERR) newIndex = Math.min (count - 1, newIndex);
1749                                         break;
1750                                 }
1751                                 case OS.VK_HOME: {
1752                                         newIndex = 0;
1753                                         break;
1754                                 }
1755                                 case OS.VK_END: {
1756                                         int count = (int)OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1757                                         if (count == OS.LB_ERR) break;
1758                                         newIndex = count - 1;
1759                                         break;
1760                                 }
1761                         }
1762                         if (newIndex != -1) {
1763                                 /*
1764                                 * Feature in Windows.  When the user changes focus using
1765                                 * the keyboard, the focus indicator does not draw.  The
1766                                 * fix is to update the UI state for the control whenever
1767                                 * the focus indicator changes as a result of something
1768                                 * the user types.
1769                                 */
1770                                 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1771                                 if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
1772                                         OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
1773                                         /*
1774                                         * Bug in Windows.  When the WM_CHANGEUISTATE is used
1775                                         * to update the UI state for a list that has been
1776                                         * selected using Shift+Arrow, the focus indicator
1777                                         * has pixel corruption.  The fix is to redraw the
1778                                         * control.
1779                                         */
1780                                         RECT itemRect = new RECT ();
1781                                         int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1782                                         OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, itemRect);
1783                                         OS.InvalidateRect (handle, itemRect, true);
1784                                 }
1785                                 OS.SendMessage (handle, OS.LB_SETCARETINDEX, newIndex, 0);
1786                                 return LRESULT.ZERO;
1787                         }
1788                 }
1789         }
1790         return result;
1791 }
1792
1793 @Override
1794 LRESULT WM_SETREDRAW (long wParam, long lParam) {
1795         LRESULT result = super.WM_SETREDRAW (wParam, lParam);
1796         if (result != null) return result;
1797         /*
1798         * Bug in Windows.  When WM_SETREDRAW is used to turn off
1799         * redraw for a list, table or tree, the background of the
1800         * control is drawn.  The fix is to call DefWindowProc(),
1801         * which stops all graphics output to the control.
1802         */
1803         OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
1804         return result;
1805 }
1806
1807 @Override
1808 LRESULT WM_SIZE (long wParam, long lParam) {
1809         /*
1810         * Bug in Windows.  If the top index is changed while the
1811         * list is being resized, Windows does not redraw properly
1812         * when their is white space at the bottom of the control.
1813         * The fix is to detect when the top index has changed and
1814         * redraw the control.
1815         *
1816         * Bug in Windows.  If the receiver is scrolled horizontally
1817         * and is resized, the list does not redraw properly.  The fix
1818         * is to redraw the control when the horizontal scroll bar is
1819         * not at the beginning.
1820         */
1821         int oldIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1822         LRESULT result = super.WM_SIZE (wParam, lParam);
1823         if (!isDisposed ()) {
1824                 SCROLLINFO info = new SCROLLINFO ();
1825                 info.cbSize = SCROLLINFO.sizeof;
1826                 info.fMask = OS.SIF_POS;
1827                 if (OS.GetScrollInfo (handle, OS.SB_HORZ, info)) {
1828                         if (info.nPos != 0) OS.InvalidateRect (handle, null, true);
1829                 }
1830                 int newIndex = (int)OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1831                 if (oldIndex != newIndex) OS.InvalidateRect (handle, null, true);
1832         }
1833         return result;
1834 }
1835
1836 @Override
1837 LRESULT wmCommandChild (long wParam, long lParam) {
1838         int code = OS.HIWORD (wParam);
1839         switch (code) {
1840                 case OS.LBN_SELCHANGE:
1841                         sendSelectionEvent (SWT.Selection);
1842                         break;
1843                 case OS.LBN_DBLCLK:
1844                         sendSelectionEvent (SWT.DefaultSelection);
1845                         break;
1846         }
1847         return super.wmCommandChild (wParam, lParam);
1848 }
1849
1850
1851
1852 }