package org.eclipse.swt.widgets; /* * (c) Copyright IBM Corp. 2000, 2001. * All Rights Reserved */ import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.gtk.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; /** * Instances of this class are controls that allow the user * to choose an item from a list of items, or optionally * enter a new value by typing it into an editable text * field. Often, Combos are used in the same place * where a single selection List widget could * be used but space is limited. A Combo takes * less space than a List widget and shows * similar information. *

* Note: Since Combos can contain both a list * and an editable text field, it is possible to confuse methods * which access one versus the other (compare for example, * clearSelection() and deselectAll()). * The API documentation is careful to indicate either "the * receiver's list" or the "the receiver's text field" to * distinguish between the two cases. *

* Note that although this class is a subclass of Composite, * it does not make sense to add children to it, or set a layout on it. *

*
*
Styles:
*
DROP_DOWN, READ_ONLY, SIMPLE
*
Events:
*
DefaultSelection, Modify, Selection
*
*

* Note: Only one of the styles DROP_DOWN and SIMPLE * may be specified. *

* IMPORTANT: This class is not intended to be subclassed. *

* * @see List */ public class Combo extends Composite { int entryHandle, listHandle; int glist; int textLimit = LIMIT; public final static int LIMIT; /* * These values can be different on different platforms. * Therefore they are not initialized in the declaration * to stop the compiler from inlining. */ static { LIMIT = 0xFFFF; } /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * for all SWT widget classes should include a comment which * describes the style constants which are applicable to the class. *

* * @param parent a composite control which will be the parent of the new instance (cannot be null) * @param style the style of control to construct * * @exception IllegalArgumentException * @exception SWTException * * @see SWT * @see Widget#checkSubclass * @see Widget#getStyle */ public Combo (Composite parent, int style) { super (parent, checkStyle (style)); } /** * Adds the argument to the end of the receiver's list. * * @param string the new item * * @exception IllegalArgumentException * @exception SWTException * @exception SWTError * * @see #add(String,int) */ public void add (String string) { checkWidget(); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); String [] items = getItems (); String [] newItems = new String [items.length + 1]; System.arraycopy (items, 0, newItems, 0, items.length); newItems [items.length] = string; setItems (newItems); } /** * Adds the argument to the receiver's list at the given * zero-relative index. *

* Note: To add an item at the end of the list, use the * result of calling getItemCount() as the * index or use add(String). *

* * @param string the new item * @param index the index for the item * * @exception IllegalArgumentException * @exception SWTException * @exception SWTError * * @see #add(String) */ public void add (String string, int index) { checkWidget(); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); if (!(0 <= index && index <= getItemCount ())) { error (SWT.ERROR_ITEM_NOT_ADDED); } String [] items = getItems (); String [] newItems = new String [items.length + 1]; System.arraycopy (items, 0, newItems, 0, items.length); newItems [index] = string; setItems (newItems); } /** * Adds the listener to the collection of listeners who will * be notified when the receiver's text is modified, by sending * it one of the messages defined in the ModifyListener * interface. * * @param listener the listener which should be notified * * @exception IllegalArgumentException * @exception SWTException * * @see ModifyListener * @see #removeModifyListener */ public void addModifyListener (ModifyListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Modify, typedListener); } /** * Adds the listener to the collection of listeners who will * be notified when the receiver's selection changes, by sending * it one of the messages defined in the SelectionListener * interface. *

* widgetSelected is called when the combo's list selection changes. * widgetDefaultSelected is typically called when ENTER is pressed the combo's text area. *

* * @param listener the listener which should be notified * * @exception IllegalArgumentException * @exception SWTException * * @see SelectionListener * @see #removeSelectionListener * @see SelectionEvent */ public void addSelectionListener(SelectionListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Selection,typedListener); addListener (SWT.DefaultSelection,typedListener); } static int checkStyle (int style) { /* * Feature in Windows. It is not possible to create * a combo box that has a border using Windows style * bits. All combo boxes draw their own border and * do not use the standard Windows border styles. * Therefore, no matter what style bits are specified, * clear the BORDER bits so that the SWT style will * match the Windows widget. * * The Windows behavior is currently implemented on * all platforms. */ style &= ~SWT.BORDER; /* * Even though it is legal to create this widget * with scroll bars, they serve no useful purpose * because they do not automatically scroll the * widget's client area. The fix is to clear * the SWT style. */ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL); style = checkBits (style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0); if ((style & SWT.SIMPLE) != 0) return style & ~SWT.READ_ONLY; return style; } /** * Sets the selection in the receiver's text field to an empty * selection starting just before the first character. If the * text field is editable, this has the effect of placing the * i-beam at the start of the text. *

* Note: To clear the selected items in the receiver's list, * use deselectAll(). *

* * @exception SWTException * * @see #deselectAll */ public void clearSelection () { checkWidget(); /*int position = OS.gtk_editable_get_position (entryHandle); OS.gtk_editable_set_position (entryHandle, position);*/ } void createHandle (int index) { state |= HANDLE; fixedHandle = OS.gtk_fixed_new (); if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES); OS.gtk_fixed_set_has_window (fixedHandle, true); handle = OS.gtk_combo_new (); if (handle == 0) error (SWT.ERROR_NO_HANDLES); GtkCombo combo = new GtkCombo (); OS.memmove (combo, handle); entryHandle = combo.entry; listHandle = combo.list; boolean editable = (style & SWT.READ_ONLY) == 0; OS.gtk_entry_set_editable (entryHandle, editable); int parentHandle = parent.parentingHandle (); OS.gtk_container_add (parentHandle, fixedHandle); OS.gtk_container_add (fixedHandle, handle); OS.gtk_widget_show (fixedHandle); OS.gtk_widget_show (handle); } GdkColor defaultBackground () { Display display = getDisplay (); return display.COLOR_TEXT_BACKGROUND; } GdkColor defaultForeground () { Display display = getDisplay (); return display.COLOR_TEXT_FOREGROUND; } void deregister () { super.deregister (); WidgetTable.remove (entryHandle); WidgetTable.remove (listHandle); } int fontHandle () { if (entryHandle != 0) return entryHandle; return super.fontHandle (); } void hookEvents () { // TO DO - expose, enter/exit, focus in/out super.hookEvents (); // TO DO - fix multiple selection events for one user action signal_connect (listHandle, "select_child", SWT.Selection, 3); signal_connect_after (entryHandle, "changed", SWT.Modify, 2); signal_connect (entryHandle, "activate", SWT.DefaultSelection, 2); int mask = OS.GDK_POINTER_MOTION_MASK | OS.GDK_BUTTON_PRESS_MASK | OS.GDK_BUTTON_RELEASE_MASK | OS.GDK_KEY_PRESS_MASK | OS.GDK_KEY_RELEASE_MASK; //FIXME - missing button handle int [] handles = new int [] {entryHandle, listHandle, /*combo.button*/}; for (int i=0; i *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • * */ public void deselect (int index) { checkWidget(); setItems (getItems ()); } /** * Deselects all selected items in the receiver's list. *

    * Note: To clear the selection in the receiver's text field, * use clearSelection(). *

    * * @exception SWTException * * @see #clearSelection */ public void deselectAll () { checkWidget(); setItems (getItems ()); } GdkColor getBackgroundColor () { int fontHandle = fontHandle (); GtkStyle style = new GtkStyle (); OS.memmove(style, OS.gtk_widget_get_style (fontHandle)); GdkColor color = new GdkColor (); color.pixel = style.base0_pixel; color.red = style.base0_red; color.green = style.base0_green; color.blue = style.base0_blue; return color; } GdkColor getForegroundColor () { int fontHandle = fontHandle (); GtkStyle style = new GtkStyle (); OS.memmove(style, OS.gtk_widget_get_style (fontHandle)); GdkColor color = new GdkColor (); color.pixel = style.text0_pixel; color.red = style.text0_red; color.green = style.text0_green; color.blue = style.text0_blue; return color; } /** * Returns the item at the given, zero-relative index in the * receiver's list. Throws an exception if the index is out * of range. * * @param index the index of the item to return * @return the item at the given index * * @exception IllegalArgumentException * @exception SWTException * @exception SWTError */ public String getItem (int index) { checkWidget(); String [] items = getItems (); if (!(0 <= index && index < items.length)) { error (SWT.ERROR_CANNOT_GET_ITEM); } return items [index]; } /** * Returns the number of items contained in the receiver's list. * * @return the number of items * * @exception SWTException * @exception SWTError */ public int getItemCount () { checkWidget(); if (glist == 0) return 0; return OS.g_list_length (glist); } /** * Returns the height of the area which would be used to * display one of the items in the receiver's list. * * @return the height of one item * * @exception SWTException * @exception SWTError */ public int getItemHeight () { checkWidget(); /* FIXME */ return 0; } /** * Returns an array of Strings which are the items * in the receiver's list. *

    * Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. *

    * * @return the items in the receiver's list * * @exception SWTException * @exception SWTError */ public String [] getItems () { checkWidget(); if (glist == 0) return new String [0]; int count = OS.g_list_length (glist); String [] items = new String [count]; for (int i=0; iPoint whose x coordinate is the start * of the selection in the receiver's text field, and whose y * coordinate is the end of the selection. The returned values * are zero-relative. An "empty" selection as indicated by * the the x and y coordinates having the same value. * * @return a point representing the selection start and end * * @exception SWTException */ public Point getSelection () { checkWidget (); int [] start = new int [1]; int [] end = new int [1]; OS.gtk_editable_get_selection_bounds (entryHandle, start, end); return new Point(start [0], end [0]); } /** * Returns the zero-relative index of the item which is currently * selected in the receiver's list, or -1 if no item is selected. * * @return the index of the selected item * * @exception SWTException */ public int getSelectionIndex () { checkWidget(); //NOT RIGHT FOR EDITABLE return indexOf (getText ()); } /** * Returns a string containing a copy of the contents of the * receiver's text field. * * @return the receiver's text * * @exception SWTException */ public String getText () { checkWidget(); /* * The GTK documentation explicitly states * that this address should not be freed. */ int address = OS.gtk_entry_get_text (entryHandle); int length = OS.strlen (address); byte [] buffer1 = new byte [length]; OS.memmove (buffer1, address, length); char [] buffer2 = Converter.mbcsToWcs (null, buffer1); return new String (buffer2, 0, buffer2.length); } String getText (int start, int stop) { /* * NOTE: The current implementation uses substring () * which can reference a potentially large character * array. */ return getText ().substring (start, stop - 1); } /** * Returns the height of the receivers's text field. * * @return the text height * * @exception SWTException * @exception SWTError */ public int getTextHeight () { checkWidget(); //FIXME return 20; } /** * Returns the maximum number of characters that the receiver's * text field is capable of holding. If this has not been changed * by setTextLimit(), it will be the constant * Combo.LIMIT. * * @return the text limit * * @exception SWTException */ public int getTextLimit () { checkWidget(); return textLimit; } /** * Searches the receiver's list starting at the first item * (index 0) until an item is found that is equal to the * argument, and returns the index of that item. If no item * is found, returns -1. * * @param string the search item * @return the index of the item * * @exception IllegalArgumentException * @exception SWTException */ public int indexOf (String string) { checkWidget(); return indexOf (string, 0); } /** * Searches the receiver's list starting at the given, * zero-relative index until an item is found that is equal * to the argument, and returns the index of that item. If * no item is found or the starting index is out of range, * returns -1. * * @param string the search item * @return the index of the item * * @exception IllegalArgumentException * @exception SWTException */ public int indexOf (String string, int start) { checkWidget(); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); String [] items = getItems (); for (int i=start; i *
  • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception SWTError
      *
    • ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure
    • *
    */ public void remove (int index) { checkWidget(); if (!(0 <= index && index < getItemCount ())) { error (SWT.ERROR_ITEM_NOT_REMOVED); } String [] oldItems = getItems (); String [] newItems = new String [oldItems.length - 1]; System.arraycopy (oldItems, 0, newItems, 0, index); System.arraycopy (oldItems, index + 1, newItems, index, oldItems.length - index - 1); setItems (newItems); } /** * Removes the items from the receiver's list which are * between the given zero-relative start and end * indices (inclusive). * * @param start the start of the range * @param end the end of the range * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception SWTError
      *
    • ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure
    • *
    */ public void remove (int start, int end) { checkWidget(); if (!(0 <= start && start <= end && end < getItemCount ())) { error (SWT.ERROR_ITEM_NOT_REMOVED); } String [] oldItems = getItems (); String [] newItems = new String [oldItems.length - (end - start + 1)]; System.arraycopy (oldItems, 0, newItems, 0, start); System.arraycopy (oldItems, end + 1, newItems, start, oldItems.length - end - 1); setItems (newItems); } /** * Searches the receiver's list starting at the first item * until an item is found that is equal to the argument, * and removes that item from the list. * * @param string the item to remove * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the string is null
    • *
    • ERROR_INVALID_ARGUMENT - if the string is not found in the list
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception SWTError
      *
    • ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure
    • *
    */ public void remove (String string) { checkWidget(); int index = indexOf (string, 0); if (index != -1) remove (index); } /** * Removes all of the items from the receiver's list. *

    * @exception SWTException

      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void removeAll () { checkWidget(); setItems (new String [0]); } /** * Removes the listener from the collection of listeners who will * be notified when the receiver's text is modified. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see ModifyListener * @see #addModifyListener */ public void removeModifyListener (ModifyListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook (SWT.Modify, listener); } /** * Removes the listener from the collection of listeners who will * be notified when the receiver's selection changes. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see SelectionListener * @see #addSelectionListener */ public void removeSelectionListener (SelectionListener listener) { checkWidget(); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook (SWT.Selection, listener); eventTable.unhook (SWT.DefaultSelection,listener); } /** * Selects the item at the given zero-relative index in the receiver's * list. If the item at the index was already selected, it remains * selected. Indices that are out of range are ignored. * * @param index the index of the item to select * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void select (int index) { checkWidget(); String [] items = getItems (); if (index >= items.length) return; String selectedText = items [index]; OS.gtk_signal_handler_block_by_data (entryHandle, SWT.Modify); OS.gtk_signal_handler_block_by_data (listHandle, SWT.Selection); OS.gtk_list_select_item (listHandle, index); OS.gtk_entry_set_text (entryHandle, Converter.wcsToMbcs (null, selectedText, true)); OS.gtk_signal_handler_unblock_by_data (entryHandle, SWT.Modify); OS.gtk_signal_handler_unblock_by_data (listHandle, SWT.Selection); } void setBackgroundColor (GdkColor color) { super.setBackgroundColor (color); if (entryHandle != 0) OS.gtk_widget_modify_base (entryHandle, 0, color); if (listHandle != 0) OS.gtk_widget_modify_base (listHandle, 0, color); } boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) { checkWidget(); int newHeight = (resize && (style & SWT.DROP_DOWN) != 0) ? getTextHeight() : height; return super.setBounds (x, y, width, newHeight, move, resize); } void setFontDescription (int font) { super.setFontDescription (font); if (entryHandle != 0) OS.gtk_widget_modify_font (entryHandle, font); if (listHandle != 0) OS.gtk_widget_modify_font (listHandle, font); } void setForegroundColor (GdkColor color) { super.setForegroundColor (color); if (entryHandle != 0) OS.gtk_widget_modify_text (entryHandle, 0, color); if (listHandle != 0) OS.gtk_widget_modify_text (listHandle, 0, color); } /** * Sets the text of the item in the receiver's list at the given * zero-relative index to the string argument. This is equivalent * to remove'ing the old item at the index, and then * add'ing the new item at that index. * * @param index the index for the item * @param string the new text for the item * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception SWTError
      *
    • ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure
    • *
    • ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure
    • *
    */ public void setItem (int index, String string) { checkWidget(); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); if (!(0 <= index && index <= getItemCount ())) { error (SWT.ERROR_INVALID_ARGUMENT); } String [] items = getItems (); items [index] = string; setItems (items); } /** * Sets the receiver's list to be the given array of items. * * @param items the array of items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception SWTError
      *
    • ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure
    • *
    */ public void setItems (String [] items) { checkWidget(); if (items == null) error (SWT.ERROR_NULL_ARGUMENT); if (items.length == 0) { OS.gtk_list_clear_items (listHandle, 0, -1); //LEAK glist = 0; } else { int new_glist = 0; for (int i=0; i *
  • ERROR_NULL_ARGUMENT - if the point is null
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setSelection (Point selection) { checkWidget(); if (selection == null) error (SWT.ERROR_NULL_ARGUMENT); OS.gtk_editable_set_position (entryHandle, selection.x); OS.gtk_editable_select_region (entryHandle, selection.x, selection.y); } /** * Sets the contents of the receiver's text field to the * given string. *

    * Note: The text field in a Combo is typically * only capable of displaying a single line of text. Thus, * setting the text to a string containing line breaks or * other special characters will probably cause it to * display incorrectly. *

    * * @param text the new text * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the string is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setText (String string) { checkWidget(); if (string == null) error (SWT.ERROR_NULL_ARGUMENT); OS.gtk_editable_delete_text (entryHandle, 0, -1); int [] position = new int [1]; byte [] buffer = Converter.wcsToMbcs (null, string); OS.gtk_editable_insert_text (entryHandle, buffer, buffer.length, position); OS.gtk_editable_set_position (entryHandle, 0); } /** * Sets the maximum number of characters that the receiver's * text field is capable of holding to be the argument. * * @param limit new text limit * * @exception IllegalArgumentException
      *
    • ERROR_CANNOT_BE_ZERO - if the limit is zero
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setTextLimit (int limit) { checkWidget(); if (limit == 0) error (SWT.ERROR_CANNOT_BE_ZERO); this.textLimit = limit; OS.gtk_entry_set_max_length (entryHandle, limit); } }