1 /*******************************************************************************
2 * Copyright (c) 2000, 2019 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 * Paul Pazderski - Bug 349112: allow setting alignment on the text field
14 *******************************************************************************/
15 package org.eclipse.swt.custom;
18 import java.util.function.*;
20 import org.eclipse.swt.*;
21 import org.eclipse.swt.accessibility.*;
22 import org.eclipse.swt.events.*;
23 import org.eclipse.swt.graphics.*;
24 import org.eclipse.swt.widgets.*;
27 * The CCombo class represents a selectable user interface object
28 * that combines a text field and a list and issues notification
29 * when an item is selected from the list.
31 * CCombo was written to work around certain limitations in the native
32 * combo box. Specifically, on win32, the height of a CCombo can be set;
33 * attempts to set the height of a Combo are ignored. CCombo can be used
34 * anywhere that having the increased flexibility is more important than
35 * getting native L&F, but the decision should not be taken lightly.
36 * There is no strict requirement that CCombo look or behave the same as
37 * the native combo box.
40 * Note that although this class is a subclass of <code>Composite</code>,
41 * it does not make sense to add children to it, or set a layout on it.
45 * <dd>BORDER, READ_ONLY, FLAT, LEAD, LEFT, CENTER, TRAIL, RIGHT</dd>
47 * <dd>DefaultSelection, Modify, Selection, Verify</dd>
50 * @see <a href="http://www.eclipse.org/swt/snippets/#ccombo">CCombo snippets</a>
51 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample</a>
52 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
54 public class CCombo extends Composite {
58 int visibleItemCount = 5;
62 Listener listener, filter;
63 Color foreground, background;
67 static final String PACKAGE_PREFIX = "org.eclipse.swt.custom."; //$NON-NLS-1$
70 * Constructs a new instance of this class given its parent
71 * and a style value describing its behavior and appearance.
73 * The style value is either one of the style constants defined in
74 * class <code>SWT</code> which is applicable to instances of this
75 * class, or must be built by <em>bitwise OR</em>'ing together
76 * (that is, using the <code>int</code> "|" operator) two or more
77 * of those <code>SWT</code> style constants. The class description
78 * lists the style constants that are applicable to the class.
79 * Style bits are also inherited from superclasses.
82 * @param parent a widget which will be the parent of the new instance (cannot be null)
83 * @param style the style of widget to construct
85 * @exception IllegalArgumentException <ul>
86 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
88 * @exception SWTException <ul>
89 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
100 * @see Widget#getStyle()
102 public CCombo (Composite parent, int style) {
103 super (parent, style = checkStyle (style));
104 _shell = super.getShell ();
106 listener = event -> {
107 if (isDisposed ()) return;
108 if (popup == event.widget) {
112 if (text == event.widget) {
116 if (list == event.widget) {
120 if (arrow == event.widget) {
124 if (CCombo.this == event.widget) {
128 if (getShell () == event.widget) {
129 getDisplay().asyncExec(() -> {
130 if (isDisposed ()) return;
131 handleFocus (SWT.FocusOut);
138 int arrowStyle = SWT.ARROW | SWT.DOWN;
139 if ((style & SWT.FLAT) != 0) arrowStyle |= SWT.FLAT;
140 arrow = new Button (this, arrowStyle);
142 if (isDisposed ()) return;
143 if (event.type == SWT.Selection) {
144 if (event.widget instanceof ScrollBar) {
149 Shell shell = ((Control)event.widget).getShell ();
150 if (shell == CCombo.this.getShell ()) {
151 handleFocus (SWT.FocusOut);
155 int [] comboEvents = {SWT.Dispose, SWT.FocusIn, SWT.Move, SWT.Resize, SWT.FocusOut};
156 for (int i=0; i<comboEvents.length; i++) this.addListener (comboEvents [i], listener);
158 int [] arrowEvents = {SWT.DragDetect, SWT.MouseDown, SWT.MouseEnter, SWT.MouseExit, SWT.MouseHover,
159 SWT.MouseMove, SWT.MouseUp, SWT.MouseWheel, SWT.Selection, SWT.FocusIn};
160 for (int i=0; i<arrowEvents.length; i++) arrow.addListener (arrowEvents [i], listener);
162 createPopup(null, -1);
163 if ((style & SWT.SIMPLE) == 0) {
164 int itemHeight = list.getItemHeight ();
165 if (itemHeight != 0) {
166 int maxHeight = getMonitor().getClientArea().height / 3;
167 visibleItemCount = Math.max(visibleItemCount, maxHeight / itemHeight);
173 static int checkStyle (int style) {
174 int mask = SWT.BORDER | SWT.READ_ONLY | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT | SWT.LEAD | SWT.CENTER | SWT.TRAIL;
175 return SWT.NO_FOCUS | (style & mask);
177 void createText(int comboStyle) {
178 String textValue = null, tooltip = null;
179 Point selection = null;
181 boolean enabled = false, focus = false, editable = false;
183 Color fg = null, bg = null;
186 textValue = text.getText();
187 tooltip = text.getToolTipText();
188 selection = text.getSelection();
189 limit = text.getTextLimit();
190 enabled = text.isEnabled();
191 editable = text.getEditable();
192 focus = text.isFocusControl();
193 font = text.getFont();
194 fg = text.getForeground();
195 bg = text.getBackground();
196 menu = text.getMenu();
200 int textStyle = SWT.SINGLE;
201 if ((comboStyle & SWT.READ_ONLY) != 0) textStyle |= SWT.READ_ONLY;
202 if ((comboStyle & SWT.FLAT) != 0) textStyle |= SWT.FLAT;
203 textStyle |= comboStyle & (SWT.LEAD | SWT.CENTER | SWT.TRAIL);
204 text = new Text (this, textStyle);
205 if (textValue != null) {
206 text.setText(textValue);
207 text.setToolTipText(tooltip);
208 if (selection != null) text.setSelection(selection);
209 text.setTextLimit(limit);
210 text.setEnabled(enabled);
211 text.setEditable(editable);
212 if (focus) text.setFocus();
213 if (font != null && !font.isDisposed()) text.setFont(font);
214 if (fg != null && !fg.isDisposed()) text.setForeground(fg);
215 if (bg != null && !bg.isDisposed()) text.setBackground(bg);
216 if (menu != null && !menu.isDisposed()) text.setMenu(menu);
217 internalLayout(true);
220 int [] textEvents = {SWT.DefaultSelection, SWT.DragDetect, SWT.KeyDown, SWT.KeyUp, SWT.MenuDetect, SWT.Modify,
221 SWT.MouseDown, SWT.MouseUp, SWT.MouseDoubleClick, SWT.MouseEnter, SWT.MouseExit, SWT.MouseHover,
222 SWT.MouseMove, SWT.MouseWheel, SWT.Traverse, SWT.FocusIn, SWT.Verify};
223 for (int i=0; i<textEvents.length; i++) text.addListener (textEvents [i], listener);
226 * Adds the argument to the end of the receiver's list.
228 * Note: If control characters like '\n', '\t' etc. are used
229 * in the string, then the behavior is platform dependent.
231 * @param string the new item
233 * @exception IllegalArgumentException <ul>
234 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
236 * @exception SWTException <ul>
237 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
238 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
241 * @see #add(String,int)
243 public void add (String string) {
245 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
249 * Adds the argument to the receiver's list at the given
250 * zero-relative index.
252 * Note: To add an item at the end of the list, use the
253 * result of calling <code>getItemCount()</code> as the
254 * index or use <code>add(String)</code>.
256 * Also note, if control characters like '\n', '\t' etc. are used
257 * in the string, then the behavior is platform dependent.
260 * @param string the new item
261 * @param index the index for the item
263 * @exception IllegalArgumentException <ul>
264 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
265 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
267 * @exception SWTException <ul>
268 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
269 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
274 public void add (String string, int index) {
276 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
277 list.add (string, index);
280 * Adds the listener to the collection of listeners who will
281 * be notified when the receiver's text is modified, by sending
282 * it one of the messages defined in the <code>ModifyListener</code>
285 * @param listener the listener which should be notified
287 * @exception IllegalArgumentException <ul>
288 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
290 * @exception SWTException <ul>
291 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
292 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
295 * @see ModifyListener
296 * @see #removeModifyListener
298 public void addModifyListener (ModifyListener listener) {
300 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
301 TypedListener typedListener = new TypedListener (listener);
302 addListener (SWT.Modify, typedListener);
305 * Adds the listener to the collection of listeners who will
306 * be notified when the user changes the receiver's selection, by sending
307 * it one of the messages defined in the <code>SelectionListener</code>
310 * <code>widgetSelected</code> is called when the combo's list selection changes.
311 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
314 * @param listener the listener which should be notified when the user changes the receiver's selection
316 * @exception IllegalArgumentException <ul>
317 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
319 * @exception SWTException <ul>
320 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
321 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
324 * @see SelectionListener
325 * @see #removeSelectionListener
326 * @see SelectionEvent
328 public void addSelectionListener(SelectionListener listener) {
330 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
331 TypedListener typedListener = new TypedListener (listener);
332 addListener (SWT.Selection,typedListener);
333 addListener (SWT.DefaultSelection,typedListener);
336 * Adds the listener to the collection of listeners who will
337 * be notified when the receiver's text is verified, by sending
338 * it one of the messages defined in the <code>VerifyListener</code>
341 * @param listener the listener which should be notified
343 * @exception IllegalArgumentException <ul>
344 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
346 * @exception SWTException <ul>
347 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
348 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
351 * @see VerifyListener
352 * @see #removeVerifyListener
356 public void addVerifyListener (VerifyListener listener) {
358 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
359 TypedListener typedListener = new TypedListener (listener);
360 addListener (SWT.Verify,typedListener);
362 void arrowEvent (Event event) {
363 switch (event.type) {
365 handleFocus (SWT.FocusIn);
374 case SWT.MouseHover: {
375 Point pt = getDisplay ().map (arrow, this, event.x, event.y);
376 event.x = pt.x; event.y = pt.y;
377 notifyListeners (event.type, event);
378 event.type = SWT.None;
381 case SWT.MouseWheel: {
382 Point pt = getDisplay ().map (arrow, this, event.x, event.y);
383 event.x = pt.x; event.y = pt.y;
384 notifyListeners (SWT.MouseWheel, event);
385 event.type = SWT.None;
386 if (isDisposed ()) break;
387 if (!event.doit) break;
388 if (event.count != 0) {
390 int oldIndex = getSelectionIndex ();
391 if (event.count > 0) {
392 select (Math.max (oldIndex - 1, 0));
394 select (Math.min (oldIndex + 1, getItemCount () - 1));
396 if (oldIndex != getSelectionIndex ()) {
397 Event e = new Event();
399 e.stateMask = event.stateMask;
400 notifyListeners (SWT.Selection, e);
402 if (isDisposed ()) break;
406 case SWT.Selection: {
408 dropDown (!isDropped ());
414 protected void checkSubclass () {
415 String name = getClass ().getName ();
416 int index = name.lastIndexOf ('.');
417 if (!name.substring (0, index + 1).equals (PACKAGE_PREFIX)) {
418 SWT.error (SWT.ERROR_INVALID_SUBCLASS);
422 * Sets the selection in the receiver's text field to an empty
423 * selection starting just before the first character. If the
424 * text field is editable, this has the effect of placing the
425 * i-beam at the start of the text.
427 * Note: To clear the selected items in the receiver's list,
428 * use <code>deselectAll()</code>.
431 * @exception SWTException <ul>
432 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
433 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
438 public void clearSelection () {
440 text.clearSelection ();
443 void comboEvent (Event event) {
444 switch (event.type) {
446 removeListener(SWT.Dispose, listener);
447 notifyListeners(SWT.Dispose, event);
448 event.type = SWT.None;
450 if (popup != null && !popup.isDisposed ()) {
451 list.removeListener (SWT.Dispose, listener);
454 Shell shell = getShell ();
455 shell.removeListener (SWT.Deactivate, listener);
456 Display display = getDisplay ();
457 display.removeFilter (SWT.FocusIn, filter);
465 Control focusControl = getDisplay ().getFocusControl ();
466 if (focusControl == arrow || focusControl == list) return;
474 text.clearSelection();
480 internalLayout (false);
486 public Point computeSize (int wHint, int hHint, boolean changed) {
488 int width = 0, height = 0;
489 String[] items = list.getItems ();
490 GC gc = new GC (text);
491 int spacer = gc.stringExtent (" ").x; //$NON-NLS-1$
492 int textWidth = gc.stringExtent (text.getText ()).x;
493 for (int i = 0; i < items.length; i++) {
494 textWidth = Math.max (gc.stringExtent (items[i]).x, textWidth);
497 Point textSize = text.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed);
498 Point arrowSize = arrow.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed);
499 Point listSize = list.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed);
500 int borderWidth = getBorderWidth ();
502 height = Math.max (textSize.y, arrowSize.y);
503 width = Math.max (textWidth + 2*spacer + arrowSize.x + 2*borderWidth, listSize.x);
504 if (wHint != SWT.DEFAULT) width = wHint;
505 if (hHint != SWT.DEFAULT) height = hHint;
506 return new Point (width + 2*borderWidth, height + 2*borderWidth);
509 * Copies the selected text.
511 * The current selection is copied to the clipboard.
514 * @exception SWTException <ul>
515 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
516 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
521 public void copy () {
525 void createPopup(String[] items, int selectionIndex) {
526 // create shell and list
527 popup = new Shell (getShell (), SWT.NO_TRIM | SWT.ON_TOP);
528 int style = getStyle ();
529 int listStyle = SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL;
530 if ((style & SWT.FLAT) != 0) listStyle |= SWT.FLAT;
531 if ((style & SWT.RIGHT_TO_LEFT) != 0) listStyle |= SWT.RIGHT_TO_LEFT;
532 if ((style & SWT.LEFT_TO_RIGHT) != 0) listStyle |= SWT.LEFT_TO_RIGHT;
533 list = new List (popup, listStyle);
534 if (font != null) list.setFont (font);
535 if (foreground != null) list.setForeground (foreground);
536 if (background != null) list.setBackground (background);
538 int [] popupEvents = {SWT.Close, SWT.Paint};
539 for (int i=0; i<popupEvents.length; i++) popup.addListener (popupEvents [i], listener);
540 int [] listEvents = {SWT.MouseUp, SWT.Selection, SWT.Traverse, SWT.KeyDown, SWT.KeyUp, SWT.FocusIn, SWT.FocusOut, SWT.Dispose};
541 for (int i=0; i<listEvents.length; i++) list.addListener (listEvents [i], listener);
543 if (items != null) list.setItems (items);
544 if (selectionIndex != -1) list.setSelection (selectionIndex);
547 * Cuts the selected text.
549 * The current selection is first copied to the
550 * clipboard and then deleted from the widget.
553 * @exception SWTException <ul>
554 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
555 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
565 * Deselects the item at the given zero-relative index in the receiver's
566 * list. If the item at the index was already deselected, it remains
567 * deselected. Indices that are out of range are ignored.
569 * @param index the index of the item to deselect
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>
576 public void deselect (int index) {
578 if (0 <= index && index < list.getItemCount () &&
579 index == list.getSelectionIndex() &&
580 text.getText().equals(list.getItem(index))) {
581 text.setText(""); //$NON-NLS-1$
582 list.deselect (index);
586 * Deselects all selected items in the receiver's list.
588 * Note: To clear the selection in the receiver's text field,
589 * use <code>clearSelection()</code>.
592 * @exception SWTException <ul>
593 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
594 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
597 * @see #clearSelection
599 public void deselectAll () {
601 text.setText(""); //$NON-NLS-1$
604 void dropDown (boolean drop) {
605 if (drop == isDropped ()) return;
606 Display display = getDisplay ();
608 display.removeFilter (SWT.Selection, filter);
609 popup.setVisible (false);
610 if (!isDisposed () && isFocusControl()) {
615 if (!isVisible()) return;
616 if (getShell() != popup.getParent ()) {
617 String[] items = list.getItems ();
618 int selectionIndex = list.getSelectionIndex ();
619 list.removeListener (SWT.Dispose, listener);
623 createPopup (items, selectionIndex);
626 Point comboSize = getSize ();
627 int itemCount = list.getItemCount ();
628 itemCount = (itemCount == 0) ? visibleItemCount : Math.min(visibleItemCount, itemCount);
629 int itemHeight = list.getItemHeight () * itemCount;
630 Point listSize = list.computeSize (SWT.DEFAULT, itemHeight, false);
631 Rectangle displayRect = getMonitor ().getClientArea ();
632 list.setBounds (1, 1, Math.max (comboSize.x - 2, Math.min(listSize.x, displayRect.width - 2)), listSize.y);
634 int index = list.getSelectionIndex ();
635 if (index != -1) list.setTopIndex (index);
636 Rectangle listRect = list.getBounds ();
637 Rectangle parentRect = display.map (getParent (), null, getBounds ());
638 int width = listRect.width + 2;
639 int height = listRect.height + 2;
640 int x = parentRect.x;
641 if (x + width > displayRect.x + displayRect.width) {
642 x = displayRect.x + displayRect.width - width;
644 int y = parentRect.y + comboSize.y;
645 if (y + height > displayRect.y + displayRect.height) {
646 int popUpwardsHeight = (parentRect.y - height < displayRect.y) ? parentRect.y - displayRect.y : height;
647 int popDownwardsHeight = displayRect.y + displayRect.height - y;
648 if (popUpwardsHeight > popDownwardsHeight) {
649 height = popUpwardsHeight;
650 y = parentRect.y - popUpwardsHeight;
652 height = popDownwardsHeight;
654 listRect.height = height - 2;
657 * Invisible HScrollBar lead to empty space at end of CCombo drop-down.
658 * Fix is to reduce height of list and shell in that case, bug 388126.
660 ScrollBar hBar = list.getHorizontalBar();
661 int emptyHBarSpace = hBar.isVisible () ? 0 : hBar.getSize ().y;
662 list.setSize (listRect.width, listRect.height - emptyHBarSpace);
663 popup.setBounds (x, y, width, height - emptyHBarSpace);
664 popup.setVisible (true);
665 if (isFocusControl()) list.setFocus ();
668 * Add a filter to listen to scrolling of the parent composite, when the
669 * drop-down is visible. Remove the filter when drop-down is not
672 display.removeFilter (SWT.Selection, filter);
673 display.addFilter (SWT.Selection, filter);
676 * Return the lowercase of the first non-'&' character following
677 * an '&' character in the given string. If there are no '&'
678 * characters in the given string, return '\0'.
680 char _findMnemonic (String string) {
681 if (string == null) return '\0';
683 int length = string.length ();
685 while (index < length && string.charAt (index) != '&') index++;
686 if (++index >= length) return '\0';
687 if (string.charAt (index) != '&') return Character.toLowerCase (string.charAt (index));
689 } while (index < length);
693 * Return the Label immediately preceding the receiver in the z-order,
696 String getAssociatedLabel () {
697 Control[] siblings = getParent ().getChildren ();
698 for (int i = 0; i < siblings.length; i++) {
699 if (siblings [i] == this) {
701 Control sibling = siblings [i-1];
702 if (sibling instanceof Label) return ((Label) sibling).getText();
703 if (sibling instanceof CLabel) return ((CLabel) sibling).getText();
711 * Returns the horizontal alignment.
712 * The alignment style (LEFT, CENTER or RIGHT) is returned.
714 * @return SWT.LEFT, SWT.RIGHT or SWT.CENTER
717 public int getAlignment() {
718 return text.getStyle() & (SWT.LEFT | SWT.CENTER | SWT.RIGHT);
721 public Control [] getChildren () {
723 return new Control [0];
726 * Gets the editable state.
728 * @return whether or not the receiver is editable
730 * @exception SWTException <ul>
731 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
732 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
737 public boolean getEditable () {
739 return text.getEditable();
742 * Returns the item at the given, zero-relative index in the
743 * receiver's list. Throws an exception if the index is out
746 * @param index the index of the item to return
747 * @return the item at the given index
749 * @exception IllegalArgumentException <ul>
750 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
752 * @exception SWTException <ul>
753 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
754 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
757 public String getItem (int index) {
759 return list.getItem (index);
762 * Returns the number of items contained in the receiver's list.
764 * @return the number of items
766 * @exception SWTException <ul>
767 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
768 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
771 public int getItemCount () {
773 return list.getItemCount ();
776 * Returns the height of the area which would be used to
777 * display <em>one</em> of the items in the receiver's list.
779 * @return the height of one item
781 * @exception SWTException <ul>
782 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
783 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
786 public int getItemHeight () {
788 return list.getItemHeight ();
791 * Returns an array of <code>String</code>s which are the items
792 * in the receiver's list.
794 * Note: This is not the actual structure used by the receiver
795 * to maintain its list of items, so modifying the array will
796 * not affect the receiver.
799 * @return the items in the receiver's list
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>
806 public String [] getItems () {
808 return list.getItems ();
811 * Returns <code>true</code> if the receiver's list is visible,
812 * and <code>false</code> otherwise.
814 * If one of the receiver's ancestors is not visible or some
815 * other condition makes the receiver not visible, this method
816 * may still indicate that it is considered visible even though
817 * it may not actually be showing.
820 * @return the receiver's list's visibility state
822 * @exception SWTException <ul>
823 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
824 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
829 public boolean getListVisible () {
834 public Menu getMenu() {
835 return text.getMenu();
838 * Returns a <code>Point</code> whose x coordinate is the start
839 * of the selection in the receiver's text field, and whose y
840 * coordinate is the end of the selection. The returned values
841 * are zero-relative. An "empty" selection as indicated by
842 * the the x and y coordinates having the same value.
844 * @return a point representing the selection start and end
846 * @exception SWTException <ul>
847 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
848 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
851 public Point getSelection () {
853 return text.getSelection ();
856 * Returns the zero-relative index of the item which is currently
857 * selected in the receiver's list, or -1 if no item is selected.
859 * @return the index of the selected item
861 * @exception SWTException <ul>
862 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
863 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
866 public int getSelectionIndex () {
868 return list.getSelectionIndex ();
871 public Shell getShell () {
873 Shell shell = super.getShell ();
874 if (shell != _shell) {
875 if (_shell != null && !_shell.isDisposed ()) {
876 _shell.removeListener (SWT.Deactivate, listener);
883 public int getStyle () {
884 int style = super.getStyle ();
885 style &= ~SWT.READ_ONLY;
886 if (!text.getEditable()) style |= SWT.READ_ONLY;
887 style &= ~(SWT.LEFT | SWT.CENTER | SWT.RIGHT);
888 style |= getAlignment();
892 * Returns a string containing a copy of the contents of the
893 * receiver's text field.
895 * @return the receiver's text
897 * @exception SWTException <ul>
898 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
899 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
902 public String getText () {
904 return text.getText ();
907 * Returns the height of the receivers's text field.
909 * @return the text height
911 * @exception SWTException <ul>
912 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
913 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
916 public int getTextHeight () {
918 return text.getLineHeight ();
921 * Returns the maximum number of characters that the receiver's
922 * text field is capable of holding. If this has not been changed
923 * by <code>setTextLimit()</code>, it will be the constant
924 * <code>Combo.LIMIT</code>.
926 * @return the text limit
928 * @exception SWTException <ul>
929 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
930 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
933 public int getTextLimit () {
935 return text.getTextLimit ();
938 * Gets the number of items that are visible in the drop
939 * down portion of the receiver's list.
941 * @return the number of items that are visible
943 * @exception SWTException <ul>
944 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
945 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
950 public int getVisibleItemCount () {
952 return visibleItemCount;
954 void handleFocus (int type) {
957 if (hasFocus) return;
958 if (getEditable ()) text.selectAll ();
960 Shell shell = getShell ();
961 shell.removeListener (SWT.Deactivate, listener);
962 shell.addListener (SWT.Deactivate, listener);
963 Display display = getDisplay ();
964 display.removeFilter (SWT.FocusIn, filter);
965 display.addFilter (SWT.FocusIn, filter);
966 Event e = new Event ();
967 notifyListeners (SWT.FocusIn, e);
971 if (!hasFocus) return;
972 Control focusControl = getDisplay ().getFocusControl ();
973 if (focusControl == arrow || focusControl == list || focusControl == text) return;
975 Shell shell = getShell ();
976 shell.removeListener(SWT.Deactivate, listener);
977 Display display = getDisplay ();
978 display.removeFilter (SWT.FocusIn, filter);
979 Event e = new Event ();
980 notifyListeners (SWT.FocusOut, e);
985 void handleScroll(Event event) {
986 ScrollBar scrollBar = (ScrollBar)event.widget;
987 Control scrollableParent = scrollBar.getParent();
988 if (scrollableParent.equals(list)) return;
989 if (isParentScrolling(scrollableParent)) dropDown(false);
992 * Searches the receiver's list starting at the first item
993 * (index 0) until an item is found that is equal to the
994 * argument, and returns the index of that item. If no item
995 * is found, returns -1.
997 * @param string the search item
998 * @return the index of the item
1000 * @exception IllegalArgumentException <ul>
1001 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1003 * @exception SWTException <ul>
1004 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1005 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1008 public int indexOf (String string) {
1010 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1011 return list.indexOf (string);
1014 * Searches the receiver's list starting at the given,
1015 * zero-relative index until an item is found that is equal
1016 * to the argument, and returns the index of that item. If
1017 * no item is found or the starting index is out of range,
1020 * @param string the search item
1021 * @param start the zero-relative index at which to begin the search
1022 * @return the index of the item
1024 * @exception IllegalArgumentException <ul>
1025 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1027 * @exception SWTException <ul>
1028 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1029 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1032 public int indexOf (String string, int start) {
1034 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1035 return list.indexOf (string, start);
1038 void initAccessible() {
1039 AccessibleAdapter accessibleAdapter = new AccessibleAdapter () {
1041 public void getName (AccessibleEvent e) {
1043 String text = getAssociatedLabel ();
1045 name = stripMnemonic (text);
1050 public void getKeyboardShortcut(AccessibleEvent e) {
1051 String shortcut = null;
1052 String text = getAssociatedLabel ();
1054 char mnemonic = _findMnemonic (text);
1055 if (mnemonic != '\0') {
1056 shortcut = "Alt+"+mnemonic; //$NON-NLS-1$
1059 e.result = shortcut;
1062 public void getHelp (AccessibleEvent e) {
1063 e.result = getToolTipText ();
1066 getAccessible ().addAccessibleListener (accessibleAdapter);
1067 text.getAccessible ().addAccessibleListener (accessibleAdapter);
1068 list.getAccessible ().addAccessibleListener (accessibleAdapter);
1070 arrow.getAccessible ().addAccessibleListener (new AccessibleAdapter() {
1072 public void getName (AccessibleEvent e) {
1073 e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
1076 public void getKeyboardShortcut (AccessibleEvent e) {
1077 e.result = "Alt+Down Arrow"; //$NON-NLS-1$
1080 public void getHelp (AccessibleEvent e) {
1081 e.result = getToolTipText ();
1085 getAccessible().addAccessibleTextListener (new AccessibleTextAdapter() {
1087 public void getCaretOffset (AccessibleTextEvent e) {
1088 e.offset = text.getCaretPosition ();
1091 public void getSelectionRange(AccessibleTextEvent e) {
1092 Point sel = text.getSelection();
1094 e.length = sel.y - sel.x;
1098 getAccessible().addAccessibleControlListener (new AccessibleControlAdapter() {
1100 public void getChildAtPoint (AccessibleControlEvent e) {
1101 Point testPoint = toControl (e.x, e.y);
1102 if (getBounds ().contains (testPoint)) {
1103 e.childID = ACC.CHILDID_SELF;
1108 public void getLocation (AccessibleControlEvent e) {
1109 Rectangle location = getBounds ();
1110 Point pt = getParent().toDisplay (location.x, location.y);
1113 e.width = location.width;
1114 e.height = location.height;
1118 public void getChildCount (AccessibleControlEvent e) {
1123 public void getRole (AccessibleControlEvent e) {
1124 e.detail = ACC.ROLE_COMBOBOX;
1128 public void getState (AccessibleControlEvent e) {
1129 e.detail = ACC.STATE_NORMAL;
1133 public void getValue (AccessibleControlEvent e) {
1134 e.result = getText ();
1138 text.getAccessible ().addAccessibleControlListener (new AccessibleControlAdapter () {
1140 public void getRole (AccessibleControlEvent e) {
1141 e.detail = text.getEditable () ? ACC.ROLE_TEXT : ACC.ROLE_LABEL;
1145 arrow.getAccessible ().addAccessibleControlListener (new AccessibleControlAdapter() {
1147 public void getDefaultAction (AccessibleControlEvent e) {
1148 e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$
1152 boolean isDropped () {
1153 return !isDisposed() && popup.getVisible ();
1156 public boolean isFocusControl () {
1158 Predicate<Control> checkFocusControl = (control) -> (control != null && !control.isDisposed() && control.isFocusControl ());
1159 if (checkFocusControl.test(text) || checkFocusControl.test(arrow) ||
1160 checkFocusControl.test(list) || checkFocusControl.test(popup)) {
1163 return super.isFocusControl ();
1166 boolean isParentScrolling(Control scrollableParent) {
1167 Control parent = this.getParent();
1168 while (parent != null) {
1169 if (parent.equals(scrollableParent))
1171 parent = parent.getParent();
1175 void internalLayout (boolean changed) {
1176 if (isDropped ()) dropDown (false);
1177 Rectangle rect = getClientArea ();
1178 int width = rect.width;
1179 int height = rect.height;
1180 Point arrowSize = arrow.computeSize (SWT.DEFAULT, height, changed);
1181 text.setBounds (0, 0, width - arrowSize.x, height);
1182 arrow.setBounds (width - arrowSize.x, 0, arrowSize.x, arrowSize.y);
1184 void listEvent (Event event) {
1185 switch (event.type) {
1187 if (getShell () != popup.getParent ()) {
1188 String[] items = list.getItems ();
1189 int selectionIndex = list.getSelectionIndex ();
1192 createPopup (items, selectionIndex);
1196 handleFocus (SWT.FocusIn);
1199 case SWT.FocusOut: {
1201 * Behavior in Windows, GTK & Cocoa: When the arrow button is pressed
1202 * with the popup list visible, the following events are received-
1203 * popup control receives a deactivate event,
1204 * list receives focus lost event, and then
1205 * arrow button receives a selection event.
1206 * If we hide the popup in the focus out event, the selection event will
1207 * show it again. To prevent the popup from showing again, we will detect
1208 * this case and let the selection event of the arrow button hide the popup.
1210 Point point = arrow.toControl(getDisplay().getCursorLocation());
1211 Point size = arrow.getSize();
1212 Rectangle rect = new Rectangle(0, 0, size.x, size.y);
1213 if (rect.contains(point)) {
1214 boolean comboShellActivated = getDisplay ().getActiveShell () == getShell ();
1215 if (!comboShellActivated) dropDown (false);
1222 if (event.button != 1) return;
1226 case SWT.Selection: {
1227 int index = list.getSelectionIndex ();
1228 if (index == -1) return;
1229 text.setText (list.getItem (index));
1230 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1231 list.setSelection (index);
1232 Event e = new Event ();
1233 e.time = event.time;
1234 e.stateMask = event.stateMask;
1235 e.doit = event.doit;
1236 notifyListeners (SWT.Selection, e);
1237 event.doit = e.doit;
1240 case SWT.Traverse: {
1241 switch (event.detail) {
1242 case SWT.TRAVERSE_RETURN:
1243 case SWT.TRAVERSE_ESCAPE:
1244 case SWT.TRAVERSE_ARROW_PREVIOUS:
1245 case SWT.TRAVERSE_ARROW_NEXT:
1248 case SWT.TRAVERSE_TAB_NEXT:
1249 case SWT.TRAVERSE_TAB_PREVIOUS:
1250 event.doit = text.traverse(event.detail);
1251 event.detail = SWT.TRAVERSE_NONE;
1252 if (event.doit) dropDown(false);
1255 Event e = new Event ();
1256 e.time = event.time;
1257 e.detail = event.detail;
1258 e.doit = event.doit;
1259 e.character = event.character;
1260 e.keyCode = event.keyCode;
1261 e.keyLocation = event.keyLocation;
1262 notifyListeners (SWT.Traverse, e);
1263 event.doit = e.doit;
1264 event.detail = e.detail;
1268 Event e = new Event ();
1269 e.time = event.time;
1270 e.character = event.character;
1271 e.keyCode = event.keyCode;
1272 e.keyLocation = event.keyLocation;
1273 e.stateMask = event.stateMask;
1274 notifyListeners (SWT.KeyUp, e);
1275 event.doit = e.doit;
1279 if (event.character == SWT.ESC) {
1280 // Escape key cancels popup list
1283 if ((event.stateMask & SWT.ALT) != 0 && (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN)) {
1286 if (event.character == SWT.CR) {
1287 // Enter causes default selection
1289 Event e = new Event ();
1290 e.time = event.time;
1291 e.stateMask = event.stateMask;
1292 notifyListeners (SWT.DefaultSelection, e);
1294 // At this point the widget may have been disposed.
1295 // If so, do not continue.
1296 if (isDisposed ()) break;
1297 Event e = new Event();
1298 e.time = event.time;
1299 e.character = event.character;
1300 e.keyCode = event.keyCode;
1301 e.keyLocation = event.keyLocation;
1302 e.stateMask = event.stateMask;
1303 notifyListeners(SWT.KeyDown, e);
1304 event.doit = e.doit;
1311 * Pastes text from clipboard.
1313 * The selected text is deleted from the widget
1314 * and new text inserted from the clipboard.
1317 * @exception SWTException <ul>
1318 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1319 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1324 public void paste () {
1328 void popupEvent(Event event) {
1329 switch (event.type) {
1331 // draw black rectangle around list
1332 Rectangle listRect = list.getBounds();
1333 Color black = getDisplay().getSystemColor(SWT.COLOR_BLACK);
1334 event.gc.setForeground(black);
1335 event.gc.drawRectangle(0, 0, listRect.width + 1, listRect.height + 1);
1344 public void redraw () {
1348 if (popup.isVisible()) list.redraw();
1351 public void redraw (int x, int y, int width, int height, boolean all) {
1352 super.redraw(x, y, width, height, true);
1356 * Removes the item from the receiver's list at the given
1357 * zero-relative index.
1359 * @param index the index for the item
1361 * @exception IllegalArgumentException <ul>
1362 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1364 * @exception SWTException <ul>
1365 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1366 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1369 public void remove (int index) {
1371 list.remove (index);
1374 * Removes the items from the receiver's list which are
1375 * between the given zero-relative start and end
1376 * indices (inclusive).
1378 * @param start the start of the range
1379 * @param end the end of the range
1381 * @exception IllegalArgumentException <ul>
1382 * <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>
1384 * @exception SWTException <ul>
1385 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1386 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1389 public void remove (int start, int end) {
1391 list.remove (start, end);
1394 * Searches the receiver's list starting at the first item
1395 * until an item is found that is equal to the argument,
1396 * and removes that item from the list.
1398 * @param string the item to remove
1400 * @exception IllegalArgumentException <ul>
1401 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1402 * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
1404 * @exception SWTException <ul>
1405 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1406 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1409 public void remove (String string) {
1411 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1412 list.remove (string);
1415 * Removes all of the items from the receiver's list and clear the
1416 * contents of receiver's text field.
1418 * @exception SWTException <ul>
1419 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1420 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1423 public void removeAll () {
1425 text.setText (""); //$NON-NLS-1$
1429 * Removes the listener from the collection of listeners who will
1430 * be notified when the receiver's text is modified.
1432 * @param listener the listener which should no longer be notified
1434 * @exception IllegalArgumentException <ul>
1435 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1437 * @exception SWTException <ul>
1438 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1439 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1442 * @see ModifyListener
1443 * @see #addModifyListener
1445 public void removeModifyListener (ModifyListener listener) {
1447 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1448 removeListener(SWT.Modify, listener);
1451 * Removes the listener from the collection of listeners who will
1452 * be notified when the user changes the receiver's selection.
1454 * @param listener the listener which should no longer be notified
1456 * @exception IllegalArgumentException <ul>
1457 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1459 * @exception SWTException <ul>
1460 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1461 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1464 * @see SelectionListener
1465 * @see #addSelectionListener
1467 public void removeSelectionListener (SelectionListener listener) {
1469 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1470 removeListener(SWT.Selection, listener);
1471 removeListener(SWT.DefaultSelection,listener);
1474 * Removes the listener from the collection of listeners who will
1475 * be notified when the control is verified.
1477 * @param listener the listener which should no longer be notified
1479 * @exception IllegalArgumentException <ul>
1480 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1482 * @exception SWTException <ul>
1483 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1484 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1487 * @see VerifyListener
1488 * @see #addVerifyListener
1492 public void removeVerifyListener (VerifyListener listener) {
1494 if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1495 removeListener(SWT.Verify, listener);
1498 * Selects the item at the given zero-relative index in the receiver's
1499 * list. If the item at the index was already selected, it remains
1500 * selected. Indices that are out of range are ignored.
1502 * @param index the index of the item to select
1504 * @exception SWTException <ul>
1505 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1506 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1509 public void select (int index) {
1512 list.deselectAll ();
1513 text.setText (""); //$NON-NLS-1$
1516 if (0 <= index && index < list.getItemCount()) {
1517 if (index != getSelectionIndex()) {
1518 text.setText (list.getItem (index));
1519 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1520 list.select (index);
1521 list.showSelection ();
1527 * Set the horizontal alignment of the CCombo.
1528 * Use the values LEFT, CENTER and RIGHT to align image and text within the available space.
1530 * @param align the alignment style of LEFT, RIGHT or CENTER
1532 * @exception SWTException <ul>
1533 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1534 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1535 * <li>ERROR_INVALID_ARGUMENT - if the value of align is not one of SWT.LEFT, SWT.RIGHT or SWT.CENTER</li>
1539 public void setAlignment(int align) {
1541 int styleWithoutAlign = getStyle() & ~(SWT.LEFT | SWT.CENTER | SWT.RIGHT);
1542 createText(styleWithoutAlign | align);
1545 public void setBackground (Color color) {
1546 super.setBackground(color);
1548 if (text != null) text.setBackground(color);
1549 if (list != null) list.setBackground(color);
1550 if (arrow != null) arrow.setBackground(color);
1553 * Sets the editable state.
1555 * @param editable the new editable state
1557 * @exception SWTException <ul>
1558 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1559 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1564 public void setEditable (boolean editable) {
1566 text.setEditable(editable);
1569 public void setEnabled (boolean enabled) {
1570 super.setEnabled(enabled);
1571 if (popup != null) popup.setVisible (false);
1572 if (text != null) text.setEnabled(enabled);
1573 if (arrow != null) arrow.setEnabled(enabled);
1576 public boolean setFocus () {
1578 if (!isEnabled () || !getVisible ()) return false;
1579 if (isFocusControl ()) return true;
1580 return text.setFocus ();
1583 public void setFont (Font font) {
1584 super.setFont (font);
1586 text.setFont (font);
1587 list.setFont (font);
1588 internalLayout (true);
1591 public void setForeground (Color color) {
1592 super.setForeground(color);
1594 if (text != null) text.setForeground(color);
1595 if (list != null) list.setForeground(color);
1596 if (arrow != null) arrow.setForeground(color);
1599 * Sets the text of the item in the receiver's list at the given
1600 * zero-relative index to the string argument. This is equivalent
1601 * to <code>remove</code>'ing the old item at the index, and then
1602 * <code>add</code>'ing the new item at that index.
1604 * @param index the index for the item
1605 * @param string the new text for the item
1607 * @exception IllegalArgumentException <ul>
1608 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1609 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1611 * @exception SWTException <ul>
1612 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1613 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1616 public void setItem (int index, String string) {
1618 list.setItem (index, string);
1621 * Sets the receiver's list to be the given array of items.
1623 * @param items the array of items
1625 * @exception IllegalArgumentException <ul>
1626 * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1627 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1629 * @exception SWTException <ul>
1630 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1631 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1634 public void setItems (String [] items) {
1636 list.setItems (items);
1637 if (!text.getEditable ()) text.setText (""); //$NON-NLS-1$
1640 * Sets the layout which is associated with the receiver to be
1641 * the argument which may be null.
1643 * Note: No Layout can be set on this Control because it already
1644 * manages the size and position of its children.
1647 * @param layout the receiver's new layout or null
1649 * @exception SWTException <ul>
1650 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1651 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1655 public void setLayout (Layout layout) {
1660 * Marks the receiver's list as visible if the argument is <code>true</code>,
1661 * and marks it invisible otherwise.
1663 * If one of the receiver's ancestors is not visible or some
1664 * other condition makes the receiver not visible, marking
1665 * it visible may not actually cause it to be displayed.
1668 * @param visible the new visibility state
1670 * @exception SWTException <ul>
1671 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1672 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1677 public void setListVisible (boolean visible) {
1682 public void setMenu(Menu menu) {
1686 * Sets the selection in the receiver's text field to the
1687 * range specified by the argument whose x coordinate is the
1688 * start of the selection and whose y coordinate is the end
1691 * @param selection a point representing the new selection start and end
1693 * @exception IllegalArgumentException <ul>
1694 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1696 * @exception SWTException <ul>
1697 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1698 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1701 public void setSelection (Point selection) {
1703 if (selection == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1704 text.setSelection (selection.x, selection.y);
1708 * Sets the contents of the receiver's text field to the
1711 * Note: The text field in a <code>Combo</code> is typically
1712 * only capable of displaying a single line of text. Thus,
1713 * setting the text to a string containing line breaks or
1714 * other special characters will probably cause it to
1715 * display incorrectly.
1717 * Also note, if control characters like '\n', '\t' etc. are used
1718 * in the string, then the behavior is platform dependent.
1721 * @param string the new text
1723 * @exception IllegalArgumentException <ul>
1724 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1726 * @exception SWTException <ul>
1727 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1728 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1731 public void setText (String string) {
1733 if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
1734 int index = list.indexOf (string);
1736 list.deselectAll ();
1737 text.setText (string);
1740 text.setText (string);
1741 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1742 list.setSelection (index);
1743 list.showSelection ();
1746 * Sets the maximum number of characters that the receiver's
1747 * text field is capable of holding to be the argument.
1749 * @param limit new text limit
1751 * @exception IllegalArgumentException <ul>
1752 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
1754 * @exception SWTException <ul>
1755 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1756 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1759 public void setTextLimit (int limit) {
1761 text.setTextLimit (limit);
1765 public void setToolTipText (String string) {
1767 super.setToolTipText(string);
1768 arrow.setToolTipText (string);
1769 text.setToolTipText (string);
1773 public void setVisible (boolean visible) {
1774 super.setVisible(visible);
1776 * At this point the widget may have been disposed in a FocusOut event.
1777 * If so then do not continue.
1779 if (isDisposed ()) return;
1781 if (popup == null || popup.isDisposed ()) return;
1782 if (!visible) popup.setVisible (false);
1785 * Sets the number of items that are visible in the drop
1786 * down portion of the receiver's list.
1788 * @param count the new number of items to be visible
1790 * @exception SWTException <ul>
1791 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1792 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1797 public void setVisibleItemCount (int count) {
1799 if (count < 0) return;
1800 visibleItemCount = count;
1802 String stripMnemonic (String string) {
1804 int length = string.length ();
1806 while ((index < length) && (string.charAt (index) != '&')) index++;
1807 if (++index >= length) return string;
1808 if (string.charAt (index) != '&') {
1809 return string.substring(0, index-1) + string.substring(index, length);
1812 } while (index < length);
1815 void textEvent (Event event) {
1816 switch (event.type) {
1818 handleFocus (SWT.FocusIn);
1821 case SWT.DefaultSelection: {
1823 Event e = new Event ();
1824 e.time = event.time;
1825 e.stateMask = event.stateMask;
1826 notifyListeners (SWT.DefaultSelection, e);
1829 case SWT.DragDetect:
1830 case SWT.MouseDoubleClick:
1832 case SWT.MouseEnter:
1834 case SWT.MouseHover: {
1835 Point pt = getDisplay ().map (text, this, event.x, event.y);
1836 event.x = pt.x; event.y = pt.y;
1837 notifyListeners (event.type, event);
1838 event.type = SWT.None;
1842 Event keyEvent = new Event ();
1843 keyEvent.time = event.time;
1844 keyEvent.character = event.character;
1845 keyEvent.keyCode = event.keyCode;
1846 keyEvent.keyLocation = event.keyLocation;
1847 keyEvent.stateMask = event.stateMask;
1848 notifyListeners (SWT.KeyDown, keyEvent);
1849 if (isDisposed ()) break;
1850 event.doit = keyEvent.doit;
1851 if (!event.doit) break;
1852 if (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN) {
1854 if ((event.stateMask & SWT.ALT) != 0) {
1855 boolean dropped = isDropped ();
1856 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1857 if (!dropped) setFocus ();
1858 dropDown (!dropped);
1862 int oldIndex = getSelectionIndex ();
1863 if (event.keyCode == SWT.ARROW_UP) {
1864 select (Math.max (oldIndex - 1, 0));
1866 select (Math.min (oldIndex + 1, getItemCount () - 1));
1868 if (oldIndex != getSelectionIndex ()) {
1869 Event e = new Event();
1870 e.time = event.time;
1871 e.stateMask = event.stateMask;
1872 notifyListeners (SWT.Selection, e);
1874 if (isDisposed ()) break;
1877 // Further work : Need to add support for incremental search in
1878 // pop up list as characters typed in text widget
1882 Event e = new Event ();
1883 e.time = event.time;
1884 e.character = event.character;
1885 e.keyCode = event.keyCode;
1886 e.keyLocation = event.keyLocation;
1887 e.stateMask = event.stateMask;
1888 notifyListeners (SWT.KeyUp, e);
1889 event.doit = e.doit;
1892 case SWT.MenuDetect: {
1893 Event e = new Event ();
1894 e.time = event.time;
1895 e.detail = event.detail;
1898 if (event.detail == SWT.MENU_KEYBOARD) {
1899 Point pt = getDisplay().map(text, null, text.getCaretLocation());
1903 notifyListeners (SWT.MenuDetect, e);
1904 event.doit = e.doit;
1910 list.deselectAll ();
1911 Event e = new Event ();
1912 e.time = event.time;
1913 notifyListeners (SWT.Modify, e);
1916 case SWT.MouseDown: {
1917 Point pt = getDisplay ().map (text, this, event.x, event.y);
1918 Event mouseEvent = new Event ();
1919 mouseEvent.button = event.button;
1920 mouseEvent.count = event.count;
1921 mouseEvent.stateMask = event.stateMask;
1922 mouseEvent.time = event.time;
1923 mouseEvent.x = pt.x; mouseEvent.y = pt.y;
1924 notifyListeners (SWT.MouseDown, mouseEvent);
1925 if (isDisposed ()) break;
1926 event.doit = mouseEvent.doit;
1927 if (!event.doit) break;
1928 if (event.button != 1) return;
1929 if (text.getEditable ()) return;
1930 boolean dropped = isDropped ();
1931 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1932 if (!dropped) setFocus ();
1933 dropDown (!dropped);
1937 Point pt = getDisplay ().map (text, this, event.x, event.y);
1938 Event mouseEvent = new Event ();
1939 mouseEvent.button = event.button;
1940 mouseEvent.count = event.count;
1941 mouseEvent.stateMask = event.stateMask;
1942 mouseEvent.time = event.time;
1943 mouseEvent.x = pt.x; mouseEvent.y = pt.y;
1944 notifyListeners (SWT.MouseUp, mouseEvent);
1945 if (isDisposed ()) break;
1946 event.doit = mouseEvent.doit;
1947 if (!event.doit) break;
1948 if (event.button != 1) return;
1949 if (text.getEditable ()) return;
1950 if (text.getEditable() && text.isFocusControl()) text.selectAll ();
1953 case SWT.MouseWheel: {
1954 notifyListeners (SWT.MouseWheel, event);
1955 event.type = SWT.None;
1956 if (isDisposed ()) break;
1957 if (!event.doit) break;
1958 if (event.count != 0) {
1960 int oldIndex = getSelectionIndex ();
1961 if (event.count > 0) {
1962 select (Math.max (oldIndex - 1, 0));
1964 select (Math.min (oldIndex + 1, getItemCount () - 1));
1966 if (oldIndex != getSelectionIndex ()) {
1967 Event e = new Event();
1968 e.time = event.time;
1969 e.stateMask = event.stateMask;
1970 notifyListeners (SWT.Selection, e);
1972 if (isDisposed ()) break;
1976 case SWT.Traverse: {
1977 switch (event.detail) {
1978 case SWT.TRAVERSE_ARROW_PREVIOUS:
1979 case SWT.TRAVERSE_ARROW_NEXT:
1980 // The enter causes default selection and
1981 // the arrow keys are used to manipulate the list contents so
1982 // do not use them for traversal.
1985 case SWT.TRAVERSE_TAB_PREVIOUS:
1986 event.doit = traverse(SWT.TRAVERSE_TAB_PREVIOUS);
1987 event.detail = SWT.TRAVERSE_NONE;
1990 Event e = new Event ();
1991 e.time = event.time;
1992 e.detail = event.detail;
1993 e.doit = event.doit;
1994 e.character = event.character;
1995 e.keyCode = event.keyCode;
1996 e.keyLocation = event.keyLocation;
1997 notifyListeners (SWT.Traverse, e);
1998 event.doit = e.doit;
1999 event.detail = e.detail;
2003 Event e = new Event ();
2004 e.text = event.text;
2005 e.start = event.start;
2007 e.character = event.character;
2008 e.keyCode = event.keyCode;
2009 e.keyLocation = event.keyLocation;
2010 e.stateMask = event.stateMask;
2011 notifyListeners (SWT.Verify, e);
2012 event.text = e.text;
2013 event.doit = e.doit;
2019 public boolean traverse(int event){
2021 * When the traverse event is sent to the CCombo, it will create a list of
2022 * controls to tab to next. Since the CCombo is a composite, the next control is
2023 * the Text field which is a child of the CCombo. It will set focus to the text
2024 * field which really is itself. So, call the traverse next events directly on the text.
2026 if (event == SWT.TRAVERSE_ARROW_NEXT || event == SWT.TRAVERSE_TAB_NEXT) {
2027 return text.traverse(event);
2029 return super.traverse(event);