Mercurial > projects > dwt-win
diff dwt/widgets/List.d @ 31:92c102dd64a3
Added all widgets modules as dummy. Most modules of accessible are equal to the linux version, except Accessible.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 28 Jan 2008 04:47:28 +0100 |
parents | |
children | 0f25be5cbe6f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/widgets/List.d Mon Jan 28 04:47:28 2008 +0100 @@ -0,0 +1,1557 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwt.widgets.List; + +import dwt.widgets.Scrollable; +class List : Scrollable { +} +/++ +import dwt.DWT; +import dwt.DWTException; +import dwt.events.SelectionEvent; +import dwt.events.SelectionListener; +import dwt.graphics.Font; +import dwt.graphics.Point; +import dwt.internal.win32.LRESULT; +import dwt.internal.win32.OS; +import dwt.internal.win32.RECT; +import dwt.internal.win32.SCROLLINFO; +import dwt.internal.win32.TCHAR; +import dwt.internal.win32.WNDCLASS; + +/** + * Instances of this class represent a selectable user interface + * object that displays a list of strings and issues notification + * when a string is selected. A list may be single or multi select. + * <p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>SINGLE, MULTI</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection, DefaultSelection</dd> + * </dl> + * <p> + * Note: Only one of SINGLE and MULTI may be specified. + * </p><p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ + +public class List extends Scrollable { + static final int INSET = 3; + static final int ListProc; + static final TCHAR ListClass = new TCHAR (0, "LISTBOX", true); + static { + WNDCLASS lpWndClass = new WNDCLASS (); + OS.GetClassInfo (0, ListClass, lpWndClass); + ListProc = lpWndClass.lpfnWndProc; + } + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>DWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>DWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a composite control which will be the parent of the new instance (cannot be null) + * @param style the style of control to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> + * </ul> + * + * @see DWT#SINGLE + * @see DWT#MULTI + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public List (Composite parent, int style) { + super (parent, checkStyle (style)); +} +/** + * Adds the argument to the end of the receiver's list. + * + * @param string the new item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #add(String,int) + */ +public void add (String string) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer); + if (result is OS.LB_ERR) error (DWT.ERROR_ITEM_NOT_ADDED); + if (result is OS.LB_ERRSPACE) error (DWT.ERROR_ITEM_NOT_ADDED); + if ((style & DWT.H_SCROLL) !is 0) setScrollWidth (buffer, true); +} +/** + * Adds the argument to the receiver's list at the given + * zero-relative index. + * <p> + * Note: To add an item at the end of the list, use the + * result of calling <code>getItemCount()</code> as the + * index or use <code>add(String)</code>. + * </p> + * + * @param string the new item + * @param index the index for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #add(String) + */ +public void add (String string, int index) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + if (index is -1) error (DWT.ERROR_INVALID_RANGE); + TCHAR buffer = new TCHAR (getCodePage (), string, true); + int result = OS.SendMessage (handle, OS.LB_INSERTSTRING, index, buffer); + if (result is OS.LB_ERRSPACE) error (DWT.ERROR_ITEM_NOT_ADDED); + if (result is OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index <= count) { + error (DWT.ERROR_ITEM_NOT_ADDED); + } else { + error (DWT.ERROR_INVALID_RANGE); + } + } + if ((style & DWT.H_SCROLL) !is 0) setScrollWidth (buffer, true); +} + +/** + * Adds the listener to the collection of listeners who will + * be notified when the user changes the receiver's selection, by sending + * it one of the messages defined in the <code>SelectionListener</code> + * interface. + * <p> + * <code>widgetSelected</code> is called when the selection changes. + * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked. + * </p> + * + * @param listener the listener which should be notified when the user changes the receiver's selection + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #removeSelectionListener + * @see SelectionEvent + */ +public void addSelectionListener(SelectionListener listener) { + checkWidget (); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (DWT.Selection,typedListener); + addListener (DWT.DefaultSelection,typedListener); +} + +int callWindowProc (int hwnd, int msg, int wParam, int lParam) { + if (handle is 0) return 0; + return OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam); +} + +static int checkStyle (int style) { + return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0); +} + +public Point computeSize (int wHint, int hHint, bool changed) { + checkWidget (); + int width = 0, height = 0; + if (wHint is DWT.DEFAULT) { + if ((style & DWT.H_SCROLL) !is 0) { + width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0); + width -= INSET; + } else { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + RECT rect = new RECT (); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + int cp = getCodePage (); + TCHAR buffer = new TCHAR (cp, 64 + 1); + for (int i=0; i<count; i++) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0); + if (length !is OS.LB_ERR) { + if (length + 1 > buffer.length ()) { + buffer = new TCHAR (cp, length + 1); + } + int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer); + if (result !is OS.LB_ERR) { + OS.DrawText (hDC, buffer, length, rect, flags); + width = Math.max (width, rect.right - rect.left); + } + } + } + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + } + } + if (hHint is DWT.DEFAULT) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int itemHeight = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + height = count * itemHeight; + } + if (width is 0) width = DEFAULT_WIDTH; + if (height is 0) height = DEFAULT_HEIGHT; + if (wHint !is DWT.DEFAULT) width = wHint; + if (hHint !is DWT.DEFAULT) height = hHint; + int border = getBorderWidth (); + width += border * 2 + INSET; + height += border * 2; + if ((style & DWT.V_SCROLL) !is 0) { + width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); + } + if ((style & DWT.H_SCROLL) !is 0) { + height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); + } + return new Point (width, height); +} + +int defaultBackground () { + return OS.GetSysColor (OS.COLOR_WINDOW); +} + +/** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is selected, it is deselected. If the item at the index + * was not selected, it remains deselected. Indices that are out + * of range and duplicate indices are ignored. + * + * @param indices the array of indices for the items to deselect + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int [] indices) { + checkWidget (); + if (indices is null) error (DWT.ERROR_NULL_ARGUMENT); + if (indices.length is 0) return; + if ((style & DWT.SINGLE) !is 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex is OS.LB_ERR) return; + for (int i=0; i<indices.length; i++) { + if (oldIndex is indices [i]) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + return; + } + } + return; + } + for (int i=0; i<indices.length; i++) { + int index = indices [i]; + if (index !is -1) { + OS.SendMessage (handle, OS.LB_SETSEL, 0, index); + } + } +} + +/** + * Deselects the item at the given zero-relative index in the receiver. + * If the item at the index was already deselected, it remains + * deselected. Indices that are out of range are ignored. + * + * @param index the index of the item to deselect + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int index) { + checkWidget (); + if (index is -1) return; + if ((style & DWT.SINGLE) !is 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex is OS.LB_ERR) return; + if (oldIndex is index) OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + return; + } + OS.SendMessage (handle, OS.LB_SETSEL, 0, index); +} + +/** + * Deselects the items at the given zero-relative indices in the receiver. + * If the item at the given zero-relative index in the receiver + * is selected, it is deselected. If the item at the index + * was not selected, it remains deselected. The range of the + * indices is inclusive. Indices that are out of range are ignored. + * + * @param start the start index of the items to deselect + * @param end the end index of the items to deselect + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselect (int start, int end) { + checkWidget (); + if (start > end) return; + if ((style & DWT.SINGLE) !is 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex is OS.LB_ERR) return; + if (start <= oldIndex && oldIndex <= end) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + } + return; + } + /* + * Ensure that at least one item is contained in + * the range from start to end. Note that when + * start = end, LB_SELITEMRANGEEX deselects the + * item. + */ + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (start < 0 && end < 0) return; + if (start >= count && end >= count) return; + start = Math.min (count - 1, Math.max (0, start)); + end = Math.min (count - 1, Math.max (0, end)); + OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, end, start); +} + +/** + * Deselects all selected items in the receiver. + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void deselectAll () { + checkWidget (); + if ((style & DWT.SINGLE) !is 0) { + OS.SendMessage (handle, OS.LB_SETCURSEL, -1, 0); + } else { + OS.SendMessage (handle, OS.LB_SETSEL, 0, -1); + } +} + +/** + * Returns the zero-relative index of the item which currently + * has the focus in the receiver, or -1 if no item has focus. + * + * @return the index of the selected item + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getFocusIndex () { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + if (result is 0) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (count is 0) return -1; + } + return result; +} + +/** + * Returns the item at the given, zero-relative index in the + * receiver. Throws an exception if the index is out of range. + * + * @param index the index of the item to return + * @return the item at the given index + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public String getItem (int index) { + checkWidget (); + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length !is OS.LB_ERR) { + TCHAR buffer = new TCHAR (getCodePage (), length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result !is OS.LB_ERR) return buffer.toString (0, length); + } + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (DWT.ERROR_CANNOT_GET_ITEM); + error (DWT.ERROR_INVALID_RANGE); + return ""; +} + +/** + * Returns the number of items contained in the receiver. + * + * @return the number of items + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getItemCount () { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (result is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_COUNT); + return result; +} + +/** + * Returns the height of the area which would be used to + * display <em>one</em> of the items in the list. + * + * @return the height of one item + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getItemHeight () { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + if (result is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_ITEM_HEIGHT); + return result; +} + +/** + * Returns a (possibly empty) array of <code>String</code>s which + * are the items in the receiver. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its list of items, so modifying the array will + * not affect the receiver. + * </p> + * + * @return the items in the receiver's list + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public String [] getItems () { + checkWidget (); + int count = getItemCount (); + String [] result = new String [count]; + for (int i=0; i<count; i++) result [i] = getItem (i); + return result; +} + +/** + * Returns an array of <code>String</code>s that are currently + * selected in the receiver. The order of the items is unspecified. + * An empty array indicates that no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its selection, so modifying the array will + * not affect the receiver. + * </p> + * @return an array representing the selection + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public String [] getSelection () { + checkWidget (); + int [] indices = getSelectionIndices (); + String [] result = new String [indices.length]; + for (int i=0; i<indices.length; i++) { + result [i] = getItem (indices [i]); + } + return result; +} + +/** + * Returns the number of selected items contained in the receiver. + * + * @return the number of selected items + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getSelectionCount () { + checkWidget (); + if ((style & DWT.SINGLE) !is 0) { + int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (result is OS.LB_ERR) return 0; + return 1; + } + int result = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (result is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_COUNT); + return result; +} + +/** + * Returns the zero-relative index of the item which is currently + * selected in the receiver, or -1 if no item is selected. + * + * @return the index of the selected item or -1 + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getSelectionIndex () { + checkWidget (); + if ((style & DWT.SINGLE) !is 0) { + return OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + } + int count = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (count is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_SELECTION); + if (count is 0) return -1; + int index = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0); + if (result is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_SELECTION); + if (result !is 0) return index; + int [] buffer = new int [1]; + result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, buffer); + if (result !is 1) error (DWT.ERROR_CANNOT_GET_SELECTION); + return buffer [0]; +} + +/** + * Returns the zero-relative indices of the items which are currently + * selected in the receiver. The order of the indices is unspecified. + * The array is empty if no items are selected. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its selection, so modifying the array will + * not affect the receiver. + * </p> + * @return the array of indices of the selected items + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int [] getSelectionIndices () { + checkWidget (); + if ((style & DWT.SINGLE) !is 0) { + int result = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (result is OS.LB_ERR) return new int [0]; + return new int [] {result}; + } + int length = OS.SendMessage (handle, OS.LB_GETSELCOUNT, 0, 0); + if (length is OS.LB_ERR) error (DWT.ERROR_CANNOT_GET_SELECTION); + int [] indices = new int [length]; + int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, length, indices); + if (result !is length) error (DWT.ERROR_CANNOT_GET_SELECTION); + return indices; +} + +/** + * Returns the zero-relative index of the item which is currently + * at the top of the receiver. This index can change when items are + * scrolled or new items are added or removed. + * + * @return the index of the top item + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int getTopIndex () { + checkWidget (); + return OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); +} + +/** + * Gets the index of an item. + * <p> + * The list is searched starting at 0 until an + * item is found that is equal to the search item. + * If no item is found, -1 is returned. Indexing + * is zero based. + * + * @param string the search item + * @return the index of the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int indexOf (String string) { + return indexOf (string, 0); +} + +/** + * Searches the receiver's list starting at the given, + * zero-relative index until an item is found that is equal + * to the argument, and returns the index of that item. If + * no item is found or the starting index is out of range, + * returns -1. + * + * @param string the search item + * @param start the zero-relative index at which to start the search + * @return the index of the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public int indexOf (String string, int start) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + + /* + * Bug in Windows. For some reason, LB_FINDSTRINGEXACT + * will not find empty strings even though it is legal + * to insert an empty string into a list. The fix is + * to search the list, an item at a time. + */ + if (string.length () is 0) { + int count = getItemCount (); + for (int i=start; i<count; i++) { + if (string.equals (getItem (i))) return i; + } + return -1; + } + + /* Use LB_FINDSTRINGEXACT to search for the item */ + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (!(0 <= start && start < count)) return -1; + int index = start - 1, last; + TCHAR buffer = new TCHAR (getCodePage (), string, true); + do { + index = OS.SendMessage (handle, OS.LB_FINDSTRINGEXACT, last = index, buffer); + if (index is OS.LB_ERR || index <= last) return -1; + } while (!string.equals (getItem (index))); + return index; +} + +/** + * Returns <code>true</code> if the item is selected, + * and <code>false</code> otherwise. Indices out of + * range are ignored. + * + * @param index the index of the item + * @return the selection state of the item at the index + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public bool isSelected (int index) { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_GETSEL, index, 0); + return (result !is 0) && (result !is OS.LB_ERR); +} + +/** + * Removes the items from the receiver at the given + * zero-relative indices. + * + * @param indices the array of indices of the items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int [] indices) { + checkWidget (); + if (indices is null) error (DWT.ERROR_NULL_ARGUMENT); + if (indices.length is 0) return; + int [] newIndices = new int [indices.length]; + System.arraycopy (indices, 0, newIndices, 0, indices.length); + sort (newIndices); + int start = newIndices [newIndices.length - 1], end = newIndices [0]; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (!(0 <= start && start <= end && end < count)) { + error (DWT.ERROR_INVALID_RANGE); + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & DWT.H_SCROLL) !is 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + } + int cp = getCodePage (); + int i = 0, topCount = 0, last = -1; + while (i < newIndices.length) { + int index = newIndices [i]; + if (index !is last) { + TCHAR buffer = null; + if ((style & DWT.H_SCROLL) !is 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length is OS.LB_ERR) break; + buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result is OS.LB_ERR) break; + } + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0); + if (result is OS.LB_ERR) break; + if ((style & DWT.H_SCROLL) !is 0) { + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + if (index < topIndex) topCount++; + last = index; + } + i++; + } + if ((style & DWT.H_SCROLL) !is 0) { + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (newWidth, false); + } + if (topCount > 0) { + topIndex -= topCount; + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + } + if (i < newIndices.length) error (DWT.ERROR_ITEM_NOT_REMOVED); +} + +/** + * Removes the item from the receiver at the given + * zero-relative index. + * + * @param index the index for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int index) { + checkWidget (); + TCHAR buffer = null; + if ((style & DWT.H_SCROLL) !is 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, index, 0); + if (length is OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (DWT.ERROR_ITEM_NOT_REMOVED); + error (DWT.ERROR_INVALID_RANGE); + } + buffer = new TCHAR (getCodePage (), length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, index, buffer); + if (result is OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (DWT.ERROR_ITEM_NOT_REMOVED); + error (DWT.ERROR_INVALID_RANGE); + } + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, index, 0); + if (result is OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (0 <= index && index < count) error (DWT.ERROR_ITEM_NOT_REMOVED); + error (DWT.ERROR_INVALID_RANGE); + } + if ((style & DWT.H_SCROLL) !is 0) setScrollWidth (buffer, false); + if (index < topIndex) { + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex - 1, 0); + } +} + +/** + * Removes the items from the receiver which are + * between the given zero-relative start and end + * indices (inclusive). + * + * @param start the start of the range + * @param end the end of the range + * + * @exception IllegalArgumentException <ul> + * <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> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (int start, int end) { + checkWidget (); + if (start > end) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (!(0 <= start && start <= end && end < count)) { + error (DWT.ERROR_INVALID_RANGE); + } + if (start is 0 && end is count - 1) { + removeAll (); + return; + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & DWT.H_SCROLL) !is 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + } + int cp = getCodePage (); + int index = start; + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + while (index <= end) { + TCHAR buffer = null; + if ((style & DWT.H_SCROLL) !is 0) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, start, 0); + if (length is OS.LB_ERR) break; + buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, start, buffer); + if (result is OS.LB_ERR) break; + } + int result = OS.SendMessage (handle, OS.LB_DELETESTRING, start, 0); + if (result is OS.LB_ERR) break; + if ((style & DWT.H_SCROLL) !is 0) { + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + index++; + } + if ((style & DWT.H_SCROLL) !is 0) { + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (newWidth, false); + } + if (end < topIndex) { + topIndex -= end - start + 1; + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + } + if (index <= end) error (DWT.ERROR_ITEM_NOT_REMOVED); +} + +/** + * Searches the receiver's list starting at the first item + * until an item is found that is equal to the argument, + * and removes that item from the list. + * + * @param string the item to remove + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void remove (String string) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + int index = indexOf (string, 0); + if (index is -1) error (DWT.ERROR_INVALID_ARGUMENT); + remove (index); +} + +/** + * Removes all of the items from the receiver. + * <p> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void removeAll () { + checkWidget (); + OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0); + if ((style & DWT.H_SCROLL) !is 0) { + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0); + } +} + +/** + * Removes the listener from the collection of listeners who will + * be notified when the user changes the receiver's selection. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SelectionListener + * @see #addSelectionListener + */ +public void removeSelectionListener(SelectionListener listener) { + checkWidget (); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + if (eventTable is null) return; + eventTable.unhook (DWT.Selection, listener); + eventTable.unhook (DWT.DefaultSelection,listener); +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is not cleared before the new items are selected. + * <p> + * If the item at a given index is not selected, it is selected. + * If the item at a given index was already selected, it remains selected. + * Indices that are out of range and duplicate indices are ignored. + * If the receiver is single-select and multiple indices are specified, + * then all indices are ignored. + * + * @param indices the array of indices for the items to select + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int[]) + */ +public void select (int [] indices) { + checkWidget (); + if (indices is null) error (DWT.ERROR_NULL_ARGUMENT); + int length = indices.length; + if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return; + select (indices, false); +} + +void select (int [] indices, bool scroll) { + int i = 0; + while (i < indices.length) { + int index = indices [i]; + if (index !is -1) { + select (index, false); + } + i++; + } + if (scroll) showSelection (); +} + +/** + * Selects the item at the given zero-relative index in the receiver's + * list. If the item at the index was already selected, it remains + * selected. Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void select (int index) { + checkWidget (); + select (index, false); +} + +void select (int index, bool scroll) { + if (index < 0) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (index >= count) return; + if (scroll) { + if ((style & DWT.SINGLE) !is 0) { + OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0); + } else { + OS.SendMessage (handle, OS.LB_SETSEL, 1, index); + } + return; + } + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + RECT itemRect = new RECT (), selectedRect = null; + OS.SendMessage (handle, OS.LB_GETITEMRECT, index, itemRect); + bool redraw = drawCount is 0 && OS.IsWindowVisible (handle); + if (redraw) { + OS.UpdateWindow (handle); + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + int focusIndex = -1; + if ((style & DWT.SINGLE) !is 0) { + int oldIndex = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + if (oldIndex !is -1) { + selectedRect = new RECT (); + OS.SendMessage (handle, OS.LB_GETITEMRECT, oldIndex, selectedRect); + } + OS.SendMessage (handle, OS.LB_SETCURSEL, index, 0); + } else { + focusIndex = OS.SendMessage (handle, OS.LB_GETCARETINDEX, 0, 0); + OS.SendMessage (handle, OS.LB_SETSEL, 1, index); + } + if ((style & DWT.MULTI) !is 0) { + if (focusIndex !is -1) { + OS.SendMessage (handle, OS.LB_SETCARETINDEX, focusIndex, 0); + } + } + OS.SendMessage (handle, OS.LB_SETTOPINDEX, topIndex, 0); + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + OS.ValidateRect (handle, null); + OS.InvalidateRect (handle, itemRect, true); + if (selectedRect !is null) { + OS.InvalidateRect (handle, selectedRect, true); + } + } +} + +/** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. + * The current selection is not cleared before the new items are selected. + * <p> + * If an item in the given range is not selected, it is selected. + * If an item in the given range was already selected, it remains selected. + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * If the receiver is single-select and there is more than one item in the + * given range, then all indices are ignored. + * + * @param start the start of the range + * @param end the end of the range + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#setSelection(int,int) + */ +public void select (int start, int end) { + checkWidget (); + if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (count is 0 || start >= count) return; + start = Math.max (0, start); + end = Math.min (end, count - 1); + if ((style & DWT.SINGLE) !is 0) { + select (start, false); + } else { + select (start, end, false); + } +} + +void select (int start, int end, bool scroll) { + /* + * Note that when start = end, LB_SELITEMRANGEEX + * deselects the item. + */ + if (start is end) { + select (start, scroll); + return; + } + OS.SendMessage (handle, OS.LB_SELITEMRANGEEX, start, end); + if (scroll) showSelection (); +} + +/** + * Selects all of the items in the receiver. + * <p> + * If the receiver is single-select, do nothing. + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void selectAll () { + checkWidget (); + if ((style & DWT.SINGLE) !is 0) return; + OS.SendMessage (handle, OS.LB_SETSEL, 1, -1); +} + +void setFocusIndex (int index) { +// checkWidget (); + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (!(0 <= index && index < count)) return; + OS.SendMessage (handle, OS.LB_SETCARETINDEX, index, 0); +} + +public void setFont (Font font) { + checkWidget (); + super.setFont (font); + if ((style & DWT.H_SCROLL) !is 0) setScrollWidth (); +} + +/** + * Sets the text of the item in the receiver's list at the given + * zero-relative index to the string argument. + * + * @param index the index for the item + * @param string the new text for the item + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setItem (int index, String string) { + checkWidget (); + if (string is null) error (DWT.ERROR_NULL_ARGUMENT); + int topIndex = getTopIndex (); + bool isSelected = isSelected (index); + remove (index); + add (string, index); + if (isSelected) select (index, false); + setTopIndex (topIndex); +} + +/** + * Sets the receiver's items to be the given array of items. + * + * @param items the array of items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the items array is null</li> + * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setItems (String [] items) { + checkWidget (); + if (items is null) error (DWT.ERROR_NULL_ARGUMENT); + for (int i=0; i<items.length; i++) { + if (items [i] is null) error (DWT.ERROR_INVALID_ARGUMENT); + } + int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC); + OS.SetWindowLong (handle, OS.GWL_WNDPROC, ListProc); + bool redraw = drawCount is 0 && OS.IsWindowVisible (handle); + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); + } + RECT rect = null; + int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0; + if ((style & DWT.H_SCROLL) !is 0) { + rect = new RECT (); + hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, 0, 0); + } + int length = items.length; + OS.SendMessage (handle, OS.LB_RESETCONTENT, 0, 0); + OS.SendMessage (handle, OS.LB_INITSTORAGE, length, length * 32); + int index = 0; + int cp = getCodePage (); + while (index < length) { + String string = items [index]; + TCHAR buffer = new TCHAR (cp, string, true); + int result = OS.SendMessage (handle, OS.LB_ADDSTRING, 0, buffer); + if (result is OS.LB_ERR || result is OS.LB_ERRSPACE) break; + if ((style & DWT.H_SCROLL) !is 0) { + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + index++; + } + if ((style & DWT.H_SCROLL) !is 0) { + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0); + } + if (redraw) { + OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); + /* + * This code is intentionally commented. The window proc + * for the list box implements WM_SETREDRAW to invalidate + * and erase the widget. This is undocumented behavior. + * The commented code below shows what is actually happening + * and reminds us that we are relying on this undocumented + * behavior. + */ +// int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE; +// OS.RedrawWindow (handle, null, 0, flags); + } + OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc); + if (index < items.length) error (DWT.ERROR_ITEM_NOT_ADDED); +} + +void setScrollWidth () { + int newWidth = 0; + RECT rect = new RECT (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + int cp = getCodePage (); + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + for (int i=0; i<count; i++) { + int length = OS.SendMessage (handle, OS.LB_GETTEXTLEN, i, 0); + if (length !is OS.LB_ERR) { + TCHAR buffer = new TCHAR (cp, length + 1); + int result = OS.SendMessage (handle, OS.LB_GETTEXT, i, buffer); + if (result !is OS.LB_ERR) { + OS.DrawText (hDC, buffer, -1, rect, flags); + newWidth = Math.max (newWidth, rect.right - rect.left); + } + } + } + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth + INSET, 0); +} + +void setScrollWidth (TCHAR buffer, bool grow) { + RECT rect = new RECT (); + int newFont, oldFont = 0; + int hDC = OS.GetDC (handle); + newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont !is 0) oldFont = OS.SelectObject (hDC, newFont); + int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX; + OS.DrawText (hDC, buffer, -1, rect, flags); + if (newFont !is 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); + setScrollWidth (rect.right - rect.left, grow); +} + +void setScrollWidth (int newWidth, bool grow) { + newWidth += INSET; + int width = OS.SendMessage (handle, OS.LB_GETHORIZONTALEXTENT, 0, 0); + if (grow) { + if (newWidth <= width) return; + OS.SendMessage (handle, OS.LB_SETHORIZONTALEXTENT, newWidth, 0); + } else { + if (newWidth < width) return; + setScrollWidth (); + } +} + +/** + * Selects the items at the given zero-relative indices in the receiver. + * The current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range and duplicate indices are ignored. + * If the receiver is single-select and multiple indices are specified, + * then all indices are ignored. + * + * @param indices the indices of the items to select + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + */ +public void setSelection(int [] indices) { + checkWidget (); + if (indices is null) error (DWT.ERROR_NULL_ARGUMENT); + deselectAll (); + int length = indices.length; + if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return; + select (indices, true); + if ((style & DWT.MULTI) !is 0) { + int focusIndex = indices [0]; + if (focusIndex >= 0) setFocusIndex (focusIndex); + } +} + +/** + * Sets the receiver's selection to be the given array of items. + * The current selection is cleared before the new items are selected. + * <p> + * Items that are not in the receiver are ignored. + * If the receiver is single-select and multiple items are specified, + * then all items are ignored. + * + * @param items the array of items + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int[]) + * @see List#setSelection(int[]) + */ +public void setSelection (String [] items) { + checkWidget (); + if (items is null) error (DWT.ERROR_NULL_ARGUMENT); + deselectAll (); + int length = items.length; + if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return; + int focusIndex = -1; + for (int i=length-1; i>=0; --i) { + String string = items [i]; + int index = 0; + if (string !is null) { + int localFocus = -1; + while ((index = indexOf (string, index)) !is -1) { + if (localFocus is -1) localFocus = index; + select (index, false); + if ((style & DWT.SINGLE) !is 0 && isSelected (index)) { + showSelection (); + return; + } + index++; + } + if (localFocus !is -1) focusIndex = localFocus; + } + } + if ((style & DWT.MULTI) !is 0) { + if (focusIndex >= 0) setFocusIndex (focusIndex); + } +} + +/** + * Selects the item at the given zero-relative index in the receiver. + * If the item at the index was already selected, it remains selected. + * The current selection is first cleared, then the new item is selected. + * Indices that are out of range are ignored. + * + * @param index the index of the item to select + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * @see List#deselectAll() + * @see List#select(int) + */ +public void setSelection (int index) { + checkWidget (); + deselectAll (); + select (index, true); + if ((style & DWT.MULTI) !is 0) { + if (index >= 0) setFocusIndex (index); + } +} + +/** + * Selects the items in the range specified by the given zero-relative + * indices in the receiver. The range of indices is inclusive. + * The current selection is cleared before the new items are selected. + * <p> + * Indices that are out of range are ignored and no items will be selected + * if start is greater than end. + * If the receiver is single-select and there is more than one item in the + * given range, then all indices are ignored. + * + * @param start the start index of the items to select + * @param end the end index of the items to select + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see List#deselectAll() + * @see List#select(int,int) + */ +public void setSelection (int start, int end) { + checkWidget (); + deselectAll (); + if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (count is 0 || start >= count) return; + start = Math.max (0, start); + end = Math.min (end, count - 1); + if ((style & DWT.SINGLE) !is 0) { + select (start, true); + } else { + select (start, end, true); + setFocusIndex (start); + } +} + +/** + * Sets the zero-relative index of the item which is currently + * at the top of the receiver. This index can change when items + * are scrolled or new items are added and removed. + * + * @param index the index of the top item + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setTopIndex (int index) { + checkWidget (); + int result = OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0); + if (result is OS.LB_ERR) { + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + index = Math.min (count - 1, Math.max (0, index)); + OS.SendMessage (handle, OS.LB_SETTOPINDEX, index, 0); + } +} + +/** + * Shows the selection. If the selection is already showing in the receiver, + * this method simply returns. Otherwise, the items are scrolled until + * the selection is visible. + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void showSelection () { + checkWidget (); + int index; + if ((style & DWT.SINGLE) !is 0) { + index = OS.SendMessage (handle, OS.LB_GETCURSEL, 0, 0); + } else { + int [] indices = new int [1]; + int result = OS.SendMessage (handle, OS.LB_GETSELITEMS, 1, indices); + index = indices [0]; + if (result !is 1) index = -1; + } + if (index is -1) return; + int count = OS.SendMessage (handle, OS.LB_GETCOUNT, 0, 0); + if (count is 0) return; + int height = OS.SendMessage (handle, OS.LB_GETITEMHEIGHT, 0, 0); + forceResize (); + RECT rect = new RECT (); + OS.GetClientRect (handle, rect); + int topIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + int visibleCount = Math.max (rect.bottom / height, 1); + int bottomIndex = Math.min (topIndex + visibleCount, count) - 1; + if (topIndex <= index && index <= bottomIndex) return; + int newTop = Math.min (Math.max (index - (visibleCount / 2), 0), count - 1); + OS.SendMessage (handle, OS.LB_SETTOPINDEX, newTop, 0); +} + +int widgetStyle () { + int bits = super.widgetStyle () | OS.LBS_NOTIFY | OS.LBS_NOINTEGRALHEIGHT; + if ((style & DWT.SINGLE) !is 0) return bits; + if ((style & DWT.MULTI) !is 0) { + if ((style & DWT.SIMPLE) !is 0) return bits | OS.LBS_MULTIPLESEL; + return bits | OS.LBS_EXTENDEDSEL; + } + return bits; +} + +TCHAR windowClass () { + return ListClass; +} + +int windowProc () { + return ListProc; +} + +LRESULT WM_SIZE (int wParam, int lParam) { + /* + * Bug in Windows. If the top index is changed while the + * list is being resized, Windows does not redraw properly + * when their is white space at the bottom of the control. + * The fix is to detect when the top index has changed and + * redraw the control. + * + * Bug in Windows. If the receiver is scrolled horizontally + * and is resized, the list does not redraw properly. The fix + * is to redraw the control when the horizontal scroll bar is + * not at the beginning. + */ + int oldIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + LRESULT result = super.WM_SIZE (wParam, lParam); + if (!isDisposed ()) { + SCROLLINFO info = new SCROLLINFO (); + info.cbSize = SCROLLINFO.sizeof; + info.fMask = OS.SIF_POS; + if (OS.GetScrollInfo (handle, OS.SB_HORZ, info)) { + if (info.nPos !is 0) OS.InvalidateRect (handle, null, true); + } + int newIndex = OS.SendMessage (handle, OS.LB_GETTOPINDEX, 0, 0); + if (oldIndex !is newIndex) OS.InvalidateRect (handle, null, true); + } + return result; +} + +LRESULT wmCommandChild (int wParam, int lParam) { + int code = wParam >> 16; + switch (code) { + case OS.LBN_SELCHANGE: + postEvent (DWT.Selection); + break; + case OS.LBN_DBLCLK: + postEvent (DWT.DefaultSelection); + break; + } + return super.wmCommandChild (wParam, lParam); +} + + + +} +++/ \ No newline at end of file