KickJava   Java API By Example, From Geeks To Geeks.

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


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
14 import org.eclipse.swt.internal.win32.*;
15 import org.eclipse.swt.*;
16 import org.eclipse.swt.graphics.*;
17 import org.eclipse.swt.events.*;
18
19 /**
20  * Instances of this class represent a selectable user interface
21  * object that displays a list of strings and issues notification
22  * when a string is selected. A list may be single or multi select.
23  * <p>
24  * <dl>
25  * <dt><b>Styles:</b></dt>
26  * <dd>SINGLE, MULTI</dd>
27  * <dt><b>Events:</b></dt>
28  * <dd>Selection, DefaultSelection</dd>
29  * </dl>
30  * <p>
31  * Note: Only one of SINGLE and MULTI may be specified.
32  * </p><p>
33  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
34  * </p>
35  */

36
37 public class List extends Scrollable {
38     static final int INSET = 3;
39     static final int ListProc;
40     static final TCHAR ListClass = new TCHAR (0, "LISTBOX", true);
41     static {
42         WNDCLASS lpWndClass = new WNDCLASS ();
43         OS.GetClassInfo (0, ListClass, lpWndClass);
44         ListProc = lpWndClass.lpfnWndProc;
45     }
46
47 /**
48  * Constructs a new instance of this class given its parent
49  * and a style value describing its behavior and appearance.
50  * <p>
51  * The style value is either one of the style constants defined in
52  * class <code>SWT</code> which is applicable to instances of this
53  * class, or must be built by <em>bitwise OR</em>'ing together
54  * (that is, using the <code>int</code> "|" operator) two or more
55  * of those <code>SWT</code> style constants. The class description
56  * lists the style constants that are applicable to the class.
57  * Style bits are also inherited from superclasses.
58  * </p>
59  *
60  * @param parent a composite control which will be the parent of the new instance (cannot be null)
61  * @param style the style of control to construct
62  *
63  * @exception IllegalArgumentException <ul>
64  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
65  * </ul>
66  * @exception SWTException <ul>
67  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
68  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
69  * </ul>
70  *
71  * @see SWT#SINGLE
72  * @see SWT#MULTI
73  * @see Widget#checkSubclass
74  * @see Widget#getStyle
75  */

76 public List (Composite parent, int style) {
77     super (parent, checkStyle (style));
78 }
79 /**
80  * Adds the argument to the end of the receiver's list.
81  *
82  * @param string the new item
83  *
84  * @exception IllegalArgumentException <ul>
85  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
86  * </ul>
87  * @exception SWTException <ul>
88  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
89  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
90  * </ul>
91  *
92  * @see #add(String,int)
93  */

94 public void add (String JavaDoc string) {
95     checkWidget ();
96     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
97     TCHAR buffer = new TCHAR (getCodePage (), string, true);
98     int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
99     if (result == OS.LB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
100     if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
101     if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
102 }
103 /**
104  * Adds the argument to the receiver's list at the given
105  * zero-relative index.
106  * <p>
107  * Note: To add an item at the end of the list, use the
108  * result of calling <code>getItemCount()</code> as the
109  * index or use <code>add(String)</code>.
110  * </p>
111  *
112  * @param string the new item
113  * @param index the index for the item
114  *
115  * @exception IllegalArgumentException <ul>
116  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
117  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
118  * </ul>
119  * @exception SWTException <ul>
120  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
121  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
122  * </ul>
123  *
124  * @see #add(String)
125  */

126 public void add (String JavaDoc string, int index) {
127     checkWidget ();
128     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
129     if (index == -1) error (SWT.ERROR_INVALID_RANGE);
130     TCHAR buffer = new TCHAR (getCodePage (), string, true);
131     int result = OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer);
132     if (result == OS.LB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
133     if (result == OS.LB_ERR) {
134         int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
135         if (0 <= index && index <= count) {
136             error (SWT.ERROR_ITEM_NOT_ADDED);
137         } else {
138             error (SWT.ERROR_INVALID_RANGE);
139         }
140     }
141     if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
142 }
143
144 /**
145  * Adds the listener to the collection of listeners who will
146  * be notified when the user changes the receiver's selection, by sending
147  * it one of the messages defined in the <code>SelectionListener</code>
148  * interface.
149  * <p>
150  * <code>widgetSelected</code> is called when the selection changes.
151  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
152  * </p>
153  *
154  * @param listener the listener which should be notified when the user changes the receiver's selection
155  *
156  * @exception IllegalArgumentException <ul>
157  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
158  * </ul>
159  * @exception SWTException <ul>
160  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
161  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
162  * </ul>
163  *
164  * @see SelectionListener
165  * @see #removeSelectionListener
166  * @see SelectionEvent
167  */

168 public void addSelectionListener(SelectionListener listener) {
169     checkWidget ();
170     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
171     TypedListener typedListener = new TypedListener (listener);
172     addListener (SWT.Selection,typedListener);
173     addListener (SWT.DefaultSelection,typedListener);
174 }
175
176 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
177     if (handle == 0) return 0;
178     return OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam);
179 }
180
181 static int checkStyle (int style) {
182     return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
183 }
184
185 public Point computeSize (int wHint, int hHint, boolean changed) {
186     checkWidget ();
187     int width = 0, height = 0;
188     if (wHint == SWT.DEFAULT) {
189         if ((style & SWT.H_SCROLL) != 0) {
190             width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
191             width -= INSET;
192         } else {
193             int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
194             int newFont, oldFont = 0;
195             int hDC = OS.GetDC (handle);
196             newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
197             if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
198             RECT rect = new RECT ();
199             int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
200             int cp = getCodePage ();
201             TCHAR buffer = new TCHAR (cp, 64 + 1);
202             for (int i=0; i<count; i++) {
203                 int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
204                 if (length != OS.LB_ERR) {
205                     if (length + 1 > buffer.length ()) {
206                         buffer = new TCHAR (cp, length + 1);
207                     }
208                     int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
209                     if (result != OS.LB_ERR) {
210                         OS.DrawText (hDC, buffer, length, rect, flags);
211                         width = Math.max (width, rect.right - rect.left);
212                     }
213                 }
214             }
215             if (newFont != 0) OS.SelectObject (hDC, oldFont);
216             OS.ReleaseDC (handle, hDC);
217         }
218     }
219     if (hHint == SWT.DEFAULT) {
220         int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
221         int itemHeight = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
222         height = count * itemHeight;
223     }
224     if (width == 0) width = DEFAULT_WIDTH;
225     if (height == 0) height = DEFAULT_HEIGHT;
226     if (wHint != SWT.DEFAULT) width = wHint;
227     if (hHint != SWT.DEFAULT) height = hHint;
228     int border = getBorderWidth ();
229     width += border * 2 + INSET;
230     height += border * 2;
231     if ((style & SWT.V_SCROLL) != 0) {
232         width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
233     }
234     if ((style & SWT.H_SCROLL) != 0) {
235         height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
236     }
237     return new Point (width, height);
238 }
239
240 int defaultBackground () {
241     return OS.GetSysColor (OS.COLOR_WINDOW);
242 }
243
244 /**
245  * Deselects the items at the given zero-relative indices in the receiver.
246  * If the item at the given zero-relative index in the receiver
247  * is selected, it is deselected. If the item at the index
248  * was not selected, it remains deselected. Indices that are out
249  * of range and duplicate indices are ignored.
250  *
251  * @param indices the array of indices for the items to deselect
252  *
253  * @exception IllegalArgumentException <ul>
254  * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
255  * </ul>
256  * @exception SWTException <ul>
257  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
258  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
259  * </ul>
260  */

261 public void deselect (int [] indices) {
262     checkWidget ();
263     if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
264     if (indices.length == 0) return;
265     if ((style & SWT.SINGLE) != 0) {
266         int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
267         if (oldIndex == OS.LB_ERR) return;
268         for (int i=0; i<indices.length; i++) {
269             if (oldIndex == indices [i]) {
270                 OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
271                 return;
272             }
273         }
274         return;
275     }
276     for (int i=0; i<indices.length; i++) {
277         int index = indices [i];
278         if (index != -1) {
279             OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
280         }
281     }
282 }
283
284 /**
285  * Deselects the item at the given zero-relative index in the receiver.
286  * If the item at the index was already deselected, it remains
287  * deselected. Indices that are out of range are ignored.
288  *
289  * @param index the index of the item to deselect
290  *
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 index) {
297     checkWidget ();
298     if (index == -1) return;
299     if ((style & SWT.SINGLE) != 0) {
300         int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
301         if (oldIndex == OS.LB_ERR) return;
302         if (oldIndex == index) OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
303         return;
304     }
305     OS.SendMessage (handle, OS.LB_SETSEL, 0, index);
306 }
307
308 /**
309  * Deselects the items at the given zero-relative indices in the receiver.
310  * If the item at the given zero-relative index in the receiver
311  * is selected, it is deselected. If the item at the index
312  * was not selected, it remains deselected. The range of the
313  * indices is inclusive. Indices that are out of range are ignored.
314  *
315  * @param start the start index of the items to deselect
316  * @param end the end index of the items to deselect
317  *
318  * @exception SWTException <ul>
319  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
320  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
321  * </ul>
322  */

323 public void deselect (int start, int end) {
324     checkWidget ();
325     if (start > end) return;
326     if ((style & SWT.SINGLE) != 0) {
327         int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
328         if (oldIndex == OS.LB_ERR) return;
329         if (start <= oldIndex && oldIndex <= end) {
330             OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
331         }
332         return;
333     }
334     /*
335     * Ensure that at least one item is contained in
336     * the range from start to end. Note that when
337     * start = end, LB_SELITEMRANGEEX deselects the
338     * item.
339     */

340     int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
341     if (start < 0 && end < 0) return;
342     if (start >= count && end >= count) return;
343     start = Math.min (count - 1, Math.max (0, start));
344     end = Math.min (count - 1, Math.max (0, end));
345     OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start);
346 }
347
348 /**
349  * Deselects all selected items in the receiver.
350  *
351  * @exception SWTException <ul>
352  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
353  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
354  * </ul>
355  */

356 public void deselectAll () {
357     checkWidget ();
358     if ((style & SWT.SINGLE) != 0) {
359         OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0);
360     } else {
361         OS.SendMessage (handle, OS.LB_SETSEL, 0, -1);
362     }
363 }
364
365 /**
366  * Returns the zero-relative index of the item which currently
367  * has the focus in the receiver, or -1 if no item has focus.
368  *
369  * @return the index of the selected item
370  *
371  * @exception SWTException <ul>
372  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
373  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
374  * </ul>
375  */

376 public int getFocusIndex () {
377     checkWidget ();
378     int result = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
379     if (result == 0) {
380         int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
381         if (count == 0) return -1;
382     }
383     return result;
384 }
385
386 /**
387  * Returns the item at the given, zero-relative index in the
388  * receiver. Throws an exception if the index is out of range.
389  *
390  * @param index the index of the item to return
391  * @return the item at the given index
392  *
393  * @exception IllegalArgumentException <ul>
394  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
395  * </ul>
396  * @exception SWTException <ul>
397  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
398  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
399  * </ul>
400  */

401 public String JavaDoc getItem (int index) {
402     checkWidget ();
403     int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
404     if (length != OS.LB_ERR) {
405         TCHAR buffer = new TCHAR (getCodePage (), length + 1);
406         int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
407         if (result != OS.LB_ERR) return buffer.toString (0, length);
408     }
409     int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
410     if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
411     error (SWT.ERROR_INVALID_RANGE);
412     return "";
413 }
414
415 /**
416  * Returns the number of items contained in the receiver.
417  *
418  * @return the number of items
419  *
420  * @exception SWTException <ul>
421  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
422  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
423  * </ul>
424  */

425 public int getItemCount () {
426     checkWidget ();
427     int result = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
428     if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
429     return result;
430 }
431
432 /**
433  * Returns the height of the area which would be used to
434  * display <em>one</em> of the items in the list.
435  *
436  * @return the height of one item
437  *
438  * @exception SWTException <ul>
439  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
440  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
441  * </ul>
442  */

443 public int getItemHeight () {
444     checkWidget ();
445     int result = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
446     if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
447     return result;
448 }
449
450 /**
451  * Returns a (possibly empty) array of <code>String</code>s which
452  * are the items in the receiver.
453  * <p>
454  * Note: This is not the actual structure used by the receiver
455  * to maintain its list of items, so modifying the array will
456  * not affect the receiver.
457  * </p>
458  *
459  * @return the items in the receiver's list
460  *
461  * @exception SWTException <ul>
462  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
463  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
464  * </ul>
465  */

466 public String JavaDoc [] getItems () {
467     checkWidget ();
468     int count = getItemCount ();
469     String JavaDoc [] result = new String JavaDoc [count];
470     for (int i=0; i<count; i++) result [i] = getItem (i);
471     return result;
472 }
473
474 /**
475  * Returns an array of <code>String</code>s that are currently
476  * selected in the receiver. The order of the items is unspecified.
477  * An empty array indicates that no items are selected.
478  * <p>
479  * Note: This is not the actual structure used by the receiver
480  * to maintain its selection, so modifying the array will
481  * not affect the receiver.
482  * </p>
483  * @return an array representing the selection
484  *
485  * @exception SWTException <ul>
486  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
487  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
488  * </ul>
489  */

490 public String JavaDoc [] getSelection () {
491     checkWidget ();
492     int [] indices = getSelectionIndices ();
493     String JavaDoc [] result = new String JavaDoc [indices.length];
494     for (int i=0; i<indices.length; i++) {
495         result [i] = getItem (indices [i]);
496     }
497     return result;
498 }
499
500 /**
501  * Returns the number of selected items contained in the receiver.
502  *
503  * @return the number of selected items
504  *
505  * @exception SWTException <ul>
506  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
507  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
508  * </ul>
509  */

510 public int getSelectionCount () {
511     checkWidget ();
512     if ((style & SWT.SINGLE) != 0) {
513         int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
514         if (result == OS.LB_ERR) return 0;
515         return 1;
516     }
517     int result = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
518     if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
519     return result;
520 }
521
522 /**
523  * Returns the zero-relative index of the item which is currently
524  * selected in the receiver, or -1 if no item is selected.
525  *
526  * @return the index of the selected item or -1
527  *
528  * @exception SWTException <ul>
529  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
530  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
531  * </ul>
532  */

533 public int getSelectionIndex () {
534     checkWidget ();
535     if ((style & SWT.SINGLE) != 0) {
536         return OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
537     }
538     int count = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
539     if (count == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
540     if (count == 0) return -1;
541     int index = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
542     int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
543     if (result == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
544     if (result != 0) return index;
545     int [] buffer = new int [1];
546     result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer);
547     if (result != 1) error (SWT.ERROR_CANNOT_GET_SELECTION);
548     return buffer [0];
549 }
550
551 /**
552  * Returns the zero-relative indices of the items which are currently
553  * selected in the receiver. The order of the indices is unspecified.
554  * The array is empty if no items are selected.
555  * <p>
556  * Note: This is not the actual structure used by the receiver
557  * to maintain its selection, so modifying the array will
558  * not affect the receiver.
559  * </p>
560  * @return the array of indices of the selected items
561  *
562  * @exception SWTException <ul>
563  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
564  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
565  * </ul>
566  */

567 public int [] getSelectionIndices () {
568     checkWidget ();
569     if ((style & SWT.SINGLE) != 0) {
570         int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
571         if (result == OS.LB_ERR) return new int [0];
572         return new int [] {result};
573     }
574     int length = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0);
575     if (length == OS.LB_ERR) error (SWT.ERROR_CANNOT_GET_SELECTION);
576     int [] indices = new int [length];
577     int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices);
578     if (result != length) error (SWT.ERROR_CANNOT_GET_SELECTION);
579     return indices;
580 }
581
582 /**
583  * Returns the zero-relative index of the item which is currently
584  * at the top of the receiver. This index can change when items are
585  * scrolled or new items are added or removed.
586  *
587  * @return the index of the top item
588  *
589  * @exception SWTException <ul>
590  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
591  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
592  * </ul>
593  */

594 public int getTopIndex () {
595     checkWidget ();
596     return OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
597 }
598
599 /**
600  * Gets the index of an item.
601  * <p>
602  * The list is searched starting at 0 until an
603  * item is found that is equal to the search item.
604  * If no item is found, -1 is returned. Indexing
605  * is zero based.
606  *
607  * @param string the search item
608  * @return the index of the item
609  *
610  * @exception IllegalArgumentException <ul>
611  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
612  * </ul>
613  * @exception SWTException <ul>
614  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
615  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
616  * </ul>
617  */

618 public int indexOf (String JavaDoc string) {
619     return indexOf (string, 0);
620 }
621
622 /**
623  * Searches the receiver's list starting at the given,
624  * zero-relative index until an item is found that is equal
625  * to the argument, and returns the index of that item. If
626  * no item is found or the starting index is out of range,
627  * returns -1.
628  *
629  * @param string the search item
630  * @param start the zero-relative index at which to start the search
631  * @return the index of the item
632  *
633  * @exception IllegalArgumentException <ul>
634  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
635  * </ul>
636  * @exception SWTException <ul>
637  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
638  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
639  * </ul>
640  */

641 public int indexOf (String JavaDoc string, int start) {
642     checkWidget ();
643     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
644     
645     /*
646     * Bug in Windows. For some reason, LB_FINDSTRINGEXACT
647     * will not find empty strings even though it is legal
648     * to insert an empty string into a list. The fix is
649     * to search the list, an item at a time.
650     */

651     if (string.length () == 0) {
652         int count = getItemCount ();
653         for (int i=start; i<count; i++) {
654             if (string.equals (getItem (i))) return i;
655         }
656         return -1;
657     }
658
659     /* Use LB_FINDSTRINGEXACT to search for the item */
660     int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
661     if (!(0 <= start && start < count)) return -1;
662     int index = start - 1, last;
663     TCHAR buffer = new TCHAR (getCodePage (), string, true);
664     do {
665         index = OS.SendMessage (handle, OS.LB_FINDSTRINGEXACT, last = index, buffer);
666         if (index == OS.LB_ERR || index <= last) return -1;
667     } while (!string.equals (getItem (index)));
668     return index;
669 }
670
671 /**
672  * Returns <code>true</code> if the item is selected,
673  * and <code>false</code> otherwise. Indices out of
674  * range are ignored.
675  *
676  * @param index the index of the item
677  * @return the selection state of the item at the index
678  *
679  * @exception SWTException <ul>
680  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
681  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
682  * </ul>
683  */

684 public boolean isSelected (int index) {
685     checkWidget ();
686     int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0);
687     return (result != 0) && (result != OS.LB_ERR);
688 }
689
690 /**
691  * Removes the items from the receiver at the given
692  * zero-relative indices.
693  *
694  * @param indices the array of indices of the items
695  *
696  * @exception IllegalArgumentException <ul>
697  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
698  * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
699  * </ul>
700  * @exception SWTException <ul>
701  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
702  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
703  * </ul>
704  */

705 public void remove (int [] indices) {
706     checkWidget ();
707     if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
708     if (indices.length == 0) return;
709     int [] newIndices = new int [indices.length];
710     System.arraycopy (indices, 0, newIndices, 0, indices.length);
711     sort (newIndices);
712     int start = newIndices [newIndices.length - 1], end = newIndices [0];
713     int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
714     if (!(0 <= start && start <= end && end < count)) {
715         error (SWT.ERROR_INVALID_RANGE);
716     }
717     int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
718     RECT rect = null;
719     int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
720     if ((style & SWT.H_SCROLL) != 0) {
721         rect = new RECT ();
722         hDC = OS.GetDC (handle);
723         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
724         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
725     }
726     int cp = getCodePage ();
727     int i = 0, topCount = 0, last = -1;
728     while (i < newIndices.length) {
729         int index = newIndices [i];
730         if (index != last) {
731             TCHAR buffer = null;
732             if ((style & SWT.H_SCROLL) != 0) {
733                 int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
734                 if (length == OS.LB_ERR) break;
735                 buffer = new TCHAR (cp, length + 1);
736                 int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
737                 if (result == OS.LB_ERR) break;
738             }
739             int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
740             if (result == OS.LB_ERR) break;
741             if ((style & SWT.H_SCROLL) != 0) {
742                 int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
743                 OS.DrawText (hDC, buffer, -1, rect, flags);
744                 newWidth = Math.max (newWidth, rect.right - rect.left);
745             }
746             if (index < topIndex) topCount++;
747             last = index;
748         }
749         i++;
750     }
751     if ((style & SWT.H_SCROLL) != 0) {
752         if (newFont != 0) OS.SelectObject (hDC, oldFont);
753         OS.ReleaseDC (handle, hDC);
754         setScrollWidth (newWidth, false);
755     }
756     if (topCount > 0) {
757         topIndex -= topCount;
758         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
759     }
760     if (i < newIndices.length) error (SWT.ERROR_ITEM_NOT_REMOVED);
761 }
762
763 /**
764  * Removes the item from the receiver at the given
765  * zero-relative index.
766  *
767  * @param index the index for the item
768  *
769  * @exception IllegalArgumentException <ul>
770  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
771  * </ul>
772  * @exception SWTException <ul>
773  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
774  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
775  * </ul>
776  */

777 public void remove (int index) {
778     checkWidget ();
779     TCHAR buffer = null;
780     if ((style & SWT.H_SCROLL) != 0) {
781         int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0);
782         if (length == OS.LB_ERR) {
783             int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
784             if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
785             error (SWT.ERROR_INVALID_RANGE);
786         }
787         buffer = new TCHAR (getCodePage (), length + 1);
788         int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer);
789         if (result == OS.LB_ERR) {
790             int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
791             if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
792             error (SWT.ERROR_INVALID_RANGE);
793         }
794     }
795     int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
796     int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0);
797     if (result == OS.LB_ERR) {
798         int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
799         if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
800         error (SWT.ERROR_INVALID_RANGE);
801     }
802     if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, false);
803     if (index < topIndex) {
804         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex - 1, 0);
805     }
806 }
807
808 /**
809  * Removes the items from the receiver which are
810  * between the given zero-relative start and end
811  * indices (inclusive).
812  *
813  * @param start the start of the range
814  * @param end the end of the range
815  *
816  * @exception IllegalArgumentException <ul>
817  * <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>
818  * </ul>
819  * @exception SWTException <ul>
820  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
821  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
822  * </ul>
823  */

824 public void remove (int start, int end) {
825     checkWidget ();
826     if (start > end) return;
827     int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
828     if (!(0 <= start && start <= end && end < count)) {
829         error (SWT.ERROR_INVALID_RANGE);
830     }
831     if (start == 0 && end == count - 1) {
832         removeAll ();
833         return;
834     }
835     int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
836     RECT rect = null;
837     int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
838     if ((style & SWT.H_SCROLL) != 0) {
839         rect = new RECT ();
840         hDC = OS.GetDC (handle);
841         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
842         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
843     }
844     int cp = getCodePage ();
845     int index = start;
846     int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
847     while (index <= end) {
848         TCHAR buffer = null;
849         if ((style & SWT.H_SCROLL) != 0) {
850             int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0);
851             if (length == OS.LB_ERR) break;
852             buffer = new TCHAR (cp, length + 1);
853             int result = OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer);
854             if (result == OS.LB_ERR) break;
855         }
856         int result = OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0);
857         if (result == OS.LB_ERR) break;
858         if ((style & SWT.H_SCROLL) != 0) {
859             OS.DrawText (hDC, buffer, -1, rect, flags);
860             newWidth = Math.max (newWidth, rect.right - rect.left);
861         }
862         index++;
863     }
864     if ((style & SWT.H_SCROLL) != 0) {
865         if (newFont != 0) OS.SelectObject (hDC, oldFont);
866         OS.ReleaseDC (handle, hDC);
867         setScrollWidth (newWidth, false);
868     }
869     if (end < topIndex) {
870         topIndex -= end - start + 1;
871         OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
872     }
873     if (index <= end) error (SWT.ERROR_ITEM_NOT_REMOVED);
874 }
875
876 /**
877  * Searches the receiver's list starting at the first item
878  * until an item is found that is equal to the argument,
879  * and removes that item from the list.
880  *
881  * @param string the item to remove
882  *
883  * @exception IllegalArgumentException <ul>
884  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
885  * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
886  * </ul>
887  * @exception SWTException <ul>
888  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
889  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
890  * </ul>
891  */

892 public void remove (String JavaDoc string) {
893     checkWidget ();
894     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
895     int index = indexOf (string, 0);
896     if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
897     remove (index);
898 }
899
900 /**
901  * Removes all of the items from the receiver.
902  * <p>
903  * @exception SWTException <ul>
904  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
905  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
906  * </ul>
907  */

908 public void removeAll () {
909     checkWidget ();
910     OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
911     if ((style & SWT.H_SCROLL) != 0) {
912         OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
913     }
914 }
915
916 /**
917  * Removes the listener from the collection of listeners who will
918  * be notified when the user changes the receiver's selection.
919  *
920  * @param listener the listener which should no longer be notified
921  *
922  * @exception IllegalArgumentException <ul>
923  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
924  * </ul>
925  * @exception SWTException <ul>
926  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
927  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
928  * </ul>
929  *
930  * @see SelectionListener
931  * @see #addSelectionListener
932  */

933 public void removeSelectionListener(SelectionListener listener) {
934     checkWidget ();
935     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
936     if (eventTable == null) return;
937     eventTable.unhook (SWT.Selection, listener);
938     eventTable.unhook (SWT.DefaultSelection,listener);
939 }
940
941 /**
942  * Selects the items at the given zero-relative indices in the receiver.
943  * The current selection is not cleared before the new items are selected.
944  * <p>
945  * If the item at a given index is not selected, it is selected.
946  * If the item at a given index was already selected, it remains selected.
947  * Indices that are out of range and duplicate indices are ignored.
948  * If the receiver is single-select and multiple indices are specified,
949  * then all indices are ignored.
950  *
951  * @param indices the array of indices for the items to select
952  *
953  * @exception IllegalArgumentException <ul>
954  * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
955  * </ul>
956  * @exception SWTException <ul>
957  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
958  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
959  * </ul>
960  *
961  * @see List#setSelection(int[])
962  */

963 public void select (int [] indices) {
964     checkWidget ();
965     if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
966     int length = indices.length;
967     if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
968     select (indices, false);
969 }
970
971 void select (int [] indices, boolean scroll) {
972     int i = 0;
973     while (i < indices.length) {
974         int index = indices [i];
975         if (index != -1) {
976             select (index, false);
977         }
978         i++;
979     }
980     if (scroll) showSelection ();
981 }
982
983 /**
984  * Selects the item at the given zero-relative index in the receiver's
985  * list. If the item at the index was already selected, it remains
986  * selected. Indices that are out of range are ignored.
987  *
988  * @param index the index of the item to select
989  *
990  * @exception SWTException <ul>
991  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
992  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
993  * </ul>
994  */

995 public void select (int index) {
996     checkWidget ();
997     select (index, false);
998 }
999
1000void select (int index, boolean scroll) {
1001    if (index < 0) return;
1002    int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1003    if (index >= count) return;
1004    if (scroll) {
1005        if ((style & SWT.SINGLE) != 0) {
1006            OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
1007        } else {
1008            OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
1009        }
1010        return;
1011    }
1012    int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1013    RECT itemRect = new RECT (), selectedRect = null;
1014    OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect);
1015    boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
1016    if (redraw) {
1017        OS.UpdateWindow (handle);
1018        OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
1019    }
1020    int focusIndex = -1;
1021    if ((style & SWT.SINGLE) != 0) {
1022        int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
1023        if (oldIndex != -1) {
1024            selectedRect = new RECT ();
1025            OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect);
1026        }
1027        OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0);
1028    } else {
1029        focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0);
1030        OS.SendMessage (handle, OS.LB_SETSEL, 1, index);
1031    }
1032    if ((style & SWT.MULTI) != 0) {
1033        if (focusIndex != -1) {
1034            OS.SendMessage (handle, OS.LB_SETCARETINDEX, focusIndex, 0);
1035        }
1036    }
1037    OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0);
1038    if (redraw) {
1039        OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
1040        OS.ValidateRect (handle, null);
1041        OS.InvalidateRect (handle, itemRect, true);
1042        if (selectedRect != null) {
1043            OS.InvalidateRect (handle, selectedRect, true);
1044        }
1045    }
1046}
1047
1048/**
1049 * Selects the items in the range specified by the given zero-relative
1050 * indices in the receiver. The range of indices is inclusive.
1051 * The current selection is not cleared before the new items are selected.
1052 * <p>
1053 * If an item in the given range is not selected, it is selected.
1054 * If an item in the given range was already selected, it remains selected.
1055 * Indices that are out of range are ignored and no items will be selected
1056 * if start is greater than end.
1057 * If the receiver is single-select and there is more than one item in the
1058 * given range, then all indices are ignored.
1059 *
1060 * @param start the start of the range
1061 * @param end the end of the range
1062 *
1063 * @exception SWTException <ul>
1064 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1065 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1066 * </ul>
1067 *
1068 * @see List#setSelection(int,int)
1069 */

1070public void select (int start, int end) {
1071    checkWidget ();
1072    if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
1073    int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1074    if (count == 0 || start >= count) return;
1075    start = Math.max (0, start);
1076    end = Math.min (end, count - 1);
1077    if ((style & SWT.SINGLE) != 0) {
1078        select (start, false);
1079    } else {
1080        select (start, end, false);
1081    }
1082}
1083
1084void select (int start, int end, boolean scroll) {
1085    /*
1086    * Note that when start = end, LB_SELITEMRANGEEX
1087    * deselects the item.
1088    */

1089    if (start == end) {
1090        select (start, scroll);
1091        return;
1092    }
1093    OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end);
1094    if (scroll) showSelection ();
1095}
1096    
1097/**
1098 * Selects all of the items in the receiver.
1099 * <p>
1100 * If the receiver is single-select, do nothing.
1101 *
1102 * @exception SWTException <ul>
1103 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1104 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1105 * </ul>
1106 */

1107public void selectAll () {
1108    checkWidget ();
1109    if ((style & SWT.SINGLE) != 0) return;
1110    OS.SendMessage (handle, OS.LB_SETSEL, 1, -1);
1111}
1112
1113void setFocusIndex (int index) {
1114// checkWidget ();
1115
int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1116    if (!(0 <= index && index < count)) return;
1117    OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0);
1118}
1119
1120public void setFont (Font font) {
1121    checkWidget ();
1122    super.setFont (font);
1123    if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
1124}
1125
1126/**
1127 * Sets the text of the item in the receiver's list at the given
1128 * zero-relative index to the string argument.
1129 *
1130 * @param index the index for the item
1131 * @param string the new text for the item
1132 *
1133 * @exception IllegalArgumentException <ul>
1134 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1135 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1136 * </ul>
1137 * @exception SWTException <ul>
1138 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1139 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1140 * </ul>
1141 */

1142public void setItem (int index, String JavaDoc string) {
1143    checkWidget ();
1144    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1145    int topIndex = getTopIndex ();
1146    boolean isSelected = isSelected (index);
1147    remove (index);
1148    add (string, index);
1149    if (isSelected) select (index, false);
1150    setTopIndex (topIndex);
1151}
1152
1153/**
1154 * Sets the receiver's items to be the given array of items.
1155 *
1156 * @param items the array of items
1157 *
1158 * @exception IllegalArgumentException <ul>
1159 * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1160 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1161 * </ul>
1162 * @exception SWTException <ul>
1163 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1164 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1165 * </ul>
1166 */

1167public void setItems (String JavaDoc [] items) {
1168    checkWidget ();
1169    if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1170    for (int i=0; i<items.length; i++) {
1171        if (items [i] == null) error (SWT.ERROR_INVALID_ARGUMENT);
1172    }
1173    int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
1174    OS.SetWindowLong (handle, OS.GWL_WNDPROC, ListProc);
1175    boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
1176    if (redraw) {
1177        OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
1178    }
1179    RECT rect = null;
1180    int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
1181    if ((style & SWT.H_SCROLL) != 0) {
1182        rect = new RECT ();
1183        hDC = OS.GetDC (handle);
1184        newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1185        if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1186        OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0);
1187    }
1188    int length = items.length;
1189    OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0);
1190    OS.SendMessage (handle, OS.LB_INITSTORAGE, length, length * 32);
1191    int index = 0;
1192    int cp = getCodePage ();
1193    while (index < length) {
1194        String JavaDoc string = items [index];
1195        TCHAR buffer = new TCHAR (cp, string, true);
1196        int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer);
1197        if (result == OS.LB_ERR || result == OS.LB_ERRSPACE) break;
1198        if ((style & SWT.H_SCROLL) != 0) {
1199            int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1200            OS.DrawText (hDC, buffer, -1, rect, flags);
1201            newWidth = Math.max (newWidth, rect.right - rect.left);
1202        }
1203        index++;
1204    }
1205    if ((style & SWT.H_SCROLL) != 0) {
1206        if (newFont != 0) OS.SelectObject (hDC, oldFont);
1207        OS.ReleaseDC (handle, hDC);
1208        OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0);
1209    }
1210    if (redraw) {
1211        OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
1212        /*
1213        * This code is intentionally commented. The window proc
1214        * for the list box implements WM_SETREDRAW to invalidate
1215        * and erase the widget. This is undocumented behavior.
1216        * The commented code below shows what is actually happening
1217        * and reminds us that we are relying on this undocumented
1218        * behavior.
1219        */

1220// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE;
1221
// OS.RedrawWindow (handle, null, 0, flags);
1222
}
1223    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
1224    if (index < items.length) error (SWT.ERROR_ITEM_NOT_ADDED);
1225}
1226
1227void setScrollWidth () {
1228    int newWidth = 0;
1229    RECT rect = new RECT ();
1230    int newFont, oldFont = 0;
1231    int hDC = OS.GetDC (handle);
1232    newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1233    if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1234    int cp = getCodePage ();
1235    int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1236    int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1237    for (int i=0; i<count; i++) {
1238        int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0);
1239        if (length != OS.LB_ERR) {
1240            TCHAR buffer = new TCHAR (cp, length + 1);
1241            int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer);
1242            if (result != OS.LB_ERR) {
1243                OS.DrawText (hDC, buffer, -1, rect, flags);
1244                newWidth = Math.max (newWidth, rect.right - rect.left);
1245            }
1246        }
1247    }
1248    if (newFont != 0) OS.SelectObject (hDC, oldFont);
1249    OS.ReleaseDC (handle, hDC);
1250    OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0);
1251}
1252
1253void setScrollWidth (TCHAR buffer, boolean grow) {
1254    RECT rect = new RECT ();
1255    int newFont, oldFont = 0;
1256    int hDC = OS.GetDC (handle);
1257    newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1258    if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1259    int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1260    OS.DrawText (hDC, buffer, -1, rect, flags);
1261    if (newFont != 0) OS.SelectObject (hDC, oldFont);
1262    OS.ReleaseDC (handle, hDC);
1263    setScrollWidth (rect.right - rect.left, grow);
1264}
1265
1266void setScrollWidth (int newWidth, boolean grow) {
1267    newWidth += INSET;
1268    int width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0);
1269    if (grow) {
1270        if (newWidth <= width) return;
1271        OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth, 0);
1272    } else {
1273        if (newWidth < width) return;
1274        setScrollWidth ();
1275    }
1276}
1277
1278/**
1279 * Selects the items at the given zero-relative indices in the receiver.
1280 * The current selection is cleared before the new items are selected.
1281 * <p>
1282 * Indices that are out of range and duplicate indices are ignored.
1283 * If the receiver is single-select and multiple indices are specified,
1284 * then all indices are ignored.
1285 *
1286 * @param indices the indices of the items to select
1287 *
1288 * @exception IllegalArgumentException <ul>
1289 * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1290 * </ul>
1291 * @exception SWTException <ul>
1292 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1293 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1294 * </ul>
1295 *
1296 * @see List#deselectAll()
1297 * @see List#select(int[])
1298 */

1299public void setSelection(int [] indices) {
1300    checkWidget ();
1301    if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
1302    deselectAll ();
1303    int length = indices.length;
1304    if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1305    select (indices, true);
1306    if ((style & SWT.MULTI) != 0) {
1307        int focusIndex = indices [0];
1308        if (focusIndex >= 0) setFocusIndex (focusIndex);
1309    }
1310}
1311
1312/**
1313 * Sets the receiver's selection to be the given array of items.
1314 * The current selection is cleared before the new items are selected.
1315 * <p>
1316 * Items that are not in the receiver are ignored.
1317 * If the receiver is single-select and multiple items are specified,
1318 * then all items are ignored.
1319 *
1320 * @param items the array of items
1321 *
1322 * @exception IllegalArgumentException <ul>
1323 * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
1324 * </ul>
1325 * @exception SWTException <ul>
1326 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1327 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1328 * </ul>
1329 *
1330 * @see List#deselectAll()
1331 * @see List#select(int[])
1332 * @see List#setSelection(int[])
1333 */

1334public void setSelection (String JavaDoc [] items) {
1335    checkWidget ();
1336    if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1337    deselectAll ();
1338    int length = items.length;
1339    if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1340    int focusIndex = -1;
1341    for (int i=length-1; i>=0; --i) {
1342        String JavaDoc string = items [i];
1343        int index = 0;
1344        if (string != null) {
1345            int localFocus = -1;
1346            while ((index = indexOf (string, index)) != -1) {
1347                if (localFocus == -1) localFocus = index;
1348                select (index, false);
1349                if ((style & SWT.SINGLE) != 0 && isSelected (index)) {
1350                    showSelection ();
1351                    return;
1352                }
1353                index++;
1354            }
1355            if (localFocus != -1) focusIndex = localFocus;
1356        }
1357    }
1358    if ((style & SWT.MULTI) != 0) {
1359        if (focusIndex >= 0) setFocusIndex (focusIndex);
1360    }
1361}
1362
1363/**
1364 * Selects the item at the given zero-relative index in the receiver.
1365 * If the item at the index was already selected, it remains selected.
1366 * The current selection is first cleared, then the new item is selected.
1367 * Indices that are out of range are ignored.
1368 *
1369 * @param index the index of the item to select
1370 *
1371 * @exception SWTException <ul>
1372 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1373 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1374 * </ul>
1375 * @see List#deselectAll()
1376 * @see List#select(int)
1377 */

1378public void setSelection (int index) {
1379    checkWidget ();
1380    deselectAll ();
1381    select (index, true);
1382    if ((style & SWT.MULTI) != 0) {
1383        if (index >= 0) setFocusIndex (index);
1384    }
1385}
1386
1387/**
1388 * Selects the items in the range specified by the given zero-relative
1389 * indices in the receiver. The range of indices is inclusive.
1390 * The current selection is cleared before the new items are selected.
1391 * <p>
1392 * Indices that are out of range are ignored and no items will be selected
1393 * if start is greater than end.
1394 * If the receiver is single-select and there is more than one item in the
1395 * given range, then all indices are ignored.
1396 *
1397 * @param start the start index of the items to select
1398 * @param end the end index of the items to select
1399 *
1400 * @exception SWTException <ul>
1401 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1402 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1403 * </ul>
1404 *
1405 * @see List#deselectAll()
1406 * @see List#select(int,int)
1407 */

1408public void setSelection (int start, int end) {
1409    checkWidget ();
1410    deselectAll ();
1411    if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
1412    int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1413    if (count == 0 || start >= count) return;
1414    start = Math.max (0, start);
1415    end = Math.min (end, count - 1);
1416    if ((style & SWT.SINGLE) != 0) {
1417        select (start, true);
1418    } else {
1419        select (start, end, true);
1420        setFocusIndex (start);
1421    }
1422}
1423
1424/**
1425 * Sets the zero-relative index of the item which is currently
1426 * at the top of the receiver. This index can change when items
1427 * are scrolled or new items are added and removed.
1428 *
1429 * @param index the index of the top item
1430 *
1431 * @exception SWTException <ul>
1432 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1433 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1434 * </ul>
1435 */

1436public void setTopIndex (int index) {
1437    checkWidget ();
1438    int result = OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
1439    if (result == OS.LB_ERR) {
1440        int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1441        index = Math.min (count - 1, Math.max (0, index));
1442        OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0);
1443    }
1444}
1445
1446/**
1447 * Shows the selection. If the selection is already showing in the receiver,
1448 * this method simply returns. Otherwise, the items are scrolled until
1449 * the selection is visible.
1450 *
1451 * @exception SWTException <ul>
1452 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1453 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1454 * </ul>
1455 */

1456public void showSelection () {
1457    checkWidget ();
1458    int index;
1459    if ((style & SWT.SINGLE) != 0) {
1460        index = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0);
1461    } else {
1462        int [] indices = new int [1];
1463        int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices);
1464        index = indices [0];
1465        if (result != 1) index = -1;
1466    }
1467    if (index == -1) return;
1468    int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0);
1469    if (count == 0) return;
1470    int height = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0);
1471    forceResize ();
1472    RECT rect = new RECT ();
1473    OS.GetClientRect (handle, rect);
1474    int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1475    int visibleCount = Math.max (rect.bottom / height, 1);
1476    int bottomIndex = Math.min (topIndex + visibleCount, count) - 1;
1477    if (topIndex <= index && index <= bottomIndex) return;
1478    int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1);
1479    OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0);
1480}
1481
1482int widgetStyle () {
1483    int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT;
1484    if ((style & SWT.SINGLE) != 0) return bits;
1485    if ((style & SWT.MULTI) != 0) {
1486        if ((style & SWT.SIMPLE) != 0) return bits | OS.LBS_MULTIPLESEL;
1487        return bits | OS.LBS_EXTENDEDSEL;
1488    }
1489    return bits;
1490}
1491
1492TCHAR windowClass () {
1493    return ListClass;
1494}
1495
1496int windowProc () {
1497    return ListProc;
1498}
1499
1500LRESULT WM_SIZE (int wParam, int lParam) {
1501    /*
1502    * Bug in Windows. If the top index is changed while the
1503    * list is being resized, Windows does not redraw properly
1504    * when their is white space at the bottom of the control.
1505    * The fix is to detect when the top index has changed and
1506    * redraw the control.
1507    *
1508    * Bug in Windows. If the receiver is scrolled horizontally
1509    * and is resized, the list does not redraw properly. The fix
1510    * is to redraw the control when the horizontal scroll bar is
1511    * not at the beginning.
1512    */

1513    int oldIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1514    LRESULT result = super.WM_SIZE (wParam, lParam);
1515    if (!isDisposed ()) {
1516        SCROLLINFO info = new SCROLLINFO ();
1517        info.cbSize = SCROLLINFO.sizeof;
1518        info.fMask = OS.SIF_POS;
1519        if (OS.GetScrollInfo (handle, OS.SB_HORZ, info)) {
1520            if (info.nPos != 0) OS.InvalidateRect (handle, null, true);
1521        }
1522        int newIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0);
1523        if (oldIndex != newIndex) OS.InvalidateRect (handle, null, true);
1524    }
1525    return result;
1526}
1527
1528LRESULT wmCommandChild (int wParam, int lParam) {
1529    int code = wParam >> 16;
1530    switch (code) {
1531        case OS.LBN_SELCHANGE:
1532            postEvent (SWT.Selection);
1533            break;
1534        case OS.LBN_DBLCLK:
1535            postEvent (SWT.DefaultSelection);
1536            break;
1537    }
1538    return super.wmCommandChild (wParam, lParam);
1539}
1540
1541
1542
1543}
1544
Popular Tags