KickJava   Java API By Example, From Geeks To Geeks.

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


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.*;
15 import org.eclipse.swt.internal.win32.*;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.graphics.*;
18 import org.eclipse.swt.events.*;
19
20 /**
21  * Instances of this class are controls that allow the user
22  * to choose an item from a list of items, or optionally
23  * enter a new value by typing it into an editable text
24  * field. Often, <code>Combo</code>s are used in the same place
25  * where a single selection <code>List</code> widget could
26  * be used but space is limited. A <code>Combo</code> takes
27  * less space than a <code>List</code> widget and shows
28  * similar information.
29  * <p>
30  * Note: Since <code>Combo</code>s can contain both a list
31  * and an editable text field, it is possible to confuse methods
32  * which access one versus the other (compare for example,
33  * <code>clearSelection()</code> and <code>deselectAll()</code>).
34  * The API documentation is careful to indicate either "the
35  * receiver's list" or the "the receiver's text field" to
36  * distinguish between the two cases.
37  * </p><p>
38  * Note that although this class is a subclass of <code>Composite</code>,
39  * it does not make sense to add children to it, or set a layout on it.
40  * </p>
41  * <dl>
42  * <dt><b>Styles:</b></dt>
43  * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd>
44  * <dt><b>Events:</b></dt>
45  * <dd>DefaultSelection, Modify, Selection, Verify</dd>
46  * </dl>
47  * <p>
48  * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
49  * </p><p>
50  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
51  * </p>
52  *
53  * @see List
54  */

55
56 public class Combo extends Composite {
57     boolean noSelection, ignoreDefaultSelection, ignoreCharacter, ignoreModify;
58     int cbtHook, scrollWidth, visibleCount = 5;
59     
60     /**
61      * the operating system limit for the number of characters
62      * that the text field in an instance of this class can hold
63      */

64     public static final int LIMIT;
65     
66     /*
67      * These values can be different on different platforms.
68      * Therefore they are not initialized in the declaration
69      * to stop the compiler from inlining.
70      */

71     static {
72         LIMIT = OS.IsWinNT ? 0x7FFFFFFF : 0x7FFF;
73     }
74     
75     /*
76      * These are the undocumented control id's for the children of
77      * a combo box. Since there are no constants for these values,
78      * they may change with different versions of Windows (but have
79      * been the same since Windows 3.0).
80      */

81     static final int CBID_LIST = 1000;
82     static final int CBID_EDIT = 1001;
83     static /*final*/ int EditProc, ListProc;
84     
85     static final int ComboProc;
86     static final TCHAR ComboClass = new TCHAR (0, "COMBOBOX", true);
87     static {
88         WNDCLASS lpWndClass = new WNDCLASS ();
89         OS.GetClassInfo (0, ComboClass, lpWndClass);
90         ComboProc = lpWndClass.lpfnWndProc;
91     }
92     
93 /**
94  * Constructs a new instance of this class given its parent
95  * and a style value describing its behavior and appearance.
96  * <p>
97  * The style value is either one of the style constants defined in
98  * class <code>SWT</code> which is applicable to instances of this
99  * class, or must be built by <em>bitwise OR</em>'ing together
100  * (that is, using the <code>int</code> "|" operator) two or more
101  * of those <code>SWT</code> style constants. The class description
102  * lists the style constants that are applicable to the class.
103  * Style bits are also inherited from superclasses.
104  * </p>
105  *
106  * @param parent a composite control which will be the parent of the new instance (cannot be null)
107  * @param style the style of control to construct
108  *
109  * @exception IllegalArgumentException <ul>
110  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
111  * </ul>
112  * @exception SWTException <ul>
113  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
114  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
115  * </ul>
116  *
117  * @see SWT#DROP_DOWN
118  * @see SWT#READ_ONLY
119  * @see SWT#SIMPLE
120  * @see Widget#checkSubclass
121  * @see Widget#getStyle
122  */

123 public Combo (Composite parent, int style) {
124     super (parent, checkStyle (style));
125     /* This code is intentionally commented */
126     //if ((style & SWT.H_SCROLL) != 0) this.style |= SWT.H_SCROLL;
127
this.style |= SWT.H_SCROLL;
128 }
129
130 /**
131  * Adds the argument to the end of the receiver's list.
132  *
133  * @param string the new item
134  *
135  * @exception IllegalArgumentException <ul>
136  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
137  * </ul>
138  * @exception SWTException <ul>
139  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
140  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
141  * </ul>
142  *
143  * @see #add(String,int)
144  */

145 public void add (String JavaDoc string) {
146     checkWidget ();
147     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
148     TCHAR buffer = new TCHAR (getCodePage (), string, true);
149     int result = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
150     if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
151     if (result == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
152     if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
153 }
154
155 /**
156  * Adds the argument to the receiver's list at the given
157  * zero-relative index.
158  * <p>
159  * Note: To add an item at the end of the list, use the
160  * result of calling <code>getItemCount()</code> as the
161  * index or use <code>add(String)</code>.
162  * </p>
163  *
164  * @param string the new item
165  * @param index the index for the item
166  *
167  * @exception IllegalArgumentException <ul>
168  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
169  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
170  * </ul>
171  * @exception SWTException <ul>
172  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
173  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
174  * </ul>
175  *
176  * @see #add(String)
177  */

178 public void add (String JavaDoc string, int index) {
179     checkWidget ();
180     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
181     int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
182     if (!(0 <= index && index <= count)) {
183         error (SWT.ERROR_INVALID_RANGE);
184     }
185     TCHAR buffer = new TCHAR (getCodePage (), string, true);
186     int result = OS.SendMessage (handle, OS.CB_INSERTSTRING, index, buffer);
187     if (result == OS.CB_ERRSPACE || result == OS.CB_ERR) {
188         error (SWT.ERROR_ITEM_NOT_ADDED);
189     }
190     if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
191 }
192
193 /**
194  * Adds the listener to the collection of listeners who will
195  * be notified when the receiver's text is modified, by sending
196  * it one of the messages defined in the <code>ModifyListener</code>
197  * interface.
198  *
199  * @param listener the listener which should be notified
200  *
201  * @exception IllegalArgumentException <ul>
202  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
203  * </ul>
204  * @exception SWTException <ul>
205  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
206  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
207  * </ul>
208  *
209  * @see ModifyListener
210  * @see #removeModifyListener
211  */

212 public void addModifyListener (ModifyListener listener) {
213     checkWidget ();
214     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
215     TypedListener typedListener = new TypedListener (listener);
216     addListener (SWT.Modify, typedListener);
217 }
218
219 /**
220  * Adds the listener to the collection of listeners who will
221  * be notified when the user changes the receiver's selection, by sending
222  * it one of the messages defined in the <code>SelectionListener</code>
223  * interface.
224  * <p>
225  * <code>widgetSelected</code> is called when the user changes the combo's list selection.
226  * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
227  * </p>
228  *
229  * @param listener the listener which should be notified
230  *
231  * @exception IllegalArgumentException <ul>
232  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
233  * </ul>
234  * @exception SWTException <ul>
235  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
236  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
237  * </ul>
238  *
239  * @see SelectionListener
240  * @see #removeSelectionListener
241  * @see SelectionEvent
242  */

243 public void addSelectionListener(SelectionListener listener) {
244     checkWidget ();
245     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
246     TypedListener typedListener = new TypedListener (listener);
247     addListener (SWT.Selection,typedListener);
248     addListener (SWT.DefaultSelection,typedListener);
249 }
250
251 /**
252  * Adds the listener to the collection of listeners who will
253  * be notified when the receiver's text is verified, by sending
254  * it one of the messages defined in the <code>VerifyListener</code>
255  * interface.
256  *
257  * @param listener the listener which should be notified
258  *
259  * @exception IllegalArgumentException <ul>
260  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
261  * </ul>
262  * @exception SWTException <ul>
263  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
264  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
265  * </ul>
266  *
267  * @see VerifyListener
268  * @see #removeVerifyListener
269  *
270  * @since 3.1
271  */

272 public void addVerifyListener (VerifyListener listener) {
273     checkWidget ();
274     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
275     TypedListener typedListener = new TypedListener (listener);
276     addListener (SWT.Verify, typedListener);
277 }
278
279 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
280     if (handle == 0) return 0;
281     if (hwnd == handle) {
282         return OS.CallWindowProc (ComboProc, hwnd, msg, wParam, lParam);
283     }
284     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
285     if (hwnd == hwndText) {
286         return OS.CallWindowProc (EditProc, hwnd, msg, wParam, lParam);
287     }
288     int hwndList = OS.GetDlgItem (handle, CBID_LIST);
289     if (hwnd == hwndList) {
290         return OS.CallWindowProc (ListProc, hwnd, msg, wParam, lParam);
291     }
292     return OS.DefWindowProc (hwnd, msg, wParam, lParam);
293 }
294
295 int CBTProc (int nCode, int wParam, int lParam) {
296     if (nCode == OS.HCBT_CREATEWND) {
297         TCHAR buffer = new TCHAR (0, 128);
298         OS.GetClassName (wParam, buffer, buffer.length ());
299         String JavaDoc className = buffer.toString (0, buffer.strlen ());
300         if (className.equals ("Edit") || className.equals ("EDIT")) { //$NON-NLS-1$ //$NON-NLS-2$
301
int bits = OS.GetWindowLong (wParam, OS.GWL_STYLE);
302             OS.SetWindowLong (wParam, OS.GWL_STYLE, bits & ~OS.ES_NOHIDESEL);
303         }
304     }
305     return OS.CallNextHookEx (cbtHook, nCode, wParam, lParam);
306 }
307
308 boolean checkHandle (int hwnd) {
309     return hwnd == handle || hwnd == OS.GetDlgItem (handle, CBID_EDIT) || hwnd == OS.GetDlgItem (handle, CBID_LIST);
310 }
311
312 protected void checkSubclass () {
313     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
314 }
315
316 static int checkStyle (int style) {
317     /*
318      * Feature in Windows. It is not possible to create
319      * a combo box that has a border using Windows style
320      * bits. All combo boxes draw their own border and
321      * do not use the standard Windows border styles.
322      * Therefore, no matter what style bits are specified,
323      * clear the BORDER bits so that the SWT style will
324      * match the Windows widget.
325      *
326      * The Windows behavior is currently implemented on
327      * all platforms.
328      */

329     style &= ~SWT.BORDER;
330     
331     /*
332      * Even though it is legal to create this widget
333      * with scroll bars, they serve no useful purpose
334      * because they do not automatically scroll the
335      * widget's client area. The fix is to clear
336      * the SWT style.
337      */

338     style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
339     style = checkBits (style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0);
340     if ((style & SWT.SIMPLE) != 0) return style & ~SWT.READ_ONLY;
341     return style;
342 }
343
344 /**
345  * Sets the selection in the receiver's text field to an empty
346  * selection starting just before the first character. If the
347  * text field is editable, this has the effect of placing the
348  * i-beam at the start of the text.
349  * <p>
350  * Note: To clear the selected items in the receiver's list,
351  * use <code>deselectAll()</code>.
352  * </p>
353  *
354  * @exception SWTException <ul>
355  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
356  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
357  * </ul>
358  *
359  * @see #deselectAll
360  */

361 public void clearSelection () {
362     checkWidget ();
363     OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, -1);
364 }
365
366 public Point computeSize (int wHint, int hHint, boolean changed) {
367     checkWidget ();
368     int width = 0, height = 0;
369     if (wHint == SWT.DEFAULT) {
370         int newFont, oldFont = 0;
371         int hDC = OS.GetDC (handle);
372         newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
373         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
374         int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
375         RECT rect = new RECT ();
376         int flags = OS.DT_CALCRECT | OS.DT_NOPREFIX;
377         if ((style & SWT.READ_ONLY) == 0) flags |= OS.DT_EDITCONTROL;
378         int length = OS.GetWindowTextLength (handle);
379         int cp = getCodePage ();
380         TCHAR buffer = new TCHAR (cp, length + 1);
381         OS.GetWindowText (handle, buffer, length + 1);
382         OS.DrawText (hDC, buffer, length, rect, flags);
383         width = Math.max (width, rect.right - rect.left);
384         if ((style & SWT.H_SCROLL) != 0) {
385             width = Math.max (width, scrollWidth);
386         } else {
387             for (int i=0; i<count; i++) {
388                 length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, i, 0);
389                 if (length != OS.CB_ERR) {
390                     if (length + 1 > buffer.length ()) buffer = new TCHAR (cp, length + 1);
391                     int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, i, buffer);
392                     if (result != OS.CB_ERR) {
393                         OS.DrawText (hDC, buffer, length, rect, flags);
394                         width = Math.max (width, rect.right - rect.left);
395                     }
396                 }
397             }
398         }
399         if (newFont != 0) OS.SelectObject (hDC, oldFont);
400         OS.ReleaseDC (handle, hDC);
401     }
402     if (hHint == SWT.DEFAULT) {
403         if ((style & SWT.SIMPLE) != 0) {
404             int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
405             int itemHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
406             height = count * itemHeight;
407         }
408     }
409     if (width == 0) width = DEFAULT_WIDTH;
410     if (height == 0) height = DEFAULT_HEIGHT;
411     if (wHint != SWT.DEFAULT) width = wHint;
412     if (hHint != SWT.DEFAULT) height = hHint;
413     if ((style & SWT.READ_ONLY) != 0) {
414         width += 8;
415     } else {
416         int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
417         if (hwndText != 0) {
418             int margins = OS.SendMessage (hwndText, OS.EM_GETMARGINS, 0, 0);
419             int marginWidth = (margins & 0xFFFF) + ((margins >> 16) & 0xFFFF);
420             width += marginWidth + 3;
421         }
422     }
423     COMBOBOXINFO pcbi = new COMBOBOXINFO ();
424     pcbi.cbSize = COMBOBOXINFO.sizeof;
425     if (((style & SWT.SIMPLE) == 0) && !OS.IsWinCE && OS.GetComboBoxInfo (handle, pcbi)) {
426         width += pcbi.itemLeft + (pcbi.buttonRight - pcbi.buttonLeft);
427         height = (pcbi.buttonBottom - pcbi.buttonTop) + pcbi.buttonTop * 2;
428     } else {
429         int border = OS.GetSystemMetrics (OS.SM_CXEDGE);
430         width += OS.GetSystemMetrics (OS.SM_CXVSCROLL) + border * 2;
431         int textHeight = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
432         if ((style & SWT.DROP_DOWN) != 0) {
433             height = textHeight + 6;
434         } else {
435             height += textHeight + 10;
436         }
437     }
438     if ((style & SWT.SIMPLE) != 0 && (style & SWT.H_SCROLL) != 0) {
439         height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
440     }
441     return new Point (width, height);
442 }
443
444 /**
445  * Copies the selected text.
446  * <p>
447  * The current selection is copied to the clipboard.
448  * </p>
449  *
450  * @exception SWTException <ul>
451  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
452  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
453  * </ul>
454  *
455  * @since 2.1
456  */

457 public void copy () {
458     checkWidget ();
459     OS.SendMessage (handle, OS.WM_COPY, 0, 0);
460 }
461
462 void createHandle () {
463     /*
464     * Feature in Windows. When the selection changes in a combo box,
465     * Windows draws the selection, even when the combo box does not
466     * have focus. Strictly speaking, this is the correct Windows
467     * behavior because the combo box sets ES_NOHIDESEL on the text
468     * control that it creates. Despite this, it looks strange because
469     * Windows also clears the selection and selects all the text when
470     * the combo box gets focus. The fix is use the CBT hook to clear
471     * the ES_NOHIDESEL style bit when the text control is created.
472     */

473     if (OS.IsWinCE || (style & (SWT.READ_ONLY | SWT.SIMPLE)) != 0) {
474         super.createHandle ();
475     } else {
476         int threadId = OS.GetCurrentThreadId ();
477         Callback cbtCallback = new Callback (this, "CBTProc", 3); //$NON-NLS-1$
478
int cbtProc = cbtCallback.getAddress ();
479         if (cbtProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
480         cbtHook = OS.SetWindowsHookEx (OS.WH_CBT, cbtProc, 0, threadId);
481         super.createHandle ();
482         if (cbtHook != 0) OS.UnhookWindowsHookEx (cbtHook);
483         cbtHook = 0;
484         cbtCallback.dispose ();
485     }
486     state &= ~(CANVAS | THEME_BACKGROUND);
487
488     /* Get the text and list window procs */
489     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
490     if (hwndText != 0 && EditProc == 0) {
491         EditProc = OS.GetWindowLong (hwndText, OS.GWL_WNDPROC);
492     }
493     int hwndList = OS.GetDlgItem (handle, CBID_LIST);
494     if (hwndList != 0 && ListProc == 0) {
495         ListProc = OS.GetWindowLong (hwndList, OS.GWL_WNDPROC);
496     }
497
498     /*
499     * Bug in Windows. If the combo box has the CBS_SIMPLE style,
500     * the list portion of the combo box is not drawn correctly the
501     * first time, causing pixel corruption. The fix is to ensure
502     * that the combo box has been resized more than once.
503     */

504     if ((style & SWT.SIMPLE) != 0) {
505         int flags = OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
506         SetWindowPos (handle, 0, 0, 0, 0x3FFF, 0x3FFF, flags);
507         SetWindowPos (handle, 0, 0, 0, 0, 0, flags);
508     }
509 }
510
511 /**
512  * Cuts the selected text.
513  * <p>
514  * The current selection is first copied to the
515  * clipboard and then deleted from the widget.
516  * </p>
517  *
518  * @exception SWTException <ul>
519  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
520  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
521  * </ul>
522  *
523  * @since 2.1
524  */

525 public void cut () {
526     checkWidget ();
527     if ((style & SWT.READ_ONLY) != 0) return;
528     OS.SendMessage (handle, OS.WM_CUT, 0, 0);
529 }
530
531 int defaultBackground () {
532     return OS.GetSysColor (OS.COLOR_WINDOW);
533 }
534
535 void deregister () {
536     super.deregister ();
537     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
538     if (hwndText != 0) display.removeControl (hwndText);
539     int hwndList = OS.GetDlgItem (handle, CBID_LIST);
540     if (hwndList != 0) display.removeControl (hwndList);
541 }
542
543 /**
544  * Deselects the item at the given zero-relative index in the receiver's
545  * list. If the item at the index was already deselected, it remains
546  * deselected. Indices that are out of range are ignored.
547  *
548  * @param index the index of the item to deselect
549  *
550  * @exception SWTException <ul>
551  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
552  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
553  * </ul>
554  */

555 public void deselect (int index) {
556     checkWidget ();
557     int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
558     if (index != selection) return;
559     OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
560     sendEvent (SWT.Modify);
561     // widget could be disposed at this point
562
}
563
564 /**
565  * Deselects all selected items in the receiver's list.
566  * <p>
567  * Note: To clear the selection in the receiver's text field,
568  * use <code>clearSelection()</code>.
569  * </p>
570  *
571  * @exception SWTException <ul>
572  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
573  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
574  * </ul>
575  *
576  * @see #clearSelection
577  */

578 public void deselectAll () {
579     checkWidget ();
580     OS.SendMessage (handle, OS.CB_SETCURSEL, -1, 0);
581     sendEvent (SWT.Modify);
582     // widget could be disposed at this point
583
}
584
585 boolean dragDetect (int hwnd, int x, int y, boolean filter, boolean [] detect, boolean [] consume) {
586     if (filter && (style & SWT.READ_ONLY) == 0) {
587         int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
588         if (hwndText != 0) {
589             int [] start = new int [1], end = new int [1];
590             OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
591             if (start [0] != end [0]) {
592                 int lParam = (x & 0xFFFF) | ((y << 16) & 0xFFFF0000);
593                 int position = OS.SendMessage (hwndText, OS.EM_CHARFROMPOS, 0, lParam) & 0xFFFF;
594                 if (start [0] <= position && position < end [0]) {
595                     if (super.dragDetect (hwnd, x, y, filter, detect, consume)) {
596                         if (consume != null) consume [0] = true;
597                         return true;
598                     }
599                 }
600             }
601             return false;
602         }
603     }
604     return super.dragDetect (hwnd, x, y, filter, detect, consume);
605 }
606
607 /**
608  * Returns the item at the given, zero-relative index in the
609  * receiver's list. Throws an exception if the index is out
610  * of range.
611  *
612  * @param index the index of the item to return
613  * @return the item at the given index
614  *
615  * @exception IllegalArgumentException <ul>
616  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
617  * </ul>
618  * @exception SWTException <ul>
619  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
620  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
621  * </ul>
622  */

623 public String JavaDoc getItem (int index) {
624     checkWidget ();
625     int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
626     if (length != OS.CB_ERR) {
627         TCHAR buffer = new TCHAR (getCodePage (), length + 1);
628         int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer);
629         if (result != OS.CB_ERR) return buffer.toString (0, length);
630     }
631     int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
632     if (0 <= index && index < count) error (SWT.ERROR_CANNOT_GET_ITEM);
633     error (SWT.ERROR_INVALID_RANGE);
634     return "";
635 }
636
637 /**
638  * Returns the number of items contained in the receiver's list.
639  *
640  * @return the number of items
641  *
642  * @exception SWTException <ul>
643  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
644  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
645  * </ul>
646  */

647 public int getItemCount () {
648     checkWidget ();
649     int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
650     if (count == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_COUNT);
651     return count;
652 }
653
654 /**
655  * Returns the height of the area which would be used to
656  * display <em>one</em> of the items in the receiver's list.
657  *
658  * @return the height of one item
659  *
660  * @exception SWTException <ul>
661  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
662  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
663  * </ul>
664  */

665 public int getItemHeight () {
666     checkWidget ();
667     int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, 0, 0);
668     if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
669     return result;
670 }
671
672 /**
673  * Returns a (possibly empty) array of <code>String</code>s which are
674  * the items in the receiver's list.
675  * <p>
676  * Note: This is not the actual structure used by the receiver
677  * to maintain its list of items, so modifying the array will
678  * not affect the receiver.
679  * </p>
680  *
681  * @return the items in the receiver's list
682  *
683  * @exception SWTException <ul>
684  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
685  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
686  * </ul>
687  */

688 public String JavaDoc [] getItems () {
689     checkWidget ();
690     int count = getItemCount ();
691     String JavaDoc [] result = new String JavaDoc [count];
692     for (int i=0; i<count; i++) result [i] = getItem (i);
693     return result;
694 }
695
696 /**
697  * Returns <code>true</code> if the receiver's list is visible,
698  * and <code>false</code> otherwise.
699  * <p>
700  * If one of the receiver's ancestors is not visible or some
701  * other condition makes the receiver not visible, this method
702  * may still indicate that it is considered visible even though
703  * it may not actually be showing.
704  * </p>
705  *
706  * @return the receiver's list's visibility state
707  *
708  * @exception SWTException <ul>
709  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
710  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
711  * </ul>
712  *
713  * @since 3.3
714  */

715 /*public*/ boolean getListVisible () {
716     checkWidget ();
717     if ((style & SWT.DROP_DOWN) != 0) {
718         return OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0;
719     }
720     return true;
721 }
722
723 String JavaDoc getNameText () {
724     return getText ();
725 }
726
727 /**
728  * Returns the orientation of the receiver.
729  *
730  * @return the orientation style
731  *
732  * @exception SWTException <ul>
733  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
734  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
735  * </ul>
736  *
737  * @since 2.1.2
738  */

739 public int getOrientation () {
740     checkWidget();
741     return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
742 }
743
744 /**
745  * Returns a <code>Point</code> whose x coordinate is the
746  * character position representing the start of the selection
747  * in the receiver's text field, and whose y coordinate is the
748  * character position representing the end of the selection.
749  * An "empty" selection is indicated by the x and y coordinates
750  * having the same value.
751  * <p>
752  * Indexing is zero based. The range of a selection is from
753  * 0..N where N is the number of characters in the widget.
754  * </p>
755  *
756  * @return a point representing the selection start and end
757  *
758  * @exception SWTException <ul>
759  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
760  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
761  * </ul>
762  */

763 public Point getSelection () {
764     checkWidget ();
765     if ((style & SWT.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) {
766         return new Point (0, OS.GetWindowTextLength (handle));
767     }
768     int [] start = new int [1], end = new int [1];
769     OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
770     if (!OS.IsUnicode && OS.IsDBLocale) {
771         start [0] = mbcsToWcsPos (start [0]);
772         end [0] = mbcsToWcsPos (end [0]);
773     }
774     return new Point (start [0], end [0]);
775 }
776
777 /**
778  * Returns the zero-relative index of the item which is currently
779  * selected in the receiver's list, or -1 if no item is selected.
780  *
781  * @return the index of the selected item
782  *
783  * @exception SWTException <ul>
784  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
785  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
786  * </ul>
787  */

788 public int getSelectionIndex () {
789     checkWidget ();
790     if (noSelection) return -1;
791     return OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
792 }
793
794 /**
795  * Returns a string containing a copy of the contents of the
796  * receiver's text field, or an empty string if there are no
797  * contents.
798  *
799  * @return the receiver's text
800  *
801  * @exception SWTException <ul>
802  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
803  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
804  * </ul>
805  */

806 public String JavaDoc getText () {
807     checkWidget ();
808     int length = OS.GetWindowTextLength (handle);
809     if (length == 0) return "";
810     TCHAR buffer = new TCHAR (getCodePage (), length + 1);
811     OS.GetWindowText (handle, buffer, length + 1);
812     return buffer.toString (0, length);
813 }
814
815 /**
816  * Returns the height of the receivers's text field.
817  *
818  * @return the text height
819  *
820  * @exception SWTException <ul>
821  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
822  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
823  * </ul>
824  */

825 public int getTextHeight () {
826     checkWidget ();
827     COMBOBOXINFO pcbi = new COMBOBOXINFO ();
828     pcbi.cbSize = COMBOBOXINFO.sizeof;
829     if (((style & SWT.SIMPLE) == 0) && !OS.IsWinCE && OS.GetComboBoxInfo (handle, pcbi)) {
830         return (pcbi.buttonBottom - pcbi.buttonTop) + pcbi.buttonTop * 2;
831     }
832     int result = OS.SendMessage (handle, OS.CB_GETITEMHEIGHT, -1, 0);
833     if (result == OS.CB_ERR) error (SWT.ERROR_CANNOT_GET_ITEM_HEIGHT);
834     return (style & SWT.DROP_DOWN) != 0 ? result + 6 : result + 10;
835 }
836
837 /**
838  * Returns the maximum number of characters that the receiver's
839  * text field is capable of holding. If this has not been changed
840  * by <code>setTextLimit()</code>, it will be the constant
841  * <code>Combo.LIMIT</code>.
842  *
843  * @return the text limit
844  *
845  * @exception SWTException <ul>
846  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
847  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
848  * </ul>
849  *
850  * @see #LIMIT
851  */

852 public int getTextLimit () {
853     checkWidget ();
854     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
855     if (hwndText == 0) return LIMIT;
856     return OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0) & 0x7FFFFFFF;
857 }
858
859 /**
860  * Gets the number of items that are visible in the drop
861  * down portion of the receiver's list.
862  * <p>
863  * Note: This operation is a hint and is not supported on
864  * platforms that do not have this concept.
865  * </p>
866  *
867  * @return the number of items that are visible
868  *
869  * @exception SWTException <ul>
870  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
871  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
872  * </ul>
873  *
874  * @since 3.0
875  */

876 public int getVisibleItemCount () {
877     checkWidget ();
878     return visibleCount;
879 }
880
881 boolean hasFocus () {
882     int hwndFocus = OS.GetFocus ();
883     if (hwndFocus == handle) return true;
884     if (hwndFocus == 0) return false;
885     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
886     if (hwndFocus == hwndText) return true;
887     int hwndList = OS.GetDlgItem (handle, CBID_LIST);
888     if (hwndFocus == hwndList) return true;
889     return false;
890 }
891
892 /**
893  * Searches the receiver's list starting at the first item
894  * (index 0) until an item is found that is equal to the
895  * argument, and returns the index of that item. If no item
896  * is found, returns -1.
897  *
898  * @param string the search item
899  * @return the index of the item
900  *
901  * @exception IllegalArgumentException <ul>
902  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
903  * </ul>
904  * @exception SWTException <ul>
905  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
906  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
907  * </ul>
908  */

909 public int indexOf (String JavaDoc string) {
910     return indexOf (string, 0);
911 }
912
913 /**
914  * Searches the receiver's list starting at the given,
915  * zero-relative index until an item is found that is equal
916  * to the argument, and returns the index of that item. If
917  * no item is found or the starting index is out of range,
918  * returns -1.
919  *
920  * @param string the search item
921  * @param start the zero-relative index at which to begin the search
922  * @return the index of the item
923  *
924  * @exception IllegalArgumentException <ul>
925  * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
926  * </ul>
927  * @exception SWTException <ul>
928  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
929  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
930  * </ul>
931  */

932 public int indexOf (String JavaDoc string, int start) {
933     checkWidget ();
934     if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
935     
936     /*
937     * Bug in Windows. For some reason, CB_FINDSTRINGEXACT
938     * will not find empty strings even though it is legal
939     * to insert an empty string into a combo. The fix is
940     * to search the combo, an item at a time.
941     */

942     if (string.length () == 0) {
943         int count = getItemCount ();
944         for (int i=start; i<count; i++) {
945             if (string.equals (getItem (i))) return i;
946         }
947         return -1;
948     }
949
950     /* Use CB_FINDSTRINGEXACT to search for the item */
951     int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
952     if (!(0 <= start && start < count)) return -1;
953     int index = start - 1, last = 0;
954     TCHAR buffer = new TCHAR (getCodePage (), string, true);
955     do {
956         index = OS.SendMessage (handle, OS.CB_FINDSTRINGEXACT, last = index, buffer);
957         if (index == OS.CB_ERR || index <= last) return -1;
958     } while (!string.equals (getItem (index)));
959     return index;
960 }
961
962 int mbcsToWcsPos (int mbcsPos) {
963     if (mbcsPos <= 0) return 0;
964     if (OS.IsUnicode) return mbcsPos;
965     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
966     if (hwndText == 0) return mbcsPos;
967     int mbcsSize = OS.GetWindowTextLengthA (hwndText);
968     if (mbcsSize == 0) return 0;
969     if (mbcsPos >= mbcsSize) return mbcsSize;
970     byte [] buffer = new byte [mbcsSize + 1];
971     OS.GetWindowTextA (hwndText, buffer, mbcsSize + 1);
972     return OS.MultiByteToWideChar (getCodePage (), OS.MB_PRECOMPOSED, buffer, mbcsPos, null, 0);
973 }
974
975 /**
976  * Pastes text from clipboard.
977  * <p>
978  * The selected text is deleted from the widget
979  * and new text inserted from the clipboard.
980  * </p>
981  *
982  * @exception SWTException <ul>
983  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
984  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
985  * </ul>
986  *
987  * @since 2.1
988  */

989 public void paste () {
990     checkWidget ();
991     if ((style & SWT.READ_ONLY) != 0) return;
992     OS.SendMessage (handle, OS.WM_PASTE, 0, 0);
993 }
994
995 void register () {
996     super.register ();
997     int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
998     if (hwndText != 0) display.addControl (hwndText, this);
999     int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1000    if (hwndList != 0) display.addControl (hwndList, this);
1001}
1002
1003/**
1004 * Removes the item from the receiver's list at the given
1005 * zero-relative index.
1006 *
1007 * @param index the index for the item
1008 *
1009 * @exception IllegalArgumentException <ul>
1010 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1011 * </ul>
1012 * @exception SWTException <ul>
1013 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1014 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1015 * </ul>
1016 */

1017public void remove (int index) {
1018    checkWidget ();
1019    remove (index, true);
1020}
1021
1022void remove (int index, boolean notify) {
1023    TCHAR buffer = null;
1024    if ((style & SWT.H_SCROLL) != 0) {
1025        int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, index, 0);
1026        if (length == OS.CB_ERR) {
1027            int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1028            if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
1029            error (SWT.ERROR_INVALID_RANGE);
1030        }
1031        buffer = new TCHAR (getCodePage (), length + 1);
1032        int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, index, buffer);
1033        if (result == OS.CB_ERR) {
1034            int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1035            if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
1036            error (SWT.ERROR_INVALID_RANGE);
1037        }
1038    }
1039    int length = OS.GetWindowTextLength (handle);
1040    int code = OS.SendMessage (handle, OS.CB_DELETESTRING, index, 0);
1041    if (code == OS.CB_ERR) {
1042        int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1043        if (0 <= index && index < count) error (SWT.ERROR_ITEM_NOT_REMOVED);
1044        error (SWT.ERROR_INVALID_RANGE);
1045    }
1046    if ((style & SWT.H_SCROLL) != 0) setScrollWidth (buffer, true);
1047    if (notify && length != OS.GetWindowTextLength (handle)) {
1048        sendEvent (SWT.Modify);
1049        if (isDisposed ()) return;
1050    }
1051    /*
1052    * Bug in Windows. When the combo box is read only
1053    * with exactly one item that is currently selected
1054    * and that item is removed, the combo box does not
1055    * redraw to clear the text area. The fix is to
1056    * force a redraw.
1057    */

1058    if ((style & SWT.READ_ONLY) != 0) {
1059        int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1060        if (count == 0) OS.InvalidateRect (handle, null, true);
1061    }
1062}
1063
1064/**
1065 * Removes the items from the receiver's list which are
1066 * between the given zero-relative start and end
1067 * indices (inclusive).
1068 *
1069 * @param start the start of the range
1070 * @param end the end of the range
1071 *
1072 * @exception IllegalArgumentException <ul>
1073 * <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>
1074 * </ul>
1075 * @exception SWTException <ul>
1076 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1077 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1078 * </ul>
1079 */

1080public void remove (int start, int end) {
1081    checkWidget ();
1082    if (start > end) return;
1083    int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1084    if (!(0 <= start && start <= end && end < count)) {
1085        error (SWT.ERROR_INVALID_RANGE);
1086    }
1087    int textLength = OS.GetWindowTextLength (handle);
1088    RECT rect = null;
1089    int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
1090    if ((style & SWT.H_SCROLL) != 0) {
1091        rect = new RECT ();
1092        hDC = OS.GetDC (handle);
1093        newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1094        if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1095    }
1096    int cp = getCodePage ();
1097    int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1098    for (int i=start; i<=end; i++) {
1099        TCHAR buffer = null;
1100        if ((style & SWT.H_SCROLL) != 0) {
1101            int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, start, 0);
1102            if (length == OS.CB_ERR) break;
1103            buffer = new TCHAR (cp, length + 1);
1104            int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, start, buffer);
1105            if (result == OS.CB_ERR) break;
1106        }
1107        int result = OS.SendMessage (handle, OS.CB_DELETESTRING, start, 0);
1108        if (result == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_REMOVED);
1109        if ((style & SWT.H_SCROLL) != 0) {
1110            OS.DrawText (hDC, buffer, -1, rect, flags);
1111            newWidth = Math.max (newWidth, rect.right - rect.left);
1112        }
1113    }
1114    if ((style & SWT.H_SCROLL) != 0) {
1115        if (newFont != 0) OS.SelectObject (hDC, oldFont);
1116        OS.ReleaseDC (handle, hDC);
1117        setScrollWidth (newWidth, false);
1118    }
1119    if (textLength != OS.GetWindowTextLength (handle)) {
1120        sendEvent (SWT.Modify);
1121        if (isDisposed ()) return;
1122    }
1123    /*
1124    * Bug in Windows. When the combo box is read only
1125    * with exactly one item that is currently selected
1126    * and that item is removed, the combo box does not
1127    * redraw to clear the text area. The fix is to
1128    * force a redraw.
1129    */

1130    if ((style & SWT.READ_ONLY) != 0) {
1131        count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1132        if (count == 0) OS.InvalidateRect (handle, null, true);
1133    }
1134}
1135
1136/**
1137 * Searches the receiver's list starting at the first item
1138 * until an item is found that is equal to the argument,
1139 * and removes that item from the list.
1140 *
1141 * @param string the item to remove
1142 *
1143 * @exception IllegalArgumentException <ul>
1144 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1145 * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
1146 * </ul>
1147 * @exception SWTException <ul>
1148 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1149 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1150 * </ul>
1151 */

1152public void remove (String JavaDoc string) {
1153    checkWidget ();
1154    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1155    int index = indexOf (string, 0);
1156    if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
1157    remove (index);
1158}
1159
1160/**
1161 * Removes all of the items from the receiver's list and clear the
1162 * contents of receiver's text field.
1163 * <p>
1164 * @exception SWTException <ul>
1165 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1166 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1167 * </ul>
1168 */

1169public void removeAll () {
1170    checkWidget ();
1171    OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
1172    sendEvent (SWT.Modify);
1173    if (isDisposed ()) return;
1174    if ((style & SWT.H_SCROLL) != 0) setScrollWidth (0);
1175}
1176
1177/**
1178 * Removes the listener from the collection of listeners who will
1179 * be notified when the receiver's text is modified.
1180 *
1181 * @param listener the listener which should no longer be notified
1182 *
1183 * @exception IllegalArgumentException <ul>
1184 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1185 * </ul>
1186 * @exception SWTException <ul>
1187 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1188 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1189 * </ul>
1190 *
1191 * @see ModifyListener
1192 * @see #addModifyListener
1193 */

1194public void removeModifyListener (ModifyListener listener) {
1195    checkWidget ();
1196    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1197    if (eventTable == null) return;
1198    eventTable.unhook (SWT.Modify, listener);
1199}
1200
1201/**
1202 * Removes the listener from the collection of listeners who will
1203 * be notified when the user changes the receiver's selection.
1204 *
1205 * @param listener the listener which should no longer be notified
1206 *
1207 * @exception IllegalArgumentException <ul>
1208 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1209 * </ul>
1210 * @exception SWTException <ul>
1211 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1212 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1213 * </ul>
1214 *
1215 * @see SelectionListener
1216 * @see #addSelectionListener
1217 */

1218public void removeSelectionListener (SelectionListener listener) {
1219    checkWidget ();
1220    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1221    if (eventTable == null) return;
1222    eventTable.unhook (SWT.Selection, listener);
1223    eventTable.unhook (SWT.DefaultSelection,listener);
1224}
1225
1226/**
1227 * Removes the listener from the collection of listeners who will
1228 * be notified when the control is verified.
1229 *
1230 * @param listener the listener which should no longer be notified
1231 *
1232 * @exception IllegalArgumentException <ul>
1233 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1234 * </ul>
1235 * @exception SWTException <ul>
1236 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1237 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1238 * </ul>
1239 *
1240 * @see VerifyListener
1241 * @see #addVerifyListener
1242 *
1243 * @since 3.1
1244 */

1245public void removeVerifyListener (VerifyListener listener) {
1246    checkWidget ();
1247    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1248    if (eventTable == null) return;
1249    eventTable.unhook (SWT.Verify, listener);
1250}
1251
1252boolean sendKeyEvent (int type, int msg, int wParam, int lParam, Event event) {
1253    if (!super.sendKeyEvent (type, msg, wParam, lParam, event)) {
1254        return false;
1255    }
1256    if ((style & SWT.READ_ONLY) != 0) return true;
1257    if (type != SWT.KeyDown) return true;
1258    if (msg != OS.WM_CHAR && msg != OS.WM_KEYDOWN && msg != OS.WM_IME_CHAR) {
1259        return true;
1260    }
1261    if (event.character == 0) return true;
1262    if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return true;
1263    char key = event.character;
1264    int stateMask = event.stateMask;
1265    
1266    /*
1267    * Disable all magic keys that could modify the text
1268    * and don't send events when Alt, Shift or Ctrl is
1269    * pressed.
1270    */

1271    switch (msg) {
1272        case OS.WM_CHAR:
1273            if (key != 0x08 && key != 0x7F && key != '\r' && key != '\t' && key != '\n') break;
1274            // FALL THROUGH
1275
case OS.WM_KEYDOWN:
1276            if ((stateMask & (SWT.ALT | SWT.SHIFT | SWT.CONTROL)) != 0) return false;
1277            break;
1278    }
1279
1280    /*
1281    * If the left button is down, the text widget refuses the character.
1282    */

1283    if (OS.GetKeyState (OS.VK_LBUTTON) < 0) {
1284        return true;
1285    }
1286
1287    /* Verify the character */
1288    String JavaDoc oldText = "";
1289    int [] start = new int [1], end = new int [1];
1290    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1291    if (hwndText == 0) return true;
1292    OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
1293    switch (key) {
1294        case 0x08: /* Bs */
1295            if (start [0] == end [0]) {
1296                if (start [0] == 0) return true;
1297                start [0] = start [0] - 1;
1298                if (!OS.IsUnicode && OS.IsDBLocale) {
1299                    int [] newStart = new int [1], newEnd = new int [1];
1300                    OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
1301                    OS.SendMessage (hwndText, OS.EM_GETSEL, newStart, newEnd);
1302                    if (start [0] != newStart [0]) start [0] = start [0] - 1;
1303                }
1304                start [0] = Math.max (start [0], 0);
1305            }
1306            break;
1307        case 0x7F: /* Del */
1308            if (start [0] == end [0]) {
1309                int length = OS.GetWindowTextLength (hwndText);
1310                if (start [0] == length) return true;
1311                end [0] = end [0] + 1;
1312                if (!OS.IsUnicode && OS.IsDBLocale) {
1313                    int [] newStart = new int [1], newEnd = new int [1];
1314                    OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
1315                    OS.SendMessage (hwndText, OS.EM_GETSEL, newStart, newEnd);
1316                    if (end [0] != newEnd [0]) end [0] = end [0] + 1;
1317                }
1318                end [0] = Math.min (end [0], length);
1319            }
1320            break;
1321        case '\r': /* Return */
1322            return true;
1323        default: /* Tab and other characters */
1324            if (key != '\t' && key < 0x20) return true;
1325            oldText = new String JavaDoc (new char [] {key});
1326            break;
1327    }
1328    String JavaDoc newText = verifyText (oldText, start [0], end [0], event);
1329    if (newText == null) return false;
1330    if (newText == oldText) return true;
1331    TCHAR buffer = new TCHAR (getCodePage (), newText, true);
1332    OS.SendMessage (hwndText, OS.EM_SETSEL, start [0], end [0]);
1333    OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
1334    return false;
1335}
1336
1337/**
1338 * Selects the item at the given zero-relative index in the receiver's
1339 * list. If the item at the index was already selected, it remains
1340 * selected. Indices that are out of range are ignored.
1341 *
1342 * @param index the index of the item to select
1343 *
1344 * @exception SWTException <ul>
1345 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1346 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1347 * </ul>
1348 */

1349public void select (int index) {
1350    checkWidget ();
1351    int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1352    if (0 <= index && index < count) {
1353        int selection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
1354        int code = OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
1355        if (code != OS.CB_ERR && code != selection) {
1356            sendEvent (SWT.Modify);
1357            // widget could be disposed at this point
1358
}
1359    }
1360}
1361
1362void setBackgroundImage (int hBitmap) {
1363    super.setBackgroundImage (hBitmap);
1364    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1365    if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
1366    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1367    if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
1368}
1369
1370void setBackgroundPixel (int pixel) {
1371    super.setBackgroundPixel (pixel);
1372    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1373    if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
1374    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1375    if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
1376}
1377
1378void setBounds (int x, int y, int width, int height, int flags) {
1379    /*
1380    * Feature in Windows. If the combo box has the CBS_DROPDOWN
1381    * or CBS_DROPDOWNLIST style, Windows uses the height that the
1382    * programmer sets in SetWindowPos () to control height of the
1383    * drop down list. When the width is non-zero, Windows remembers
1384    * this value and sets the height to be the height of the text
1385    * field part of the combo box. If the width is zero, Windows
1386    * allows the height to have any value. Therefore, when the
1387    * programmer sets and then queries the height, the values can
1388    * be different depending on the width. The problem occurs when
1389    * the programmer uses computeSize () to determine the preferred
1390    * height (always the height of the text field) and then uses
1391    * this value to set the height of the combo box. The result
1392    * is a combo box with a zero size drop down list. The fix, is
1393    * to always set the height to show a fixed number of combo box
1394    * items and ignore the height value that the programmer supplies.
1395    */

1396    if ((style & SWT.DROP_DOWN) != 0) {
1397        height = getTextHeight () + (getItemHeight () * visibleCount) + 2;
1398        /*
1399        * Feature in Windows. When a drop down combo box is resized,
1400        * the combo box resizes the height of the text field and uses
1401        * the height provided in SetWindowPos () to determine the height
1402        * of the drop down list. For some reason, the combo box redraws
1403        * the whole area, not just the text field. The fix is to set the
1404        * SWP_NOSIZE bits when the height of text field and the drop down
1405        * list is the same as the requested height.
1406        *
1407        * NOTE: Setting the width of a combo box to zero does not update
1408        * the width of the drop down control rect. If the width of the
1409        * combo box is zero, then do not set SWP_NOSIZE.
1410        */

1411        RECT rect = new RECT ();
1412        OS.GetWindowRect (handle, rect);
1413        if (rect.right - rect.left != 0) {
1414            if (OS.SendMessage (handle, OS.CB_GETDROPPEDCONTROLRECT, 0, rect) != 0) {
1415                int oldWidth = rect.right - rect.left, oldHeight = rect.bottom - rect.top;
1416                if (oldWidth == width && oldHeight == height) flags |= OS.SWP_NOSIZE;
1417            }
1418        }
1419        SetWindowPos (handle, 0, x, y, width, height, flags);
1420    } else {
1421        super.setBounds (x, y, width, height, flags);
1422    }
1423}
1424
1425public void setFont (Font font) {
1426    checkWidget ();
1427    super.setFont (font);
1428    if ((style & SWT.H_SCROLL) != 0) setScrollWidth ();
1429}
1430
1431void setForegroundPixel (int pixel) {
1432    super.setForegroundPixel (pixel);
1433    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1434    if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
1435    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1436    if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
1437}
1438
1439/**
1440 * Sets the text of the item in the receiver's list at the given
1441 * zero-relative index to the string argument.
1442 *
1443 * @param index the index for the item
1444 * @param string the new text for the item
1445 *
1446 * @exception IllegalArgumentException <ul>
1447 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1448 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1449 * </ul>
1450 * @exception SWTException <ul>
1451 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1452 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1453 * </ul>
1454 */

1455public void setItem (int index, String JavaDoc string) {
1456    checkWidget ();
1457    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1458    int selection = getSelectionIndex ();
1459    remove (index, false);
1460    if (isDisposed ()) return;
1461    add (string, index);
1462    if (selection != -1) select (selection);
1463}
1464
1465/**
1466 * Sets the receiver's list to be the given array of items.
1467 *
1468 * @param items the array of items
1469 *
1470 * @exception IllegalArgumentException <ul>
1471 * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1472 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1473 * </ul>
1474 * @exception SWTException <ul>
1475 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1476 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1477 * </ul>
1478 */

1479public void setItems (String JavaDoc [] items) {
1480    checkWidget ();
1481    if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1482    for (int i=0; i<items.length; i++) {
1483        if (items [i] == null) error (SWT.ERROR_INVALID_ARGUMENT);
1484    }
1485    RECT rect = null;
1486    int hDC = 0, oldFont = 0, newFont = 0, newWidth = 0;
1487    if ((style & SWT.H_SCROLL) != 0) {
1488        rect = new RECT ();
1489        hDC = OS.GetDC (handle);
1490        newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1491        if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1492        setScrollWidth (0);
1493    }
1494    OS.SendMessage (handle, OS.CB_RESETCONTENT, 0, 0);
1495    int codePage = getCodePage ();
1496    for (int i=0; i<items.length; i++) {
1497        String JavaDoc string = items [i];
1498        TCHAR buffer = new TCHAR (codePage, string, true);
1499        int code = OS.SendMessage (handle, OS.CB_ADDSTRING, 0, buffer);
1500        if (code == OS.CB_ERR) error (SWT.ERROR_ITEM_NOT_ADDED);
1501        if (code == OS.CB_ERRSPACE) error (SWT.ERROR_ITEM_NOT_ADDED);
1502        if ((style & SWT.H_SCROLL) != 0) {
1503            int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1504            OS.DrawText (hDC, buffer, -1, rect, flags);
1505            newWidth = Math.max (newWidth, rect.right - rect.left);
1506        }
1507    }
1508    if ((style & SWT.H_SCROLL) != 0) {
1509        if (newFont != 0) OS.SelectObject (hDC, oldFont);
1510        OS.ReleaseDC (handle, hDC);
1511        setScrollWidth (newWidth + 3);
1512    }
1513    sendEvent (SWT.Modify);
1514    // widget could be disposed at this point
1515
}
1516
1517/**
1518 * Marks the receiver's list as visible if the argument is <code>true</code>,
1519 * and marks it invisible otherwise.
1520 * <p>
1521 * If one of the receiver's ancestors is not visible or some
1522 * other condition makes the receiver not visible, marking
1523 * it visible may not actually cause it to be displayed.
1524 * </p>
1525 *
1526 * @param visible the new visibility state
1527 *
1528 * @exception SWTException <ul>
1529 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1530 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1531 * </ul>
1532 *
1533 * @since 3.3
1534 */

1535/*public*/ void setListVisible (boolean visible) {
1536    checkWidget ();
1537    OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, visible ? 1 : 0, 0);
1538}
1539
1540/**
1541 * Sets the orientation of the receiver, which must be one
1542 * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
1543 * <p>
1544 *
1545 * @param orientation new orientation style
1546 *
1547 * @exception SWTException <ul>
1548 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1549 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1550 * </ul>
1551 *
1552 * @since 2.1.2
1553 */

1554public void setOrientation (int orientation) {
1555    checkWidget();
1556    if (OS.IsWinCE) return;
1557    if (OS.WIN32_VERSION < OS.VERSION (4, 10)) return;
1558    int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
1559    if ((orientation & flags) == 0 || (orientation & flags) == flags) return;
1560    style &= ~flags;
1561    style |= orientation & flags;
1562    int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
1563    if ((style & SWT.RIGHT_TO_LEFT) != 0) {
1564        style |= SWT.MIRRORED;
1565        bits |= OS.WS_EX_LAYOUTRTL;
1566    } else {
1567        style &= ~SWT.MIRRORED;
1568        bits &= ~OS.WS_EX_LAYOUTRTL;
1569    }
1570    OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits);
1571    int hwndText = 0, hwndList = 0;
1572    COMBOBOXINFO pcbi = new COMBOBOXINFO ();
1573    pcbi.cbSize = COMBOBOXINFO.sizeof;
1574    if (OS.GetComboBoxInfo (handle, pcbi)) {
1575        hwndText = pcbi.hwndItem;
1576        hwndList = pcbi.hwndList;
1577    }
1578    if (hwndText != 0) {
1579        int bits1 = OS.GetWindowLong (hwndText, OS.GWL_EXSTYLE);
1580        int bits2 = OS.GetWindowLong (hwndText, OS.GWL_STYLE);
1581        if ((style & SWT.RIGHT_TO_LEFT) != 0) {
1582            bits1 |= OS.WS_EX_RIGHT | OS.WS_EX_RTLREADING;
1583            bits2 |= OS.ES_RIGHT;
1584        } else {
1585            bits1 &= ~(OS.WS_EX_RIGHT | OS.WS_EX_RTLREADING);
1586            bits2 &= ~OS.ES_RIGHT;
1587        }
1588        OS.SetWindowLong (hwndText, OS.GWL_EXSTYLE, bits1);
1589        OS.SetWindowLong (hwndText, OS.GWL_STYLE, bits2);
1590        
1591        /*
1592        * Bug in Windows. For some reason, the single line text field
1593        * portion of the combo box does not redraw to reflect the new
1594        * style bits. The fix is to force the widget to be resized by
1595        * temporarily shrinking and then growing the width and height.
1596        */

1597        RECT rect = new RECT ();
1598        OS.GetWindowRect (hwndText, rect);
1599        int width = rect.right - rect.left, height = rect.bottom - rect.top;
1600        OS.GetWindowRect (handle, rect);
1601        int widthCombo = rect.right - rect.left, heightCombo = rect.bottom - rect.top;
1602        int uFlags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
1603        SetWindowPos (hwndText, 0, 0, 0, width - 1, height - 1, uFlags);
1604        SetWindowPos (handle, 0, 0, 0, widthCombo - 1, heightCombo - 1, uFlags);
1605        SetWindowPos (hwndText, 0, 0, 0, width, height, uFlags);
1606        SetWindowPos (handle, 0, 0, 0, widthCombo, heightCombo, uFlags);
1607        OS.InvalidateRect (handle, null, true);
1608    }
1609    if (hwndList != 0) {
1610        int bits1 = OS.GetWindowLong (hwndList, OS.GWL_EXSTYLE);
1611        if ((style & SWT.RIGHT_TO_LEFT) != 0) {
1612            bits1 |= OS.WS_EX_LAYOUTRTL;
1613        } else {
1614            bits1 &= ~OS.WS_EX_LAYOUTRTL;
1615        }
1616        OS.SetWindowLong (hwndList, OS.GWL_EXSTYLE, bits1);
1617    }
1618}
1619
1620void setScrollWidth () {
1621    int newWidth = 0;
1622    RECT rect = new RECT ();
1623    int newFont, oldFont = 0;
1624    int hDC = OS.GetDC (handle);
1625    newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1626    if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1627    int cp = getCodePage ();
1628    int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1629    int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1630    for (int i=0; i<count; i++) {
1631        int length = OS.SendMessage (handle, OS.CB_GETLBTEXTLEN, i, 0);
1632        if (length != OS.CB_ERR) {
1633            TCHAR buffer = new TCHAR (cp, length + 1);
1634            int result = OS.SendMessage (handle, OS.CB_GETLBTEXT, i, buffer);
1635            if (result != OS.CB_ERR) {
1636                OS.DrawText (hDC, buffer, -1, rect, flags);
1637                newWidth = Math.max (newWidth, rect.right - rect.left);
1638            }
1639        }
1640    }
1641    if (newFont != 0) OS.SelectObject (hDC, oldFont);
1642    OS.ReleaseDC (handle, hDC);
1643    setScrollWidth (newWidth + 3);
1644}
1645
1646void setScrollWidth (int scrollWidth) {
1647    this.scrollWidth = scrollWidth;
1648    if ((style & SWT.SIMPLE) != 0) {
1649        OS.SendMessage (handle, OS.CB_SETHORIZONTALEXTENT, scrollWidth, 0);
1650        return;
1651    }
1652    boolean scroll = false;
1653    int count = OS.SendMessage (handle, OS.CB_GETCOUNT, 0, 0);
1654    if (count > 3) {
1655        int maxWidth = 0;
1656        if (OS.IsWinCE || OS.WIN32_VERSION < OS.VERSION (4, 10)) {
1657            RECT rect = new RECT ();
1658            OS.SystemParametersInfo (OS.SPI_GETWORKAREA, 0, rect, 0);
1659            maxWidth = (rect.right - rect.left) / 4;
1660        } else {
1661            int hmonitor = OS.MonitorFromWindow (handle, OS.MONITOR_DEFAULTTONEAREST);
1662            MONITORINFO lpmi = new MONITORINFO ();
1663            lpmi.cbSize = MONITORINFO.sizeof;
1664            OS.GetMonitorInfo (hmonitor, lpmi);
1665            maxWidth = (lpmi.rcWork_right - lpmi.rcWork_left) / 4;
1666        }
1667        scroll = scrollWidth > maxWidth;
1668    }
1669    if (scroll) {
1670        OS.SendMessage (handle, OS.CB_SETDROPPEDWIDTH, 0, 0);
1671        OS.SendMessage (handle, OS.CB_SETHORIZONTALEXTENT, scrollWidth, 0);
1672    } else {
1673        scrollWidth += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
1674        OS.SendMessage (handle, OS.CB_SETDROPPEDWIDTH, scrollWidth, 0);
1675        OS.SendMessage (handle, OS.CB_SETHORIZONTALEXTENT, 0, 0);
1676    }
1677}
1678
1679void setScrollWidth (TCHAR buffer, boolean grow) {
1680    RECT rect = new RECT ();
1681    int newFont, oldFont = 0;
1682    int hDC = OS.GetDC (handle);
1683    newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
1684    if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
1685    int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE | OS.DT_NOPREFIX;
1686    OS.DrawText (hDC, buffer, -1, rect, flags);
1687    if (newFont != 0) OS.SelectObject (hDC, oldFont);
1688    OS.ReleaseDC (handle, hDC);
1689    setScrollWidth (rect.right - rect.left, grow);
1690}
1691
1692void setScrollWidth (int newWidth, boolean grow) {
1693    if (grow) {
1694        if (newWidth <= scrollWidth) return;
1695        setScrollWidth (newWidth + 3);
1696    } else {
1697        if (newWidth < scrollWidth) return;
1698        setScrollWidth ();
1699    }
1700}
1701
1702/**
1703 * Sets the selection in the receiver's text field to the
1704 * range specified by the argument whose x coordinate is the
1705 * start of the selection and whose y coordinate is the end
1706 * of the selection.
1707 *
1708 * @param selection a point representing the new selection start and end
1709 *
1710 * @exception IllegalArgumentException <ul>
1711 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1712 * </ul>
1713 * @exception SWTException <ul>
1714 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1715 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1716 * </ul>
1717 */

1718public void setSelection (Point selection) {
1719    checkWidget ();
1720    if (selection == null) error (SWT.ERROR_NULL_ARGUMENT);
1721    int start = selection.x, end = selection.y;
1722    if (!OS.IsUnicode && OS.IsDBLocale) {
1723        start = wcsToMbcsPos (start);
1724        end = wcsToMbcsPos (end);
1725    }
1726    int bits = (start & 0xFFFF) | ((end << 16) & 0xFFFF0000);
1727    OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits);
1728}
1729
1730/**
1731 * Sets the contents of the receiver's text field to the
1732 * given string.
1733 * <p>
1734 * Note: The text field in a <code>Combo</code> is typically
1735 * only capable of displaying a single line of text. Thus,
1736 * setting the text to a string containing line breaks or
1737 * other special characters will probably cause it to
1738 * display incorrectly.
1739 * </p>
1740 *
1741 * @param string the new text
1742 *
1743 * @exception IllegalArgumentException <ul>
1744 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1745 * </ul>
1746 * @exception SWTException <ul>
1747 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1748 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1749 * </ul>
1750 */

1751public void setText (String JavaDoc string) {
1752    checkWidget ();
1753    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1754    if ((style & SWT.READ_ONLY) != 0) {
1755        int index = indexOf (string);
1756        if (index != -1) select (index);
1757        return;
1758    }
1759    int limit = LIMIT;
1760    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1761    if (hwndText != 0) {
1762        limit = OS.SendMessage (hwndText, OS.EM_GETLIMITTEXT, 0, 0);
1763    }
1764    if (string.length () > limit) string = string.substring (0, limit);
1765    TCHAR buffer = new TCHAR (getCodePage (), string, true);
1766    if (OS.SetWindowText (handle, buffer)) {
1767        sendEvent (SWT.Modify);
1768        // widget could be disposed at this point
1769
}
1770}
1771
1772/**
1773 * Sets the maximum number of characters that the receiver's
1774 * text field is capable of holding to be the argument.
1775 * <p>
1776 * To reset this value to the default, use <code>setTextLimit(Combo.LIMIT)</code>.
1777 * Specifying a limit value larger than <code>Combo.LIMIT</code> sets the
1778 * receiver's limit to <code>Combo.LIMIT</code>.
1779 * </p>
1780 * @param limit new text limit
1781 *
1782 * @exception IllegalArgumentException <ul>
1783 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
1784 * </ul>
1785 * @exception SWTException <ul>
1786 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1787 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1788 * </ul>
1789 *
1790 * @see #LIMIT
1791 */

1792public void setTextLimit (int limit) {
1793    checkWidget ();
1794    if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO);
1795    OS.SendMessage (handle, OS.CB_LIMITTEXT, limit, 0);
1796}
1797
1798void setToolTipText (Shell shell, String JavaDoc string) {
1799    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1800    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1801    if (hwndText != 0) shell.setToolTipText (hwndText, string);
1802    if (hwndList != 0) shell.setToolTipText (hwndList, string);
1803    shell.setToolTipText (handle, string);
1804}
1805
1806/**
1807 * Sets the number of items that are visible in the drop
1808 * down portion of the receiver's list.
1809 * <p>
1810 * Note: This operation is a hint and is not supported on
1811 * platforms that do not have this concept.
1812 * </p>
1813 *
1814 * @param count the new number of items to be visible
1815 *
1816 * @exception SWTException <ul>
1817 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1818 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1819 * </ul>
1820 *
1821 * @since 3.0
1822 */

1823public void setVisibleItemCount (int count) {
1824    checkWidget ();
1825    if (count < 0) return;
1826    visibleCount = count;
1827    if ((style & SWT.DROP_DOWN) != 0) {
1828        forceResize ();
1829        RECT rect = new RECT ();
1830        OS.GetWindowRect (handle, rect);
1831        int flags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_DRAWFRAME | OS.SWP_NOACTIVATE;
1832        setBounds (0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
1833    }
1834}
1835
1836void subclass () {
1837    super.subclass ();
1838    int newProc = display.windowProc;
1839    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1840    if (hwndText != 0) {
1841        OS.SetWindowLong (hwndText, OS.GWL_WNDPROC, newProc);
1842    }
1843    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1844    if (hwndList != 0) {
1845        OS.SetWindowLong (hwndList, OS.GWL_WNDPROC, newProc);
1846    }
1847}
1848
1849boolean translateTraversal (MSG msg) {
1850    /*
1851    * When the combo box is dropped down, allow return
1852    * to select an item in the list and escape to close
1853    * the combo box.
1854    */

1855    switch (msg.wParam) {
1856        case OS.VK_RETURN:
1857        case OS.VK_ESCAPE:
1858            if ((style & SWT.DROP_DOWN) != 0) {
1859                if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
1860                    return false;
1861                }
1862            }
1863    }
1864    return super.translateTraversal (msg);
1865}
1866
1867boolean traverseEscape () {
1868    if ((style & SWT.DROP_DOWN) != 0) {
1869        if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
1870            OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0);
1871            return true;
1872        }
1873    }
1874    return super.traverseEscape ();
1875}
1876
1877boolean traverseReturn () {
1878    if ((style & SWT.DROP_DOWN) != 0) {
1879        if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
1880            OS.SendMessage (handle, OS.CB_SHOWDROPDOWN, 0, 0);
1881            return true;
1882        }
1883    }
1884    return super.traverseReturn ();
1885}
1886
1887void unsubclass () {
1888    super.unsubclass ();
1889    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1890    if (hwndText != 0 && EditProc != 0) {
1891        OS.SetWindowLong (hwndText, OS.GWL_WNDPROC, EditProc);
1892    }
1893    int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1894    if (hwndList != 0 && ListProc != 0) {
1895        OS.SetWindowLong (hwndList, OS.GWL_WNDPROC, ListProc);
1896    }
1897}
1898
1899String JavaDoc verifyText (String JavaDoc string, int start, int end, Event keyEvent) {
1900    Event event = new Event ();
1901    event.text = string;
1902    event.start = start;
1903    event.end = end;
1904    if (keyEvent != null) {
1905        event.character = keyEvent.character;
1906        event.keyCode = keyEvent.keyCode;
1907        event.stateMask = keyEvent.stateMask;
1908    }
1909    if (!OS.IsUnicode && OS.IsDBLocale) {
1910        event.start = mbcsToWcsPos (start);
1911        event.end = mbcsToWcsPos (end);
1912    }
1913    /*
1914    * It is possible (but unlikely), that application
1915    * code could have disposed the widget in the verify
1916    * event. If this happens, answer null to cancel
1917    * the operation.
1918    */

1919    sendEvent (SWT.Verify, event);
1920    if (!event.doit || isDisposed ()) return null;
1921    return event.text;
1922}
1923
1924int wcsToMbcsPos (int wcsPos) {
1925    if (wcsPos <= 0) return 0;
1926    if (OS.IsUnicode) return wcsPos;
1927    int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1928    if (hwndText == 0) return wcsPos;
1929    int mbcsSize = OS.GetWindowTextLengthA (hwndText);
1930    if (mbcsSize == 0) return 0;
1931    byte [] buffer = new byte [mbcsSize + 1];
1932    OS.GetWindowTextA (hwndText, buffer, mbcsSize + 1);
1933    int mbcsPos = 0, wcsCount = 0;
1934    while (mbcsPos < mbcsSize) {
1935        if (wcsPos == wcsCount) break;
1936        if (OS.IsDBCSLeadByte (buffer [mbcsPos++])) mbcsPos++;
1937        wcsCount++;
1938    }
1939    return mbcsPos;
1940}
1941
1942int widgetExtStyle () {
1943    return super.widgetExtStyle () & ~OS.WS_EX_NOINHERITLAYOUT;
1944}
1945
1946int widgetStyle () {
1947    int bits = super.widgetStyle () | OS.CBS_AUTOHSCROLL | OS.CBS_NOINTEGRALHEIGHT | OS.WS_HSCROLL |OS.WS_VSCROLL;
1948    if ((style & SWT.SIMPLE) != 0) return bits | OS.CBS_SIMPLE;
1949    if ((style & SWT.READ_ONLY) != 0) return bits | OS.CBS_DROPDOWNLIST;
1950    return bits | OS.CBS_DROPDOWN;
1951}
1952
1953TCHAR windowClass () {
1954    return ComboClass;
1955}
1956
1957int windowProc () {
1958    return ComboProc;
1959}
1960
1961int windowProc (int hwnd, int msg, int wParam, int lParam) {
1962    if (handle == 0) return 0;
1963    if (hwnd != handle) {
1964        int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
1965        int hwndList = OS.GetDlgItem (handle, CBID_LIST);
1966        if ((hwndText != 0 && hwnd == hwndText) || (hwndList != 0 && hwnd == hwndList)) {
1967            LRESULT result = null;
1968            switch (msg) {
1969                /* Keyboard messages */
1970                case OS.WM_CHAR: result = wmChar (hwnd, wParam, lParam); break;
1971                case OS.WM_IME_CHAR: result = wmIMEChar (hwnd, wParam, lParam); break;
1972                case OS.WM_KEYDOWN: result = wmKeyDown (hwnd, wParam, lParam); break;
1973                case OS.WM_KEYUP: result = wmKeyUp (hwnd, wParam, lParam); break;
1974                case OS.WM_SYSCHAR: result = wmSysChar (hwnd, wParam, lParam); break;
1975                case OS.WM_SYSKEYDOWN: result = wmSysKeyDown (hwnd, wParam, lParam); break;
1976                case OS.WM_SYSKEYUP: result = wmSysKeyUp (hwnd, wParam, lParam); break;
1977
1978                /* Mouse Messages */
1979                case OS.WM_CAPTURECHANGED: result = wmCaptureChanged (hwnd, wParam, lParam); break;
1980                case OS.WM_LBUTTONDBLCLK: result = wmLButtonDblClk (hwnd, wParam, lParam); break;
1981                case OS.WM_LBUTTONDOWN: result = wmLButtonDown (hwnd, wParam, lParam); break;
1982                case OS.WM_LBUTTONUP: result = wmLButtonUp (hwnd, wParam, lParam); break;
1983                case OS.WM_MBUTTONDBLCLK: result = wmMButtonDblClk (hwnd, wParam, lParam); break;
1984                case OS.WM_MBUTTONDOWN: result = wmMButtonDown (hwnd, wParam, lParam); break;
1985                case OS.WM_MBUTTONUP: result = wmMButtonUp (hwnd, wParam, lParam); break;
1986                case OS.WM_MOUSEHOVER: result = wmMouseHover (hwnd, wParam, lParam); break;
1987                case OS.WM_MOUSELEAVE: result = wmMouseLeave (hwnd, wParam, lParam); break;
1988                case OS.WM_MOUSEMOVE: result = wmMouseMove (hwnd, wParam, lParam); break;
1989// case OS.WM_MOUSEWHEEL: result = wmMouseWheel (hwnd, wParam, lParam); break;
1990
case OS.WM_RBUTTONDBLCLK: result = wmRButtonDblClk (hwnd, wParam, lParam); break;
1991                case OS.WM_RBUTTONDOWN: result = wmRButtonDown (hwnd, wParam, lParam); break;
1992                case OS.WM_RBUTTONUP: result = wmRButtonUp (hwnd, wParam, lParam); break;
1993                case OS.WM_XBUTTONDBLCLK: result = wmXButtonDblClk (hwnd, wParam, lParam); break;
1994                case OS.WM_XBUTTONDOWN: result = wmXButtonDown (hwnd, wParam, lParam); break;
1995                case OS.WM_XBUTTONUP: result = wmXButtonUp (hwnd, wParam, lParam); break;
1996
1997                /* Paint messages */
1998                case OS.WM_PAINT: result = wmPaint (hwnd, wParam, lParam); break;
1999
2000                /* Menu messages */
2001                case OS.WM_CONTEXTMENU: result = wmContextMenu (hwnd, wParam, lParam); break;
2002                    
2003                /* Clipboard messages */
2004                case OS.WM_CLEAR:
2005                case OS.WM_CUT:
2006                case OS.WM_PASTE:
2007                case OS.WM_UNDO:
2008                case OS.EM_UNDO:
2009                case OS.WM_SETTEXT:
2010                    if (hwnd == hwndText) {
2011                        result = wmClipboard (hwnd, msg, wParam, lParam);
2012                    }
2013                    break;
2014            }
2015            if (result != null) return result.value;
2016            return callWindowProc (hwnd, msg, wParam, lParam);
2017        }
2018    }
2019    if (msg == OS.CB_SETCURSEL) {
2020        if ((style & SWT.READ_ONLY) != 0) {
2021            if (hooks (SWT.Verify) || filters (SWT.Verify)) {
2022                String JavaDoc oldText = getText (), newText = null;
2023                if (wParam == -1) {
2024                    newText = "";
2025                } else {
2026                    if (0 <= wParam && wParam < getItemCount ()) {
2027                        newText = getItem (wParam);
2028                    }
2029                }
2030                if (newText != null && !newText.equals (oldText)) {
2031                    int length = OS.GetWindowTextLength (handle);
2032                    oldText = newText;
2033                    newText = verifyText (newText, 0, length, null);
2034                    if (newText == null) return 0;
2035                    if (!newText.equals (oldText)) {
2036                        int index = indexOf (newText);
2037                        if (index != -1 && index != wParam) {
2038                            return callWindowProc (handle, OS.CB_SETCURSEL, index, lParam);
2039                        }
2040                    }
2041                }
2042            }
2043        }
2044    }
2045    return super.windowProc (hwnd, msg, wParam, lParam);
2046}
2047
2048LRESULT WM_CTLCOLOR (int wParam, int lParam) {
2049    return wmColorChild (wParam, lParam);
2050}
2051
2052LRESULT WM_GETDLGCODE (int wParam, int lParam) {
2053    int code = callWindowProc (handle, OS.WM_GETDLGCODE, wParam, lParam);
2054    return new LRESULT (code | OS.DLGC_WANTARROWS);
2055}
2056
2057LRESULT WM_KILLFOCUS (int wParam, int lParam) {
2058    /*
2059    * Bug in Windows. When a combo box that is read only
2060    * is disposed in CBN_KILLFOCUS, Windows segment faults.
2061    * The fix is to send focus from WM_KILLFOCUS instead
2062    * of CBN_KILLFOCUS.
2063    *
2064    * NOTE: In version 6 of COMCTL32.DLL, the bug is fixed.
2065    */

2066    if ((style & SWT.READ_ONLY) != 0) {
2067        return super.WM_KILLFOCUS (wParam, lParam);
2068    }
2069    
2070    /*
2071    * Return NULL - Focus notification is
2072    * done in WM_COMMAND by CBN_KILLFOCUS.
2073    */

2074    return null;
2075}
2076
2077LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
2078    /*
2079    * Feature in Windows. When an editable combo box is dropped
2080    * down and the text in the entry field partially matches an
2081    * item in the list, Windows selects the item but doesn't send
2082    * WM_COMMAND with CBN_SELCHANGE. The fix is to detect that
2083    * the selection has changed and issue the notification.
2084    */

2085    int oldSelection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2086    LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
2087    if (result == LRESULT.ZERO) return result;
2088    if ((style & SWT.READ_ONLY) == 0) {
2089        int newSelection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2090        if (oldSelection != newSelection) {
2091            sendEvent (SWT.Modify);
2092            if (isDisposed ()) return LRESULT.ZERO;
2093            sendEvent (SWT.Selection);
2094            if (isDisposed ()) return LRESULT.ZERO;
2095        }
2096    }
2097    return result;
2098}
2099
2100LRESULT WM_SETFOCUS (int wParam, int lParam) {
2101    /*
2102    * Return NULL - Focus notification is
2103    * done by WM_COMMAND with CBN_SETFOCUS.
2104    */

2105    return null;
2106}
2107
2108LRESULT WM_SIZE (int wParam, int lParam) {
2109    /*
2110    * Bug in Windows. If the combo box has the CBS_SIMPLE style,
2111    * the list portion of the combo box is not redrawn when the
2112    * combo box is resized. The fix is to force a redraw when
2113    * the size has changed.
2114    */

2115    if ((style & SWT.SIMPLE) != 0) {
2116        LRESULT result = super.WM_SIZE (wParam, lParam);
2117        if (OS.IsWindowVisible (handle)) {
2118            if (OS.IsWinCE) {
2119                int hwndText = OS.GetDlgItem (handle, CBID_EDIT);
2120                if (hwndText != 0) OS.InvalidateRect (hwndText, null, true);
2121                int hwndList = OS.GetDlgItem (handle, CBID_LIST);
2122                if (hwndList != 0) OS.InvalidateRect (hwndList, null, true);
2123            } else {
2124                int uFlags = OS.RDW_ERASE | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
2125                OS.RedrawWindow (handle, null, 0, uFlags);
2126            }
2127        }
2128        return result;
2129    }
2130    
2131    /*
2132    * Feature in Windows. When an editable drop down combo box
2133    * contains text that does not correspond to an item in the
2134    * list, when the widget is resized, it selects the closest
2135    * match from the list. The fix is to remember the original
2136    * text and reset it after the widget is resized.
2137    */

2138    LRESULT result = null;
2139    if ((style & SWT.READ_ONLY) != 0) {
2140        result = super.WM_SIZE (wParam, lParam);
2141    } else {
2142        int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2143        boolean redraw = false;
2144        TCHAR buffer = null;
2145        int [] start = null, end = null;
2146        if (index == OS.CB_ERR) {
2147            int length = OS.GetWindowTextLength (handle);
2148            if (length != 0) {
2149                buffer = new TCHAR (getCodePage (), length + 1);
2150                OS.GetWindowText (handle, buffer, length + 1);
2151                start = new int [1]; end = new int [1];
2152                OS.SendMessage (handle, OS.CB_GETEDITSEL, start, end);
2153                redraw = drawCount == 0 && OS.IsWindowVisible (handle);
2154                if (redraw) setRedraw (false);
2155            }
2156        }
2157        result = super.WM_SIZE (wParam, lParam);
2158        /*
2159        * It is possible (but unlikely), that application
2160        * code could have disposed the widget in the resize
2161        * event. If this happens, end the processing of the
2162        * Windows message by returning the result of the
2163        * WM_SIZE message.
2164        */

2165        if (isDisposed ()) return result;
2166        if (buffer != null) {
2167            OS.SetWindowText (handle, buffer);
2168            int bits = (start [0] & 0xFFFF) | ((end [0] << 16) & 0xFFFF0000);
2169            OS.SendMessage (handle, OS.CB_SETEDITSEL, 0, bits);
2170            if (redraw) setRedraw (true);
2171        }
2172    }
2173    /*
2174    * Feature in Windows. When CB_SETDROPPEDWIDTH is called with
2175    * a width that is smaller than the current size of the combo
2176    * box, it is ignored. This the fix is to set the width after
2177    * the combo box has been resized.
2178    */

2179    if ((style & SWT.H_SCROLL) != 0) setScrollWidth (scrollWidth);
2180    return result;
2181}
2182
2183LRESULT wmChar (int hwnd, int wParam, int lParam) {
2184    if (ignoreCharacter) return null;
2185    LRESULT result = super.wmChar (hwnd, wParam, lParam);
2186    if (result != null) return result;
2187    /*
2188    * Feature in Windows. For some reason, when the
2189    * widget is a single line text widget, when the
2190    * user presses tab, return or escape, Windows beeps.
2191    * The fix is to look for these keys and not call
2192    * the window proc.
2193    *
2194    * NOTE: This only happens when the drop down list
2195    * is not visible.
2196    */

2197    switch (wParam) {
2198        case SWT.TAB: return LRESULT.ZERO;
2199        case SWT.CR:
2200            if (!ignoreDefaultSelection) postEvent (SWT.DefaultSelection);
2201            ignoreDefaultSelection = false;
2202            // FALL THROUGH
2203
case SWT.ESC:
2204            if ((style & SWT.DROP_DOWN) != 0) {
2205                if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) == 0) {
2206                    return LRESULT.ZERO;
2207                }
2208            }
2209    }
2210    return result;
2211}
2212
2213LRESULT wmClipboard (int hwndText, int msg, int wParam, int lParam) {
2214    if ((style & SWT.READ_ONLY) != 0) return null;
2215    if (!hooks (SWT.Verify) && !filters (SWT.Verify)) return null;
2216    boolean call = false;
2217    int [] start = new int [1], end = new int [1];
2218    String JavaDoc newText = null;
2219    switch (msg) {
2220        case OS.WM_CLEAR:
2221        case OS.WM_CUT:
2222            OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
2223            if (start [0] != end [0]) {
2224                newText = "";
2225                call = true;
2226            }
2227            break;
2228        case OS.WM_PASTE:
2229            OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
2230            newText = getClipboardText ();
2231            break;
2232        case OS.EM_UNDO:
2233        case OS.WM_UNDO:
2234            if (OS.SendMessage (hwndText, OS.EM_CANUNDO, 0, 0) != 0) {
2235                ignoreModify = true;
2236                OS.SendMessage (hwndText, OS.EM_GETSEL, start, end);
2237                OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
2238                int length = OS.GetWindowTextLength (hwndText);
2239                int [] newStart = new int [1], newEnd = new int [1];
2240                OS.SendMessage (hwndText, OS.EM_GETSEL, newStart, newEnd);
2241                if (length != 0 && newStart [0] != newEnd [0]) {
2242                    TCHAR buffer = new TCHAR (getCodePage (), length + 1);
2243                    OS.GetWindowText (hwndText, buffer, length + 1);
2244                    newText = buffer.toString (newStart [0], newEnd [0] - newStart [0]);
2245                } else {
2246                    newText = "";
2247                }
2248                OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
2249                ignoreModify = false;
2250            }
2251            break;
2252        case OS.WM_SETTEXT:
2253            end [0] = OS.GetWindowTextLength (hwndText);
2254            int length = OS.IsUnicode ? OS.wcslen (lParam) : OS.strlen (lParam);
2255            TCHAR buffer = new TCHAR (getCodePage (), length);
2256            int byteCount = buffer.length () * TCHAR.sizeof;
2257            OS.MoveMemory (buffer, lParam, byteCount);
2258            newText = buffer.toString (0, length);
2259            break;
2260    }
2261    if (newText != null) {
2262        String JavaDoc oldText = newText;
2263        newText = verifyText (newText, start [0], end [0], null);
2264        if (newText == null) return LRESULT.ZERO;
2265        if (!newText.equals (oldText)) {
2266            if (call) {
2267                OS.CallWindowProc (EditProc, hwndText, msg, wParam, lParam);
2268            }
2269            TCHAR buffer = new TCHAR (getCodePage (), newText, true);
2270            if (msg == OS.WM_SETTEXT) {
2271                int hHeap = OS.GetProcessHeap ();
2272                int byteCount = buffer.length () * TCHAR.sizeof;
2273                int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
2274                OS.MoveMemory (pszText, buffer, byteCount);
2275                int code = OS.CallWindowProc (EditProc, hwndText, msg, wParam, pszText);
2276                OS.HeapFree (hHeap, 0, pszText);
2277                return new LRESULT (code);
2278            } else {
2279                OS.SendMessage (hwndText, OS.EM_REPLACESEL, 0, buffer);
2280                return LRESULT.ZERO;
2281            }
2282        }
2283    }
2284    return null;
2285}
2286
2287LRESULT wmCommandChild (int wParam, int lParam) {
2288    int code = wParam >> 16;
2289    switch (code) {
2290        case OS.CBN_EDITCHANGE:
2291            if (ignoreModify) break;
2292            /*
2293            * Feature in Windows. If the combo box list selection is
2294            * queried using CB_GETCURSEL before the WM_COMMAND (with
2295            * CBN_EDITCHANGE) returns, CB_GETCURSEL returns the previous
2296            * selection in the list. It seems that the combo box sends
2297            * the WM_COMMAND before it makes the selection in the list box
2298            * match the entry field. The fix is remember that no selection
2299            * in the list should exist in this case.
2300            */

2301            noSelection = true;
2302            sendEvent (SWT.Modify);
2303            if (isDisposed ()) return LRESULT.ZERO;
2304            noSelection = false;
2305            break;
2306        case OS.CBN_SELCHANGE:
2307            /*
2308            * Feature in Windows. If the text in an editable combo box
2309            * is queried using GetWindowText () before the WM_COMMAND
2310            * (with CBN_SELCHANGE) returns, GetWindowText () returns is
2311            * the previous text in the combo box. It seems that the combo
2312            * box sends the WM_COMMAND before it updates the text field to
2313            * match the list selection. The fix is to force the text field
2314            * to match the list selection by re-selecting the list item.
2315            */

2316            int index = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2317            if (index != OS.CB_ERR) {
2318                OS.SendMessage (handle, OS.CB_SETCURSEL, index, 0);
2319            }
2320            /*
2321            * It is possible (but unlikely), that application
2322            * code could have disposed the widget in the modify
2323            * event. If this happens, end the processing of the
2324            * Windows message by returning zero as the result of
2325            * the window proc.
2326            */

2327            sendEvent (SWT.Modify);
2328            if (isDisposed ()) return LRESULT.ZERO;
2329            postEvent (SWT.Selection);
2330            break;
2331        case OS.CBN_SETFOCUS:
2332            sendFocusEvent (SWT.FocusIn);
2333            if (isDisposed ()) return LRESULT.ZERO;
2334            break;
2335        case OS.CBN_KILLFOCUS:
2336            /*
2337            * Bug in Windows. When a combo box that is read only
2338            * is disposed in CBN_KILLFOCUS, Windows segment faults.
2339            * The fix is to send focus from WM_KILLFOCUS instead
2340            * of CBN_KILLFOCUS.
2341            *
2342            * NOTE: In version 6 of COMCTL32.DLL, the bug is fixed.
2343            */

2344            if ((style & SWT.READ_ONLY) != 0) break;
2345            sendFocusEvent (SWT.FocusOut);
2346            if (isDisposed ()) return LRESULT.ZERO;
2347            break;
2348    }
2349    return super.wmCommandChild (wParam, lParam);
2350}
2351
2352LRESULT wmIMEChar (int hwnd, int wParam, int lParam) {
2353
2354    /* Process a DBCS character */
2355    Display display = this.display;
2356    display.lastKey = 0;
2357    display.lastAscii = wParam;
2358    display.lastVirtual = display.lastNull = display.lastDead = false;
2359    if (!sendKeyEvent (SWT.KeyDown, OS.WM_IME_CHAR, wParam, lParam)) {
2360        return LRESULT.ZERO;
2361    }
2362
2363    /*
2364    * Feature in Windows. The Windows text widget uses
2365    * two 2 WM_CHAR's to process a DBCS key instead of
2366    * using WM_IME_CHAR. The fix is to allow the text
2367    * widget to get the WM_CHAR's but ignore sending
2368    * them to the application.
2369    */

2370    ignoreCharacter = true;
2371    int result = callWindowProc (hwnd, OS.WM_IME_CHAR, wParam, lParam);
2372    MSG msg = new MSG ();
2373    int flags = OS.PM_REMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
2374    while (OS.PeekMessage (msg, hwnd, OS.WM_CHAR, OS.WM_CHAR, flags)) {
2375        OS.TranslateMessage (msg);
2376        OS.DispatchMessage (msg);
2377    }
2378    ignoreCharacter = false;
2379    
2380    sendKeyEvent (SWT.KeyUp, OS.WM_IME_CHAR, wParam, lParam);
2381    // widget could be disposed at this point
2382
display.lastKey = display.lastAscii = 0;
2383    return new LRESULT (result);
2384}
2385
2386LRESULT wmKeyDown (int hwnd, int wParam, int lParam) {
2387    if (ignoreCharacter) return null;
2388    LRESULT result = super.wmKeyDown (hwnd, wParam, lParam);
2389    if (result != null) return result;
2390    ignoreDefaultSelection = false;
2391    if (wParam == OS.VK_RETURN) {
2392        if ((style & SWT.DROP_DOWN) != 0) {
2393            if (OS.SendMessage (handle, OS.CB_GETDROPPEDSTATE, 0, 0) != 0) {
2394                ignoreDefaultSelection = true;
2395            }
2396        }
2397    }
2398    return result;
2399}
2400
2401LRESULT wmSysKeyDown (int hwnd, int wParam, int lParam) {
2402    /*
2403    * Feature in Windows. When an editable combo box is dropped
2404    * down using Alt+Down and the text in the entry field partially
2405    * matches an item in the list, Windows selects the item but doesn't
2406    * send WM_COMMAND with CBN_SELCHANGE. The fix is to detect that
2407    * the selection has changed and issue the notification.
2408    */

2409    int oldSelection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2410    LRESULT result = super.wmSysKeyDown (hwnd, wParam, lParam);
2411    if (result != null) return result;
2412    if ((style & SWT.READ_ONLY) == 0) {
2413        if (wParam == OS.VK_DOWN) {
2414            int code = callWindowProc (hwnd, OS.WM_SYSKEYDOWN, wParam, lParam);
2415            int newSelection = OS.SendMessage (handle, OS.CB_GETCURSEL, 0, 0);
2416            if (oldSelection != newSelection) {
2417                sendEvent (SWT.Modify);
2418                if (isDisposed ()) return LRESULT.ZERO;
2419                sendEvent (SWT.Selection);
2420                if (isDisposed ()) return LRESULT.ZERO;
2421            }
2422            return new LRESULT (code);
2423        }
2424    }
2425    return result;
2426}
2427
2428}
2429
Popular Tags