0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.swt.widgets;
0011:
0012: import org.eclipse.swt.*;
0013: import org.eclipse.swt.events.*;
0014: import org.eclipse.swt.graphics.*;
0015: import org.eclipse.swt.internal.carbon.ControlEditTextSelectionRec;
0016: import org.eclipse.swt.internal.carbon.OS;
0017: import org.eclipse.swt.internal.carbon.CFRange;
0018: import org.eclipse.swt.internal.carbon.CGRect;
0019: import org.eclipse.swt.internal.carbon.Rect;
0020:
0021: /**
0022: * Instances of this class are controls that allow the user
0023: * to choose an item from a list of items, or optionally
0024: * enter a new value by typing it into an editable text
0025: * field. Often, <code>Combo</code>s are used in the same place
0026: * where a single selection <code>List</code> widget could
0027: * be used but space is limited. A <code>Combo</code> takes
0028: * less space than a <code>List</code> widget and shows
0029: * similar information.
0030: * <p>
0031: * Note: Since <code>Combo</code>s can contain both a list
0032: * and an editable text field, it is possible to confuse methods
0033: * which access one versus the other (compare for example,
0034: * <code>clearSelection()</code> and <code>deselectAll()</code>).
0035: * The API documentation is careful to indicate either "the
0036: * receiver's list" or the "the receiver's text field" to
0037: * distinguish between the two cases.
0038: * </p><p>
0039: * Note that although this class is a subclass of <code>Composite</code>,
0040: * it does not make sense to add children to it, or set a layout on it.
0041: * </p>
0042: * <dl>
0043: * <dt><b>Styles:</b></dt>
0044: * <dd>DROP_DOWN, READ_ONLY, SIMPLE</dd>
0045: * <dt><b>Events:</b></dt>
0046: * <dd>DefaultSelection, Modify, Selection, Verify</dd>
0047: * </dl>
0048: * <p>
0049: * Note: Only one of the styles DROP_DOWN and SIMPLE may be specified.
0050: * </p><p>
0051: * IMPORTANT: This class is <em>not</em> intended to be subclassed.
0052: * </p>
0053: *
0054: * @see List
0055: */
0056: public class Combo extends Composite {
0057: int menuHandle;
0058: int textLimit = LIMIT;
0059: String lastText = "";
0060: ControlEditTextSelectionRec selection;
0061:
0062: /**
0063: * the operating system limit for the number of characters
0064: * that the text field in an instance of this class can hold
0065: */
0066: public static final int LIMIT;
0067:
0068: /*
0069: * These values can be different on different platforms.
0070: * Therefore they are not initialized in the declaration
0071: * to stop the compiler from inlining.
0072: */
0073: static {
0074: LIMIT = 0x7FFFFFFF;
0075: }
0076:
0077: /**
0078: * Constructs a new instance of this class given its parent
0079: * and a style value describing its behavior and appearance.
0080: * <p>
0081: * The style value is either one of the style constants defined in
0082: * class <code>SWT</code> which is applicable to instances of this
0083: * class, or must be built by <em>bitwise OR</em>'ing together
0084: * (that is, using the <code>int</code> "|" operator) two or more
0085: * of those <code>SWT</code> style constants. The class description
0086: * lists the style constants that are applicable to the class.
0087: * Style bits are also inherited from superclasses.
0088: * </p>
0089: *
0090: * @param parent a composite control which will be the parent of the new instance (cannot be null)
0091: * @param style the style of control to construct
0092: *
0093: * @exception IllegalArgumentException <ul>
0094: * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
0095: * </ul>
0096: * @exception SWTException <ul>
0097: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
0098: * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
0099: * </ul>
0100: *
0101: * @see SWT#DROP_DOWN
0102: * @see SWT#READ_ONLY
0103: * @see SWT#SIMPLE
0104: * @see Widget#checkSubclass
0105: * @see Widget#getStyle
0106: */
0107: public Combo(Composite parent, int style) {
0108: super (parent, checkStyle(style));
0109: }
0110:
0111: /**
0112: * Adds the argument to the end of the receiver's list.
0113: *
0114: * @param string the new item
0115: *
0116: * @exception IllegalArgumentException <ul>
0117: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
0118: * </ul>
0119: * @exception SWTException <ul>
0120: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0121: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0122: * </ul>
0123: *
0124: * @see #add(String,int)
0125: */
0126: public void add(String string) {
0127: checkWidget();
0128: if (string == null)
0129: error(SWT.ERROR_NULL_ARGUMENT);
0130: char[] buffer = new char[string.length()];
0131: string.getChars(0, buffer.length, buffer, 0);
0132: int ptr = OS.CFStringCreateWithCharacters(
0133: OS.kCFAllocatorDefault, buffer, buffer.length);
0134: if (ptr == 0)
0135: error(SWT.ERROR_ITEM_NOT_ADDED);
0136: int result;
0137: if ((style & SWT.READ_ONLY) != 0) {
0138: result = OS.AppendMenuItemTextWithCFString(menuHandle, ptr,
0139: 0, 0, null);
0140: /*
0141: * Feature in the Macintosh. Setting text that starts with "-" makes the
0142: * menu item a separator. The fix is to clear the separator attribute.
0143: */
0144: if (string.startsWith("-")) {
0145: OS.ChangeMenuItemAttributes(menuHandle, (short) OS
0146: .CountMenuItems(menuHandle), 0,
0147: OS.kMenuItemAttrSeparator);
0148: }
0149: } else {
0150: result = OS.HIComboBoxAppendTextItem(handle, ptr, null);
0151: }
0152: OS.CFRelease(ptr);
0153: if (result != OS.noErr)
0154: error(SWT.ERROR_ITEM_NOT_ADDED);
0155: }
0156:
0157: /**
0158: * Adds the argument to the receiver's list at the given
0159: * zero-relative index.
0160: * <p>
0161: * Note: To add an item at the end of the list, use the
0162: * result of calling <code>getItemCount()</code> as the
0163: * index or use <code>add(String)</code>.
0164: * </p>
0165: *
0166: * @param string the new item
0167: * @param index the index for the item
0168: *
0169: * @exception IllegalArgumentException <ul>
0170: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
0171: * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
0172: * </ul>
0173: * @exception SWTException <ul>
0174: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0175: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0176: * </ul>
0177: *
0178: * @see #add(String)
0179: */
0180: public void add(String string, int index) {
0181: checkWidget();
0182: if (string == null)
0183: error(SWT.ERROR_NULL_ARGUMENT);
0184: int count = getItemCount();
0185: if (0 > index || index > count)
0186: error(SWT.ERROR_INVALID_RANGE);
0187: char[] buffer = new char[string.length()];
0188: string.getChars(0, buffer.length, buffer, 0);
0189: int ptr = OS.CFStringCreateWithCharacters(
0190: OS.kCFAllocatorDefault, buffer, buffer.length);
0191: if (ptr == 0)
0192: error(SWT.ERROR_ITEM_NOT_ADDED);
0193: int result;
0194: if ((style & SWT.READ_ONLY) != 0) {
0195: result = OS.InsertMenuItemTextWithCFString(menuHandle, ptr,
0196: (short) index, 0, 0);
0197: /*
0198: * Feature in the Macintosh. Setting text that starts with "-" makes the
0199: * menu item a separator. The fix is to clear the separator attribute.
0200: */
0201: if (string.startsWith("-")) {
0202: OS.ChangeMenuItemAttributes(menuHandle,
0203: (short) (index + 1), 0,
0204: OS.kMenuItemAttrSeparator);
0205: }
0206: } else {
0207: result = OS.HIComboBoxInsertTextItemAtIndex(handle, index,
0208: ptr);
0209: }
0210: OS.CFRelease(ptr);
0211: if (result != OS.noErr)
0212: error(SWT.ERROR_ITEM_NOT_ADDED);
0213: }
0214:
0215: /**
0216: * Adds the listener to the collection of listeners who will
0217: * be notified when the receiver's text is modified, by sending
0218: * it one of the messages defined in the <code>ModifyListener</code>
0219: * interface.
0220: *
0221: * @param listener the listener which should be notified
0222: *
0223: * @exception IllegalArgumentException <ul>
0224: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0225: * </ul>
0226: * @exception SWTException <ul>
0227: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0228: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0229: * </ul>
0230: *
0231: * @see ModifyListener
0232: * @see #removeModifyListener
0233: */
0234: public void addModifyListener(ModifyListener listener) {
0235: checkWidget();
0236: if (listener == null)
0237: error(SWT.ERROR_NULL_ARGUMENT);
0238: TypedListener typedListener = new TypedListener(listener);
0239: addListener(SWT.Modify, typedListener);
0240: }
0241:
0242: /**
0243: * Adds the listener to the collection of listeners who will
0244: * be notified when the user changes the receiver's selection, by sending
0245: * it one of the messages defined in the <code>SelectionListener</code>
0246: * interface.
0247: * <p>
0248: * <code>widgetSelected</code> is called when the user changes the combo's list selection.
0249: * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area.
0250: * </p>
0251: *
0252: * @param listener the listener which should be notified
0253: *
0254: * @exception IllegalArgumentException <ul>
0255: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0256: * </ul>
0257: * @exception SWTException <ul>
0258: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0259: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0260: * </ul>
0261: *
0262: * @see SelectionListener
0263: * @see #removeSelectionListener
0264: * @see SelectionEvent
0265: */
0266: public void addSelectionListener(SelectionListener listener) {
0267: checkWidget();
0268: if (listener == null)
0269: error(SWT.ERROR_NULL_ARGUMENT);
0270: TypedListener typedListener = new TypedListener(listener);
0271: addListener(SWT.Selection, typedListener);
0272: addListener(SWT.DefaultSelection, typedListener);
0273: }
0274:
0275: /**
0276: * Adds the listener to the collection of listeners who will
0277: * be notified when the receiver's text is verified, by sending
0278: * it one of the messages defined in the <code>VerifyListener</code>
0279: * interface.
0280: *
0281: * @param listener the listener which should be notified
0282: *
0283: * @exception IllegalArgumentException <ul>
0284: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
0285: * </ul>
0286: * @exception SWTException <ul>
0287: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0288: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0289: * </ul>
0290: *
0291: * @see VerifyListener
0292: * @see #removeVerifyListener
0293: *
0294: * @since 3.1
0295: */
0296: public void addVerifyListener(VerifyListener listener) {
0297: checkWidget();
0298: if (listener == null)
0299: error(SWT.ERROR_NULL_ARGUMENT);
0300: TypedListener typedListener = new TypedListener(listener);
0301: addListener(SWT.Verify, typedListener);
0302: }
0303:
0304: int callFocusEventHandler(int nextHandler, int theEvent) {
0305: short[] part = new short[1];
0306: if ((style & SWT.READ_ONLY) == 0) {
0307: OS.GetEventParameter(theEvent, OS.kEventParamControlPart,
0308: OS.typeControlPartCode, null, 2, null, part);
0309: if (part[0] == OS.kControlFocusNoPart) {
0310: selection = new ControlEditTextSelectionRec();
0311: OS.GetControlData(handle,
0312: (short) OS.kControlEntireControl,
0313: OS.kControlEditTextSelectionTag, 4, selection,
0314: null);
0315: }
0316: }
0317: int result = super .callFocusEventHandler(nextHandler, theEvent);
0318: if ((style & SWT.READ_ONLY) == 0) {
0319: if (part[0] != OS.kControlFocusNoPart && selection != null) {
0320: OS.SetControlData(handle,
0321: (short) OS.kControlEntireControl,
0322: OS.kControlEditTextSelectionTag, 4, selection);
0323: selection = null;
0324: }
0325: }
0326: return result;
0327: }
0328:
0329: static int checkStyle(int style) {
0330: /*
0331: * Feature in Windows. It is not possible to create
0332: * a combo box that has a border using Windows style
0333: * bits. All combo boxes draw their own border and
0334: * do not use the standard Windows border styles.
0335: * Therefore, no matter what style bits are specified,
0336: * clear the BORDER bits so that the SWT style will
0337: * match the Windows widget.
0338: *
0339: * The Windows behavior is currently implemented on
0340: * all platforms.
0341: */
0342: style &= ~SWT.BORDER;
0343:
0344: /*
0345: * Even though it is legal to create this widget
0346: * with scroll bars, they serve no useful purpose
0347: * because they do not automatically scroll the
0348: * widget's client area. The fix is to clear
0349: * the SWT style.
0350: */
0351: style &= ~(SWT.H_SCROLL | SWT.V_SCROLL);
0352: style = checkBits(style, SWT.DROP_DOWN, SWT.SIMPLE, 0, 0, 0, 0);
0353: if ((style & SWT.SIMPLE) != 0)
0354: return style & ~SWT.READ_ONLY;
0355: return style;
0356: }
0357:
0358: void checkSelection() {
0359: if ((style & SWT.READ_ONLY) != 0)
0360: return;
0361: String newText = getText();
0362: if (newText.equals(lastText))
0363: return;
0364: if (hooks(SWT.Verify) || filters(SWT.Verify)) {
0365: setText(lastText, false);
0366: newText = verifyText(newText, 0, lastText.length(), null);
0367: if (newText == null)
0368: return;
0369: setText(newText, false);
0370: } else {
0371: lastText = newText;
0372: }
0373: sendEvent(SWT.Modify);
0374: if (isDisposed())
0375: return;
0376: int index = indexOf(newText);
0377: if (index != -1)
0378: postEvent(SWT.Selection);
0379: }
0380:
0381: protected void checkSubclass() {
0382: if (!isValidSubclass())
0383: error(SWT.ERROR_INVALID_SUBCLASS);
0384: }
0385:
0386: /**
0387: * Sets the selection in the receiver's text field to an empty
0388: * selection starting just before the first character. If the
0389: * text field is editable, this has the effect of placing the
0390: * i-beam at the start of the text.
0391: * <p>
0392: * Note: To clear the selected items in the receiver's list,
0393: * use <code>deselectAll()</code>.
0394: * </p>
0395: *
0396: * @exception SWTException <ul>
0397: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0398: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0399: * </ul>
0400: *
0401: * @see #deselectAll
0402: */
0403: public void clearSelection() {
0404: checkWidget();
0405: if ((style & SWT.READ_ONLY) == 0) {
0406: Point selection = getSelection();
0407: selection.y = selection.x;
0408: setSelection(selection);
0409: }
0410: }
0411:
0412: public Point computeSize(int wHint, int hHint, boolean changed) {
0413: checkWidget();
0414: int width = 0, height = 0;
0415: int[] ptr = new int[1];
0416: if ((style & SWT.READ_ONLY) != 0) {
0417: int index = OS.GetControlValue(handle) - 1;
0418: OS.CopyMenuItemTextAsCFString(menuHandle,
0419: (short) (index + 1), ptr);
0420: } else {
0421: OS.GetControlData(handle,
0422: (short) OS.kHIComboBoxEditTextPart,
0423: OS.kControlEditTextCFStringTag, 4, ptr, null);
0424: }
0425: Point size = textExtent(ptr[0], 0);
0426: if (ptr[0] != 0)
0427: OS.CFRelease(ptr[0]);
0428: width = Math.max(width, size.x);
0429: height = Math.max(height, size.y);
0430: int count;
0431: if ((style & SWT.READ_ONLY) != 0) {
0432: count = OS.CountMenuItems(menuHandle);
0433: } else {
0434: count = OS.HIComboBoxGetItemCount(handle);
0435: }
0436: for (int i = 0; i < count; i++) {
0437: int result;
0438: if ((style & SWT.READ_ONLY) != 0) {
0439: result = OS.CopyMenuItemTextAsCFString(menuHandle,
0440: (short) (i + 1), ptr);
0441: } else {
0442: result = OS.HIComboBoxCopyTextItemAtIndex(handle, i,
0443: ptr);
0444: }
0445: if (result == OS.noErr) {
0446: size = textExtent(ptr[0], 0);
0447: width = Math.max(width, size.x);
0448: OS.CFRelease(ptr[0]);
0449: }
0450: }
0451: int[] metric = new int[1];
0452: if ((style & SWT.READ_ONLY) != 0) {
0453: OS.GetThemeMetric(OS.kThemeMetricDisclosureButtonWidth,
0454: metric);
0455: width += metric[0];
0456: //NOT DONE
0457: width += 13;
0458: } else {
0459: OS
0460: .GetThemeMetric(
0461: OS.kThemeMetricComboBoxLargeDisclosureWidth,
0462: metric);
0463: width += metric[0];
0464: }
0465: OS.GetThemeMetric(OS.kThemeMetricEditTextWhitespace, metric);
0466: width += metric[0] * 2;
0467: height += metric[0] * 2;
0468: Rect inset = getInset();
0469: width += inset.left + inset.right;
0470: height += inset.top + inset.bottom;
0471: if (wHint != SWT.DEFAULT)
0472: width = wHint;
0473: if (hHint != SWT.DEFAULT)
0474: height = hHint;
0475: return new Point(width, height);
0476: }
0477:
0478: /**
0479: * Copies the selected text.
0480: * <p>
0481: * The current selection is copied to the clipboard.
0482: * </p>
0483: *
0484: * @exception SWTException <ul>
0485: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0486: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0487: * </ul>
0488: *
0489: * @since 2.1
0490: */
0491: public void copy() {
0492: checkWidget();
0493: Point selection = getSelection();
0494: if (selection.x == selection.y)
0495: return;
0496: copyToClipboard(getText(selection.x, selection.y));
0497: }
0498:
0499: void createHandle() {
0500: if ((style & SWT.READ_ONLY) != 0) {
0501: int[] outControl = new int[1];
0502: int window = OS.GetControlOwner(parent.handle);
0503: /*
0504: * From ControlDefinitions.h:
0505: *
0506: * Passing in a menu ID of -12345 causes the popup not to try and get the menu from a
0507: * resource. Instead, you can build the menu and later stuff the MenuRef field in
0508: * the popup data information.
0509: */
0510: OS.CreatePopupButtonControl(window, null, 0,
0511: (short) -12345, false, (short) 0, (short) 0, 0,
0512: outControl);
0513: if (outControl[0] == 0)
0514: error(SWT.ERROR_NO_HANDLES);
0515: handle = outControl[0];
0516: int[] menuRef = new int[1];
0517: OS.CreateNewMenu((short) 0, 0, menuRef);
0518: if (menuRef[0] == 0)
0519: error(SWT.ERROR_NO_HANDLES);
0520: menuHandle = menuRef[0];
0521: OS.SetControlPopupMenuHandle(handle, menuHandle);
0522: OS.SetControl32BitMaximum(handle, 0x7FFF);
0523: } else {
0524: int[] outControl = new int[1];
0525: CGRect rect = new CGRect();
0526: int inAttributes = OS.kHIComboBoxAutoSizeListAttribute;
0527: /*
0528: * The following code is intentionally commented.
0529: * Auto completion does not allow the user to change
0530: * case of the text in a combo box.
0531: */
0532: // inAttributes |= OS.kHIComboBoxAutoCompletionAttribute;
0533: OS.HIComboBoxCreate(rect, 0, null, 0, inAttributes,
0534: outControl);
0535: if (outControl[0] == 0)
0536: error(SWT.ERROR_NO_HANDLES);
0537: handle = outControl[0];
0538: OS.SetControlData(handle,
0539: (short) OS.kHIComboBoxEditTextPart,
0540: OS.kTXNDrawCaretWhenInactiveTag, 4,
0541: new byte[] { 0 });
0542: OS.HIViewSetVisible(handle, true);
0543: }
0544: }
0545:
0546: /**
0547: * Cuts the selected text.
0548: * <p>
0549: * The current selection is first copied to the
0550: * clipboard and then deleted from the widget.
0551: * </p>
0552: *
0553: * @exception SWTException <ul>
0554: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0555: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0556: * </ul>
0557: *
0558: * @since 2.1
0559: */
0560: public void cut() {
0561: checkWidget();
0562: if ((style & SWT.READ_ONLY) != 0)
0563: return;
0564: Point selection = getSelection();
0565: if (selection.x == selection.y)
0566: return;
0567: int start = selection.x, end = selection.y;
0568: String text = getText();
0569: String leftText = text.substring(0, start);
0570: String rightText = text.substring(end, text.length());
0571: String oldText = text.substring(start, end);
0572: String newText = "";
0573: if (hooks(SWT.Verify) || filters(SWT.Verify)) {
0574: newText = verifyText(newText, start, end, null);
0575: if (newText == null)
0576: return;
0577: }
0578: char[] buffer = new char[oldText.length()];
0579: oldText.getChars(0, buffer.length, buffer, 0);
0580: copyToClipboard(buffer);
0581: setText(leftText + newText + rightText, false);
0582: start += newText.length();
0583: setSelection(new Point(start, start));
0584: sendEvent(SWT.Modify);
0585: }
0586:
0587: Color defaultBackground() {
0588: return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
0589: }
0590:
0591: Color defaultForeground() {
0592: return display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
0593: }
0594:
0595: /**
0596: * Deselects the item at the given zero-relative index in the receiver's
0597: * list. If the item at the index was already deselected, it remains
0598: * deselected. Indices that are out of range are ignored.
0599: *
0600: * @param index the index of the item to deselect
0601: *
0602: * @exception SWTException <ul>
0603: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0604: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0605: * </ul>
0606: */
0607: public void deselect(int index) {
0608: checkWidget();
0609: if (index == -1)
0610: return;
0611: if (index == getSelectionIndex()) {
0612: if ((style & SWT.READ_ONLY) != 0) {
0613: OS.SetControl32BitValue(handle, 0);
0614: sendEvent(SWT.Modify);
0615: } else {
0616: setText("");
0617: }
0618: }
0619: }
0620:
0621: /**
0622: * Deselects all selected items in the receiver's list.
0623: * <p>
0624: * Note: To clear the selection in the receiver's text field,
0625: * use <code>clearSelection()</code>.
0626: * </p>
0627: *
0628: * @exception SWTException <ul>
0629: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0630: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0631: * </ul>
0632: *
0633: * @see #clearSelection
0634: */
0635: public void deselectAll() {
0636: checkWidget();
0637: if ((style & SWT.READ_ONLY) != 0) {
0638: OS.SetControl32BitValue(handle, 0);
0639: sendEvent(SWT.Modify);
0640: } else {
0641: setText("");
0642: }
0643: }
0644:
0645: void destroyWidget() {
0646: /*
0647: * Bug in the Macintosh. Carbon segments fault if the combo box has
0648: * keyboard focus and it is disposed or its parent is disposed because
0649: * there is an outstanding timer that runs after the widget is dispoed.
0650: * The fix is to remove the combo box from its parent and dispose it when
0651: * the display is idle.
0652: *
0653: * NOTE: The problem does not happen when the window is disposed.
0654: */
0655: if ((getShell().state & DISPOSE_SENT) != 0) {
0656: super .destroyWidget();
0657: } else {
0658: releaseHandle();
0659: }
0660: }
0661:
0662: /**
0663: * Returns the item at the given, zero-relative index in the
0664: * receiver's list. Throws an exception if the index is out
0665: * of range.
0666: *
0667: * @param index the index of the item to return
0668: * @return the item at the given index
0669: *
0670: * @exception IllegalArgumentException <ul>
0671: * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
0672: * </ul>
0673: * @exception SWTException <ul>
0674: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0675: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0676: * </ul>
0677: */
0678: public String getItem(int index) {
0679: checkWidget();
0680: int count = getItemCount();
0681: if (0 > index || index >= count)
0682: error(SWT.ERROR_INVALID_RANGE);
0683: int[] ptr = new int[1];
0684: int result;
0685: if ((style & SWT.READ_ONLY) != 0) {
0686: result = OS.CopyMenuItemTextAsCFString(menuHandle,
0687: (short) (index + 1), ptr);
0688: } else {
0689: result = OS.HIComboBoxCopyTextItemAtIndex(handle, index,
0690: ptr);
0691: }
0692: if (result != OS.noErr)
0693: error(SWT.ERROR_CANNOT_GET_ITEM);
0694: int length = OS.CFStringGetLength(ptr[0]);
0695: char[] buffer = new char[length];
0696: CFRange range = new CFRange();
0697: range.length = length;
0698: OS.CFStringGetCharacters(ptr[0], range, buffer);
0699: OS.CFRelease(ptr[0]);
0700: return new String(buffer);
0701: }
0702:
0703: /**
0704: * Returns the number of items contained in the receiver's list.
0705: *
0706: * @return the number of items
0707: *
0708: * @exception SWTException <ul>
0709: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0710: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0711: * </ul>
0712: */
0713: public int getItemCount() {
0714: checkWidget();
0715: if ((style & SWT.READ_ONLY) != 0) {
0716: return OS.CountMenuItems(menuHandle);
0717: } else {
0718: return OS.HIComboBoxGetItemCount(handle);
0719: }
0720: }
0721:
0722: /**
0723: * Returns the height of the area which would be used to
0724: * display <em>one</em> of the items in the receiver's list.
0725: *
0726: * @return the height of one item
0727: *
0728: * @exception SWTException <ul>
0729: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0730: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0731: * </ul>
0732: */
0733: public int getItemHeight() {
0734: checkWidget();
0735: //TODO - not supported by the OS
0736: return 26;
0737: }
0738:
0739: /**
0740: * Returns a (possibly empty) array of <code>String</code>s which are
0741: * the items in the receiver's list.
0742: * <p>
0743: * Note: This is not the actual structure used by the receiver
0744: * to maintain its list of items, so modifying the array will
0745: * not affect the receiver.
0746: * </p>
0747: *
0748: * @return the items in the receiver's list
0749: *
0750: * @exception SWTException <ul>
0751: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0752: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0753: * </ul>
0754: */
0755: public String[] getItems() {
0756: checkWidget();
0757: int count = getItemCount();
0758: String[] result = new String[count];
0759: for (int i = 0; i < count; i++)
0760: result[i] = getItem(i);
0761: return result;
0762: }
0763:
0764: int getMininumHeight() {
0765: return getTextHeight();
0766: }
0767:
0768: /**
0769: * Returns the orientation of the receiver.
0770: *
0771: * @return the orientation style
0772: *
0773: * @exception SWTException <ul>
0774: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0775: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0776: * </ul>
0777: *
0778: * @since 2.1.2
0779: */
0780: public int getOrientation() {
0781: checkWidget();
0782: return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
0783: }
0784:
0785: /**
0786: * Returns a <code>Point</code> whose x coordinate is the
0787: * character position representing the start of the selection
0788: * in the receiver's text field, and whose y coordinate is the
0789: * character position representing the end of the selection.
0790: * An "empty" selection is indicated by the x and y coordinates
0791: * having the same value.
0792: * <p>
0793: * Indexing is zero based. The range of a selection is from
0794: * 0..N where N is the number of characters in the widget.
0795: * </p>
0796: *
0797: * @return a point representing the selection start and end
0798: *
0799: * @exception SWTException <ul>
0800: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0801: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0802: * </ul>
0803: */
0804: public Point getSelection() {
0805: checkWidget();
0806: if ((style & SWT.READ_ONLY) != 0) {
0807: return new Point(0, getCharCount());
0808: } else {
0809: ControlEditTextSelectionRec selection;
0810: if (this .selection != null) {
0811: selection = this .selection;
0812: } else {
0813: selection = new ControlEditTextSelectionRec();
0814: OS.GetControlData(handle,
0815: (short) OS.kHIComboBoxEditTextPart,
0816: OS.kControlEditTextSelectionTag, 4, selection,
0817: null);
0818: }
0819: return new Point(selection.selStart, selection.selEnd);
0820: }
0821: }
0822:
0823: /**
0824: * Returns the zero-relative index of the item which is currently
0825: * selected in the receiver's list, or -1 if no item is selected.
0826: *
0827: * @return the index of the selected item
0828: *
0829: * @exception SWTException <ul>
0830: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0831: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0832: * </ul>
0833: */
0834: public int getSelectionIndex() {
0835: checkWidget();
0836: if ((style & SWT.READ_ONLY) != 0) {
0837: return OS.GetControlValue(handle) - 1;
0838: } else {
0839: return indexOf(getText());
0840: }
0841: }
0842:
0843: /**
0844: * Returns a string containing a copy of the contents of the
0845: * receiver's text field, or an empty string if there are no
0846: * contents.
0847: *
0848: * @return the receiver's text
0849: *
0850: * @exception SWTException <ul>
0851: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0852: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0853: * </ul>
0854: */
0855: public String getText() {
0856: checkWidget();
0857: return new String(getText(0, -1));
0858: }
0859:
0860: char[] getText(int start, int end) {
0861: int result;
0862: int[] ptr = new int[1];
0863: if ((style & SWT.READ_ONLY) != 0) {
0864: int index = OS.GetControlValue(handle) - 1;
0865: result = OS.CopyMenuItemTextAsCFString(menuHandle,
0866: (short) (index + 1), ptr);
0867: } else {
0868: int[] actualSize = new int[1];
0869: result = OS.GetControlData(handle,
0870: (short) OS.kHIComboBoxEditTextPart,
0871: OS.kControlEditTextCFStringTag, 4, ptr, actualSize);
0872: }
0873: if (result != OS.noErr)
0874: return new char[0];
0875: CFRange range = new CFRange();
0876: range.location = start;
0877: if (end == -1) {
0878: int length = OS.CFStringGetLength(ptr[0]);
0879: range.length = length - start;
0880: } else {
0881: range.length = end - start;
0882: }
0883: char[] buffer = new char[range.length];
0884: OS.CFStringGetCharacters(ptr[0], range, buffer);
0885: OS.CFRelease(ptr[0]);
0886: return buffer;
0887: }
0888:
0889: /**
0890: * Returns the height of the receivers's text field.
0891: *
0892: * @return the text height
0893: *
0894: * @exception SWTException <ul>
0895: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0896: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0897: * </ul>
0898: */
0899: public int getTextHeight() {
0900: checkWidget();
0901: //TODO - not supported by the OS
0902: return 26;
0903: }
0904:
0905: /**
0906: * Returns the maximum number of characters that the receiver's
0907: * text field is capable of holding. If this has not been changed
0908: * by <code>setTextLimit()</code>, it will be the constant
0909: * <code>Combo.LIMIT</code>.
0910: *
0911: * @return the text limit
0912: *
0913: * @exception SWTException <ul>
0914: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0915: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0916: * </ul>
0917: *
0918: * @see #LIMIT
0919: */
0920: public int getTextLimit() {
0921: checkWidget();
0922: return textLimit;
0923: }
0924:
0925: /**
0926: * Gets the number of items that are visible in the drop
0927: * down portion of the receiver's list.
0928: * <p>
0929: * Note: This operation is a hint and is not supported on
0930: * platforms that do not have this concept.
0931: * </p>
0932: *
0933: * @return the number of items that are visible
0934: *
0935: * @exception SWTException <ul>
0936: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0937: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0938: * </ul>
0939: *
0940: * @since 3.0
0941: */
0942: public int getVisibleItemCount() {
0943: checkWidget();
0944: if ((style & SWT.READ_ONLY) != 0) {
0945: return getItemCount();
0946: } else {
0947: int[] buffer = new int[1];
0948: OS.GetControlData(handle, (short) OS.kControlEntireControl,
0949: OS.kHIComboBoxNumVisibleItemsTag, 4, buffer, null);
0950: return buffer[0];
0951: }
0952: }
0953:
0954: void hookEvents() {
0955: super .hookEvents();
0956: if ((style & SWT.READ_ONLY) != 0) {
0957: int commandProc = display.commandProc;
0958: int[] mask = new int[] { OS.kEventClassCommand,
0959: OS.kEventProcessCommand, };
0960: int menuTarget = OS.GetMenuEventTarget(menuHandle);
0961: OS.InstallEventHandler(menuTarget, commandProc,
0962: mask.length / 2, mask, handle, null);
0963: }
0964: }
0965:
0966: /**
0967: * Searches the receiver's list starting at the first item
0968: * (index 0) until an item is found that is equal to the
0969: * argument, and returns the index of that item. If no item
0970: * is found, returns -1.
0971: *
0972: * @param string the search item
0973: * @return the index of the item
0974: *
0975: * @exception IllegalArgumentException <ul>
0976: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
0977: * </ul>
0978: * @exception SWTException <ul>
0979: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
0980: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
0981: * </ul>
0982: */
0983: public int indexOf(String string) {
0984: return indexOf(string, 0);
0985: }
0986:
0987: /**
0988: * Searches the receiver's list starting at the given,
0989: * zero-relative index until an item is found that is equal
0990: * to the argument, and returns the index of that item. If
0991: * no item is found or the starting index is out of range,
0992: * returns -1.
0993: *
0994: * @param string the search item
0995: * @param start the zero-relative index at which to begin the search
0996: * @return the index of the item
0997: *
0998: * @exception IllegalArgumentException <ul>
0999: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1000: * </ul>
1001: * @exception SWTException <ul>
1002: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1003: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1004: * </ul>
1005: */
1006: public int indexOf(String string, int start) {
1007: checkWidget();
1008: if (string == null)
1009: error(SWT.ERROR_NULL_ARGUMENT);
1010: int count = getItemCount();
1011: if (!(0 <= start && start < count))
1012: return -1;
1013: for (int i = start; i < count; i++) {
1014: if (string.equals(getItem(i))) {
1015: return i;
1016: }
1017: }
1018: return -1;
1019: }
1020:
1021: int getCharCount() {
1022: // checkWidget ();
1023: int[] ptr = new int[1];
1024: int result;
1025: if ((style & SWT.READ_ONLY) != 0) {
1026: int index = OS.GetControlValue(handle) - 1;
1027: result = OS.CopyMenuItemTextAsCFString(menuHandle,
1028: (short) (index + 1), ptr);
1029: } else {
1030: int[] actualSize = new int[1];
1031: result = OS.GetControlData(handle,
1032: (short) OS.kHIComboBoxEditTextPart,
1033: OS.kControlEditTextCFStringTag, 4, ptr, actualSize);
1034: }
1035: if (result != OS.noErr)
1036: return 0;
1037: int length = OS.CFStringGetLength(ptr[0]);
1038: OS.CFRelease(ptr[0]);
1039: return length;
1040: }
1041:
1042: Rect getInset() {
1043: return display.comboInset;
1044: }
1045:
1046: int kEventControlActivate(int nextHandler, int theEvent,
1047: int userData) {
1048: int result = super .kEventControlActivate(nextHandler, theEvent,
1049: userData);
1050: if (result == OS.noErr)
1051: return result;
1052: /*
1053: * Feature in the Macintosh. When a combo box gets
1054: * kEventControlActivate, it starts the caret blinking.
1055: * Because there is no clipping on the Macintosh, the
1056: * caret may blink through a widget that is obscurred.
1057: * The fix is to avoid running the default handler.
1058: */
1059: return OS.noErr;
1060: }
1061:
1062: int kEventProcessCommand(int nextHandler, int theEvent, int userData) {
1063: int result = super .kEventProcessCommand(nextHandler, theEvent,
1064: userData);
1065: if (result == OS.noErr)
1066: return result;
1067: /*
1068: * It is possible (but unlikely), that application
1069: * code could have disposed the widget in the modify
1070: * event. If this happens, end the processing of the
1071: * Windows message by returning zero as the result of
1072: * the window proc.
1073: *
1074: * Note: this should be a send event, but selection is updated
1075: * right way.
1076: */
1077: postEvent(SWT.Modify);
1078: if (isDisposed())
1079: return OS.eventNotHandledErr;
1080: postEvent(SWT.Selection);
1081: return OS.eventNotHandledErr;
1082: }
1083:
1084: int kEventRawKeyPressed(int nextHandler, int theEvent, int userData) {
1085: /*
1086: * Feature in the Macintosh. The combo box widget consumes the
1087: * kEventRawKeyDown event when the up and down arrow keys are
1088: * pressed, causing kEventTextInputUnicodeForKeyEvent not
1089: * to be sent. The fix is to handle these keys in kEventRawKeyDown.
1090: *
1091: * NOTE: This was fixed in OS X 10.4.
1092: */
1093: if (OS.VERSION < 0x1040) {
1094: int[] keyCode = new int[1];
1095: OS.GetEventParameter(theEvent, OS.kEventParamKeyCode,
1096: OS.typeUInt32, null, keyCode.length * 4, null,
1097: keyCode);
1098: switch (keyCode[0]) {
1099: case 126: /* Up arrow */
1100: case 125: /* Down arrow */
1101: if (!sendKeyEvent(SWT.KeyDown, theEvent))
1102: return OS.noErr;
1103: break;
1104: }
1105: }
1106: return OS.eventNotHandledErr;
1107: }
1108:
1109: int kEventControlSetFocusPart(int nextHandler, int theEvent,
1110: int userData) {
1111: int result = super .kEventControlSetFocusPart(nextHandler,
1112: theEvent, userData);
1113: if (result == OS.noErr) {
1114: if ((style & SWT.READ_ONLY) == 0) {
1115: short[] part = new short[1];
1116: OS.GetEventParameter(theEvent,
1117: OS.kEventParamControlPart,
1118: OS.typeControlPartCode, null, 2, null, part);
1119: if (part[0] != OS.kControlFocusNoPart)
1120: display.focusCombo = this ;
1121: }
1122: }
1123: return result;
1124: }
1125:
1126: int kEventUnicodeKeyPressed(int nextHandler, int theEvent,
1127: int userData) {
1128: int result = super .kEventUnicodeKeyPressed(nextHandler,
1129: theEvent, userData);
1130: if (result == OS.noErr)
1131: return result;
1132: int[] keyboardEvent = new int[1];
1133: OS.GetEventParameter(theEvent,
1134: OS.kEventParamTextInputSendKeyboardEvent,
1135: OS.typeEventRef, null, keyboardEvent.length * 4, null,
1136: keyboardEvent);
1137: int[] keyCode = new int[1];
1138: OS.GetEventParameter(keyboardEvent[0], OS.kEventParamKeyCode,
1139: OS.typeUInt32, null, keyCode.length * 4, null, keyCode);
1140: switch (keyCode[0]) {
1141: case 76: /* KP Enter */
1142: case 36: { /* Return */
1143: postEvent(SWT.DefaultSelection);
1144: break;
1145: }
1146: }
1147: result = OS.CallNextEventHandler(nextHandler, theEvent);
1148: lastText = getText();
1149: return result;
1150: }
1151:
1152: /**
1153: * Pastes text from clipboard.
1154: * <p>
1155: * The selected text is deleted from the widget
1156: * and new text inserted from the clipboard.
1157: * </p>
1158: *
1159: * @exception SWTException <ul>
1160: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1161: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1162: * </ul>
1163: *
1164: * @since 2.1
1165: */
1166: public void paste() {
1167: checkWidget();
1168: if ((style & SWT.READ_ONLY) != 0)
1169: return;
1170: Point selection = getSelection();
1171: int start = selection.x, end = selection.y;
1172: String text = getText();
1173: String leftText = text.substring(0, start);
1174: String rightText = text.substring(end, text.length());
1175: String newText = getClipboardText();
1176: if (hooks(SWT.Verify) || filters(SWT.Verify)) {
1177: newText = verifyText(newText, start, end, null);
1178: if (newText == null)
1179: return;
1180: }
1181: if (textLimit != LIMIT) {
1182: int charCount = text.length();
1183: if (charCount - (end - start) + newText.length() > textLimit) {
1184: newText = newText.substring(0, textLimit - charCount
1185: + (end - start));
1186: }
1187: }
1188: setText(leftText + newText + rightText, false);
1189: start += newText.length();
1190: setSelection(new Point(start, start));
1191: sendEvent(SWT.Modify);
1192: }
1193:
1194: void releaseHandle() {
1195: /*
1196: * Bug in the Macintosh. Carbon segments fault if the combo box has
1197: * keyboard focus and it is disposed or its parent is disposed because
1198: * there is an outstanding timer that runs after the widget is dispoed.
1199: * The fix is to remove the combo box from its parent and dispose it when
1200: * the display is idle.
1201: *
1202: * NOTE: The problem does not happen when the window is disposed.
1203: */
1204: if ((getShell().state & DISPOSE_SENT) == 0) {
1205: display.addToDisposeWindow(handle);
1206: }
1207: super .releaseHandle();
1208: }
1209:
1210: void releaseWidget() {
1211: super .releaseWidget();
1212: if (display.focusCombo == this )
1213: display.focusCombo = null;
1214: if (menuHandle != 0) {
1215: OS.DisposeMenu(menuHandle);
1216: }
1217: menuHandle = 0;
1218: }
1219:
1220: /**
1221: * Removes the item from the receiver's list at the given
1222: * zero-relative index.
1223: *
1224: * @param index the index for the item
1225: *
1226: * @exception IllegalArgumentException <ul>
1227: * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1228: * </ul>
1229: * @exception SWTException <ul>
1230: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1231: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1232: * </ul>
1233: */
1234: public void remove(int index) {
1235: checkWidget();
1236: if (index == -1)
1237: error(SWT.ERROR_INVALID_RANGE);
1238: int count = getItemCount();
1239: if (0 > index || index >= count)
1240: error(SWT.ERROR_INVALID_RANGE);
1241: if ((style & SWT.READ_ONLY) != 0) {
1242: OS.DeleteMenuItems(menuHandle, (short) (index + 1), 1);
1243: if (index == OS.GetControlValue(handle) - 1) {
1244: OS.SetControl32BitValue(handle, 0);
1245: }
1246: } else {
1247: OS.HIComboBoxRemoveItemAtIndex(handle, index);
1248: }
1249: }
1250:
1251: /**
1252: * Removes the items from the receiver's list which are
1253: * between the given zero-relative start and end
1254: * indices (inclusive).
1255: *
1256: * @param start the start of the range
1257: * @param end the end of the range
1258: *
1259: * @exception IllegalArgumentException <ul>
1260: * <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>
1261: * </ul>
1262: * @exception SWTException <ul>
1263: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1264: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1265: * </ul>
1266: */
1267: public void remove(int start, int end) {
1268: checkWidget();
1269: if (start > end)
1270: return;
1271: int count = getItemCount();
1272: if (!(0 <= start && start <= end && end < count)) {
1273: error(SWT.ERROR_INVALID_RANGE);
1274: }
1275: int newEnd = Math.min(end, count - 1);
1276: if ((style & SWT.READ_ONLY) != 0) {
1277: OS.DeleteMenuItems(menuHandle, (short) (start + 1), newEnd
1278: - start + 1);
1279: int index = OS.GetControlValue(handle) - 1;
1280: if (start <= index && index <= end) {
1281: OS.SetControl32BitValue(handle, 0);
1282: }
1283: } else {
1284: for (int i = newEnd; i >= start; i--) {
1285: OS.HIComboBoxRemoveItemAtIndex(handle, i);
1286: }
1287: }
1288: }
1289:
1290: /**
1291: * Searches the receiver's list starting at the first item
1292: * until an item is found that is equal to the argument,
1293: * and removes that item from the list.
1294: *
1295: * @param string the item to remove
1296: *
1297: * @exception IllegalArgumentException <ul>
1298: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1299: * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
1300: * </ul>
1301: * @exception SWTException <ul>
1302: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1303: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1304: * </ul>
1305: */
1306: public void remove(String string) {
1307: checkWidget();
1308: if (string == null)
1309: error(SWT.ERROR_NULL_ARGUMENT);
1310: int index = indexOf(string, 0);
1311: if (index == -1)
1312: error(SWT.ERROR_INVALID_ARGUMENT);
1313: remove(index);
1314: }
1315:
1316: /**
1317: * Removes all of the items from the receiver's list and clear the
1318: * contents of receiver's text field.
1319: * <p>
1320: * @exception SWTException <ul>
1321: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1322: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1323: * </ul>
1324: */
1325: public void removeAll() {
1326: checkWidget();
1327: int count = getItemCount();
1328: if ((style & SWT.READ_ONLY) != 0) {
1329: OS.DeleteMenuItems(menuHandle, (short) 1, count);
1330: OS.SetControl32BitValue(handle, 0);
1331: } else {
1332: setText("", true);
1333: if (count > 0) {
1334: for (int i = count - 1; i >= 0; i--) {
1335: OS.HIComboBoxRemoveItemAtIndex(handle, i);
1336: }
1337: }
1338: }
1339: }
1340:
1341: /**
1342: * Removes the listener from the collection of listeners who will
1343: * be notified when the receiver's text is modified.
1344: *
1345: * @param listener the listener which should no longer be notified
1346: *
1347: * @exception IllegalArgumentException <ul>
1348: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1349: * </ul>
1350: * @exception SWTException <ul>
1351: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1352: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1353: * </ul>
1354: *
1355: * @see ModifyListener
1356: * @see #addModifyListener
1357: */
1358: public void removeModifyListener(ModifyListener listener) {
1359: checkWidget();
1360: if (listener == null)
1361: error(SWT.ERROR_NULL_ARGUMENT);
1362: if (eventTable == null)
1363: return;
1364: eventTable.unhook(SWT.Modify, listener);
1365: }
1366:
1367: /**
1368: * Removes the listener from the collection of listeners who will
1369: * be notified when the user changes the receiver's selection.
1370: *
1371: * @param listener the listener which should no longer be notified
1372: *
1373: * @exception IllegalArgumentException <ul>
1374: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1375: * </ul>
1376: * @exception SWTException <ul>
1377: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1378: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1379: * </ul>
1380: *
1381: * @see SelectionListener
1382: * @see #addSelectionListener
1383: */
1384: public void removeSelectionListener(SelectionListener listener) {
1385: checkWidget();
1386: if (listener == null)
1387: error(SWT.ERROR_NULL_ARGUMENT);
1388: if (eventTable == null)
1389: return;
1390: eventTable.unhook(SWT.Selection, listener);
1391: eventTable.unhook(SWT.DefaultSelection, listener);
1392: }
1393:
1394: /**
1395: * Removes the listener from the collection of listeners who will
1396: * be notified when the control is verified.
1397: *
1398: * @param listener the listener which should no longer be notified
1399: *
1400: * @exception IllegalArgumentException <ul>
1401: * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1402: * </ul>
1403: * @exception SWTException <ul>
1404: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1405: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1406: * </ul>
1407: *
1408: * @see VerifyListener
1409: * @see #addVerifyListener
1410: *
1411: * @since 3.1
1412: */
1413: public void removeVerifyListener(VerifyListener listener) {
1414: checkWidget();
1415: if (listener == null)
1416: error(SWT.ERROR_NULL_ARGUMENT);
1417: if (eventTable == null)
1418: return;
1419: eventTable.unhook(SWT.Verify, listener);
1420: }
1421:
1422: /**
1423: * Selects the item at the given zero-relative index in the receiver's
1424: * list. If the item at the index was already selected, it remains
1425: * selected. Indices that are out of range are ignored.
1426: *
1427: * @param index the index of the item to select
1428: *
1429: * @exception SWTException <ul>
1430: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1431: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1432: * </ul>
1433: */
1434: public void select(int index) {
1435: checkWidget();
1436: int count = getItemCount();
1437: if (0 <= index && index < count) {
1438: if ((style & SWT.READ_ONLY) != 0) {
1439: OS.SetControl32BitValue(handle, index + 1);
1440: sendEvent(SWT.Modify);
1441: } else {
1442: setText(getItem(index), true);
1443: }
1444: }
1445: }
1446:
1447: boolean sendKeyEvent(int type, Event event) {
1448: if (!super .sendKeyEvent(type, event)) {
1449: return false;
1450: }
1451: if (type != SWT.KeyDown)
1452: return true;
1453: if ((style & SWT.READ_ONLY) != 0)
1454: return true;
1455: if (event.character == 0)
1456: return true;
1457: String oldText = "", newText = "";
1458: if (hooks(SWT.Verify) || filters(SWT.Verify)) {
1459: int charCount = getCharCount();
1460: Point selection = getSelection();
1461: int start = selection.x, end = selection.y;
1462: switch (event.character) {
1463: case SWT.BS:
1464: if (start == end) {
1465: if (start == 0)
1466: return true;
1467: start = Math.max(0, start - 1);
1468: }
1469: break;
1470: case SWT.DEL:
1471: if (start == end) {
1472: if (start == charCount)
1473: return true;
1474: end = Math.min(end + 1, charCount);
1475: }
1476: break;
1477: case SWT.CR:
1478: return true;
1479: default:
1480: if (event.character != '\t' && event.character < 0x20)
1481: return true;
1482: oldText = new String(new char[] { event.character });
1483: }
1484: newText = verifyText(oldText, start, end, event);
1485: if (newText == null)
1486: return false;
1487: if (charCount - (end - start) + newText.length() > textLimit) {
1488: return false;
1489: }
1490: if (newText != oldText) {
1491: String text = getText();
1492: String leftText = text.substring(0, start);
1493: String rightText = text.substring(end, text.length());
1494: setText(leftText + newText + rightText, false);
1495: start += newText.length();
1496: setSelection(new Point(start, start));
1497: }
1498: }
1499: /*
1500: * Post the modify event so that the character will be inserted
1501: * into the widget when the modify event is delivered. Normally,
1502: * modify events are sent but it is safe to post the event here
1503: * because this method is called from the event loop.
1504: */
1505: postEvent(SWT.Modify);
1506: return newText == oldText;
1507: }
1508:
1509: void setBackground(int control, float[] color) {
1510: if ((style & SWT.READ_ONLY) == 0) {
1511: if (color == null)
1512: color = defaultBackground().handle;
1513: }
1514: super .setBackground(control, color);
1515: }
1516:
1517: int setBounds(int x, int y, int width, int height, boolean move,
1518: boolean resize, boolean events) {
1519: if ((style & SWT.READ_ONLY) != 0) {
1520: return super .setBounds(x, y, width, height, move, resize,
1521: events);
1522: }
1523: /*
1524: * Bug in the Macintosh. When the caret is moved,
1525: * the combo widget scrolls to show the new location.
1526: * This means that the combo widget may be scrolled
1527: * to the left in order to show the caret when the
1528: * widget is not large enough to show both the caret
1529: * location and all the text. Unfortunately, when
1530: * the widget is resized such that all the text and
1531: * the caret could be visible, the Macintosh does not
1532: * scroll the widget back. The fix is to save the
1533: * current selection, reset the text and then restore
1534: * the selection. This will cause the widget
1535: * to recompute the left scroll position.
1536: */
1537: Rect inset = getInset();
1538: Rectangle rect = getBounds();
1539: int oldWidth = rect.width - inset.left - inset.right;
1540: int result = super .setBounds(x, y, width, height, move, resize,
1541: events);
1542: if (oldWidth == 0 && width > 0) {
1543: Point selection = getSelection();
1544: setText(getText(), false);
1545: setSelection(selection);
1546: }
1547: return result;
1548: }
1549:
1550: /**
1551: * Sets the text of the item in the receiver's list at the given
1552: * zero-relative index to the string argument.
1553: *
1554: * @param index the index for the item
1555: * @param string the new text for the item
1556: *
1557: * @exception IllegalArgumentException <ul>
1558: * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1559: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1560: * </ul>
1561: * @exception SWTException <ul>
1562: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1563: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1564: * </ul>
1565: */
1566: public void setItem(int index, String string) {
1567: checkWidget();
1568: if (string == null)
1569: error(SWT.ERROR_NULL_ARGUMENT);
1570: int count = getItemCount();
1571: if (0 > index || index >= count)
1572: error(SWT.ERROR_INVALID_RANGE);
1573: char[] buffer = new char[string.length()];
1574: string.getChars(0, buffer.length, buffer, 0);
1575: int ptr = OS.CFStringCreateWithCharacters(
1576: OS.kCFAllocatorDefault, buffer, buffer.length);
1577: if (ptr == 0)
1578: error(SWT.ERROR_ITEM_NOT_ADDED);
1579: int result;
1580: if ((style & SWT.READ_ONLY) != 0) {
1581: result = OS.SetMenuItemTextWithCFString(menuHandle,
1582: (short) (index + 1), ptr);
1583: /*
1584: * Feature in the Macintosh. Setting text that starts with "-" makes the
1585: * menu item a separator. The fix is to clear the separator attribute.
1586: */
1587: if (string.startsWith("-")) {
1588: OS.ChangeMenuItemAttributes(menuHandle,
1589: (short) (index + 1), 0,
1590: OS.kMenuItemAttrSeparator);
1591: }
1592: } else {
1593: result = OS.HIComboBoxInsertTextItemAtIndex(handle, index,
1594: ptr);
1595: OS.HIComboBoxRemoveItemAtIndex(handle, index + 1);
1596: }
1597: OS.CFRelease(ptr);
1598: if (result != OS.noErr)
1599: error(SWT.ERROR_ITEM_NOT_ADDED);
1600: }
1601:
1602: /**
1603: * Sets the receiver's list to be the given array of items.
1604: *
1605: * @param items the array of items
1606: *
1607: * @exception IllegalArgumentException <ul>
1608: * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1609: * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1610: * </ul>
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>
1614: * </ul>
1615: */
1616: public void setItems(String[] items) {
1617: checkWidget();
1618: if (items == null)
1619: error(SWT.ERROR_NULL_ARGUMENT);
1620: for (int i = 0; i < items.length; i++) {
1621: if (items[i] == null)
1622: error(SWT.ERROR_INVALID_ARGUMENT);
1623: }
1624: removeAll();
1625: if (items.length == 0)
1626: return;
1627: for (int i = 0; i < items.length; i++) {
1628: String string = items[i];
1629: char[] buffer = new char[string.length()];
1630: string.getChars(0, buffer.length, buffer, 0);
1631: int ptr = OS.CFStringCreateWithCharacters(
1632: OS.kCFAllocatorDefault, buffer, buffer.length);
1633: if (ptr == 0)
1634: error(SWT.ERROR_ITEM_NOT_ADDED);
1635: int result;
1636: if ((style & SWT.READ_ONLY) != 0) {
1637: result = OS.AppendMenuItemTextWithCFString(menuHandle,
1638: ptr, 0, 0, null);
1639: /*
1640: * Feature in the Macintosh. Setting text that starts with "-" makes the
1641: * menu item a separator. The fix is to clear the separator attribute.
1642: */
1643: if (string.startsWith("-")) {
1644: OS.ChangeMenuItemAttributes(menuHandle,
1645: (short) (i + 1), 0,
1646: OS.kMenuItemAttrSeparator);
1647: }
1648: } else {
1649: int[] outIndex = new int[1];
1650: result = OS.HIComboBoxAppendTextItem(handle, ptr,
1651: outIndex);
1652: }
1653: OS.CFRelease(ptr);
1654: if (result != OS.noErr)
1655: error(SWT.ERROR_ITEM_NOT_ADDED);
1656: }
1657: }
1658:
1659: /*public*/void setListVisible(boolean visible) {
1660: checkWidget();
1661: if ((style & SWT.READ_ONLY) != 0) {
1662: //TODO - show the menu in the right place
1663: } else {
1664: OS.HIComboBoxSetListVisible(handle, visible);
1665: }
1666: }
1667:
1668: /**
1669: * Sets the orientation of the receiver, which must be one
1670: * of the constants <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
1671: * <p>
1672: *
1673: * @param orientation new orientation style
1674: *
1675: * @exception SWTException <ul>
1676: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1677: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1678: * </ul>
1679: *
1680: * @since 2.1.2
1681: */
1682: public void setOrientation(int orientation) {
1683: checkWidget();
1684: }
1685:
1686: /**
1687: * Sets the selection in the receiver's text field to the
1688: * range specified by the argument whose x coordinate is the
1689: * start of the selection and whose y coordinate is the end
1690: * of the selection.
1691: *
1692: * @param selection a point representing the new selection start and end
1693: *
1694: * @exception IllegalArgumentException <ul>
1695: * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
1696: * </ul>
1697: * @exception SWTException <ul>
1698: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1699: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1700: * </ul>
1701: */
1702: public void setSelection(Point selection) {
1703: checkWidget();
1704: if (selection == null)
1705: error(SWT.ERROR_NULL_ARGUMENT);
1706: if ((style & SWT.READ_ONLY) == 0) {
1707: int length = getCharCount();
1708: int start = selection.x, end = selection.y;
1709: ControlEditTextSelectionRec sel = new ControlEditTextSelectionRec();
1710: sel.selStart = (short) Math.min(Math.max(Math.min(start,
1711: end), 0), length);
1712: sel.selEnd = (short) Math.min(Math.max(
1713: Math.max(start, end), 0), length);
1714: if (hasFocus()) {
1715: OS.SetControlData(handle, OS.kHIComboBoxEditTextPart,
1716: OS.kControlEditTextSelectionTag, 4, sel);
1717: } else {
1718: this .selection = sel;
1719: }
1720: }
1721: }
1722:
1723: /**
1724: * Sets the contents of the receiver's text field to the
1725: * given string.
1726: * <p>
1727: * Note: The text field in a <code>Combo</code> is typically
1728: * only capable of displaying a single line of text. Thus,
1729: * setting the text to a string containing line breaks or
1730: * other special characters will probably cause it to
1731: * display incorrectly.
1732: * </p>
1733: *
1734: * @param string the new text
1735: *
1736: * @exception IllegalArgumentException <ul>
1737: * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1738: * </ul>
1739: * @exception SWTException <ul>
1740: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1741: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1742: * </ul>
1743: */
1744: public void setText(String string) {
1745: checkWidget();
1746: if (string == null)
1747: error(SWT.ERROR_NULL_ARGUMENT);
1748: setText(string, true);
1749: }
1750:
1751: void setText(String string, boolean notify) {
1752: if (notify) {
1753: if (hooks(SWT.Verify) || filters(SWT.Verify)) {
1754: string = verifyText(string, 0, getCharCount(), null);
1755: if (string == null)
1756: return;
1757: }
1758: }
1759: if ((style & SWT.READ_ONLY) != 0) {
1760: int index = indexOf(string);
1761: if (index != -1 && index != getSelectionIndex()) {
1762: select(index);
1763: if (notify)
1764: sendEvent(SWT.Modify);
1765: }
1766: } else {
1767: char[] buffer = new char[Math.min(string.length(),
1768: textLimit)];
1769: string.getChars(0, buffer.length, buffer, 0);
1770: int ptr = OS.CFStringCreateWithCharacters(
1771: OS.kCFAllocatorDefault, buffer, buffer.length);
1772: if (ptr == 0)
1773: error(SWT.ERROR_CANNOT_SET_TEXT);
1774: lastText = string;
1775: OS.SetControlData(handle, OS.kHIComboBoxEditTextPart,
1776: OS.kControlEditTextCFStringTag, 4,
1777: new int[] { ptr });
1778: OS.CFRelease(ptr);
1779: selection = null;
1780: if (notify)
1781: sendEvent(SWT.Modify);
1782: }
1783: }
1784:
1785: /**
1786: * Sets the maximum number of characters that the receiver's
1787: * text field is capable of holding to be the argument.
1788: * <p>
1789: * To reset this value to the default, use <code>setTextLimit(Combo.LIMIT)</code>.
1790: * Specifying a limit value larger than <code>Combo.LIMIT</code> sets the
1791: * receiver's limit to <code>Combo.LIMIT</code>.
1792: * </p>
1793: * @param limit new text limit
1794: *
1795: * @exception IllegalArgumentException <ul>
1796: * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li>
1797: * </ul>
1798: * @exception SWTException <ul>
1799: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1800: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1801: * </ul>
1802: *
1803: * @see #LIMIT
1804: */
1805: public void setTextLimit(int limit) {
1806: checkWidget();
1807: if (limit == 0)
1808: error(SWT.ERROR_CANNOT_BE_ZERO);
1809: textLimit = limit;
1810: }
1811:
1812: /**
1813: * Sets the number of items that are visible in the drop
1814: * down portion of the receiver's list.
1815: * <p>
1816: * Note: This operation is a hint and is not supported on
1817: * platforms that do not have this concept.
1818: * </p>
1819: *
1820: * @param count the new number of items to be visible
1821: *
1822: * @exception SWTException <ul>
1823: * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1824: * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1825: * </ul>
1826: *
1827: * @since 3.0
1828: */
1829: public void setVisibleItemCount(int count) {
1830: checkWidget();
1831: if (count < 0)
1832: return;
1833: if ((style & SWT.READ_ONLY) != 0) {
1834: //TODO
1835: } else {
1836: OS.SetControlData(handle, OS.kControlEntireControl,
1837: OS.kHIComboBoxNumVisibleItemsTag, 4,
1838: new int[] { count });
1839: }
1840: }
1841:
1842: String verifyText(String string, int start, int end, Event keyEvent) {
1843: Event event = new Event();
1844: event.text = string;
1845: event.start = start;
1846: event.end = end;
1847: if (keyEvent != null) {
1848: event.character = keyEvent.character;
1849: event.keyCode = keyEvent.keyCode;
1850: event.stateMask = keyEvent.stateMask;
1851: }
1852: /*
1853: * It is possible (but unlikely), that application
1854: * code could have disposed the widget in the verify
1855: * event. If this happens, answer null to cancel
1856: * the operation.
1857: */
1858: sendEvent(SWT.Verify, event);
1859: if (!event.doit || isDisposed())
1860: return null;
1861: return event.text;
1862: }
1863:
1864: }
|