1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.custom.CCombo; 14 15 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.SWTException; 19 import org.eclipse.swt.accessibility.ACC; 20 import org.eclipse.swt.accessibility.AccessibleAdapter; 21 import org.eclipse.swt.accessibility.AccessibleControlAdapter; 22 import org.eclipse.swt.accessibility.AccessibleControlEvent; 23 import org.eclipse.swt.accessibility.AccessibleEvent; 24 import org.eclipse.swt.accessibility.AccessibleTextAdapter; 25 import org.eclipse.swt.accessibility.AccessibleTextEvent; 26 import org.eclipse.swt.events.ModifyListener; 27 import org.eclipse.swt.events.SelectionEvent; 28 import org.eclipse.swt.events.SelectionListener; 29 import org.eclipse.swt.events.VerifyListener; 30 import org.eclipse.swt.graphics.Color; 31 import org.eclipse.swt.graphics.Font; 32 import org.eclipse.swt.graphics.GC; 33 import org.eclipse.swt.graphics.Point; 34 import org.eclipse.swt.graphics.Rectangle; 35 import org.eclipse.swt.widgets.Button; 36 import org.eclipse.swt.widgets.Composite; 37 import org.eclipse.swt.widgets.Control; 38 import org.eclipse.swt.widgets.Display; 39 import org.eclipse.swt.widgets.Event; 40 import org.eclipse.swt.widgets.Label; 41 import org.eclipse.swt.widgets.Layout; 42 import org.eclipse.swt.widgets.List; 43 import org.eclipse.swt.widgets.Listener; 44 import org.eclipse.swt.widgets.Menu; 45 import org.eclipse.swt.widgets.Shell; 46 import org.eclipse.swt.widgets.Text; 47 import org.eclipse.swt.widgets.TypedListener; 48 import org.eclipse.swt.widgets.Widget; 49 50 import java.lang.all; 51 import java.nonstandard.UnsafeUtf; 52 53 /** 54 * The CCombo class represents a selectable user interface object 55 * that combines a text field and a list and issues notification 56 * when an item is selected from the list. 57 * <p> 58 * CCombo was written to work around certain limitations in the native 59 * combo box. Specifically, on win32, the height of a CCombo can be set; 60 * attempts to set the height of a Combo are ignored. CCombo can be used 61 * anywhere that having the increased flexibility is more important than 62 * getting native L&F, but the decision should not be taken lightly. 63 * There is no is no strict requirement that CCombo look or behave 64 * the same as the native combo box. 65 * </p> 66 * <p> 67 * Note that although this class is a subclass of <code>Composite</code>, 68 * it does not make sense to add children to it, or set a layout on it. 69 * </p> 70 * <dl> 71 * <dt><b>Styles:</b> 72 * <dd>BORDER, READ_ONLY, FLAT</dd> 73 * <dt><b>Events:</b> 74 * <dd>DefaultSelection, Modify, Selection, Verify</dd> 75 * </dl> 76 * 77 * @see <a href="http://www.eclipse.org/swt/snippets/#ccombo">CCombo snippets</a> 78 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample</a> 79 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 80 */ 81 public final class CCombo : Composite { 82 83 alias Composite.computeSize computeSize; 84 85 Text text; 86 List list; 87 int visibleItemCount = 5; 88 Shell popup; 89 Button arrow; 90 bool hasFocus; 91 Listener listener, filter; 92 Color foreground, background; 93 Font font; 94 95 /** 96 * Constructs a new instance of this class given its parent 97 * and a style value describing its behavior and appearance. 98 * <p> 99 * The style value is either one of the style constants defined in 100 * class <code>SWT</code> which is applicable to instances of this 101 * class, or must be built by <em>bitwise OR</em>'ing together 102 * (that is, using the <code>int</code> "|" operator) two or more 103 * of those <code>SWT</code> style constants. The class description 104 * lists the style constants that are applicable to the class. 105 * Style bits are also inherited from superclasses. 106 * </p> 107 * 108 * @param parent a widget which will be the parent of the new instance (cannot be null) 109 * @param style the style of widget to construct 110 * 111 * @exception IllegalArgumentException <ul> 112 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 113 * </ul> 114 * @exception SWTException <ul> 115 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> 116 * </ul> 117 * 118 * @see SWT#BORDER 119 * @see SWT#READ_ONLY 120 * @see SWT#FLAT 121 * @see Widget#getStyle() 122 */ 123 public this (Composite parent, int style) { 124 super (parent, style = checkStyle (style)); 125 126 int textStyle = SWT.SINGLE; 127 if ((style & SWT.READ_ONLY) !is 0) textStyle |= SWT.READ_ONLY; 128 if ((style & SWT.FLAT) !is 0) textStyle |= SWT.FLAT; 129 text = new Text (this, textStyle); 130 int arrowStyle = SWT.ARROW | SWT.DOWN; 131 if ((style & SWT.FLAT) !is 0) arrowStyle |= SWT.FLAT; 132 arrow = new Button (this, arrowStyle); 133 134 listener = new class() Listener { 135 public void handleEvent (Event event) { 136 if (popup is event.widget) { 137 popupEvent (event); 138 return; 139 } 140 if (text is event.widget) { 141 textEvent (event); 142 return; 143 } 144 if (list is event.widget) { 145 listEvent (event); 146 return; 147 } 148 if (arrow is event.widget) { 149 arrowEvent (event); 150 return; 151 } 152 if (this.outer is event.widget) { 153 comboEvent (event); 154 return; 155 } 156 if (getShell () is event.widget) { 157 getDisplay().asyncExec(new class() Runnable { 158 public void run() { 159 if (isDisposed()) return; 160 handleFocus (SWT.FocusOut); 161 } 162 }); 163 } 164 } 165 }; 166 filter = new class() Listener { 167 public void handleEvent(Event event) { 168 Shell shell = (cast(Control)event.widget).getShell (); 169 if (shell is this.outer.getShell ()) { 170 handleFocus (SWT.FocusOut); 171 } 172 } 173 }; 174 175 int [] comboEvents = [SWT.Dispose, SWT.FocusIn, SWT.Move, SWT.Resize]; 176 for (int i=0; i<comboEvents.length; i++) this.addListener (comboEvents [i], listener); 177 178 int [] textEvents = [SWT.DefaultSelection, SWT.KeyDown, SWT.KeyUp, SWT.MenuDetect, SWT.Modify, SWT.MouseDown, SWT.MouseUp, SWT.MouseDoubleClick, SWT.MouseWheel, SWT.Traverse, SWT.FocusIn, SWT.Verify]; 179 for (int i=0; i<textEvents.length; i++) text.addListener (textEvents [i], listener); 180 181 int [] arrowEvents = [SWT.MouseDown, SWT.MouseUp, SWT.Selection, SWT.FocusIn]; 182 for (int i=0; i<arrowEvents.length; i++) arrow.addListener (arrowEvents [i], listener); 183 184 createPopup(null, -1); 185 initAccessible(); 186 } 187 static int checkStyle (int style) { 188 int mask = SWT.BORDER | SWT.READ_ONLY | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; 189 return SWT.NO_FOCUS | (style & mask); 190 } 191 /** 192 * Adds the argument to the end of the receiver's list. 193 * 194 * @param string the new item 195 * 196 * @exception SWTException <ul> 197 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 198 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 199 * </ul> 200 * 201 * @see #add(String,int) 202 */ 203 public void add (String string) { 204 checkWidget(); 205 // SWT extension: allow null for zero length string 206 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 207 list.add (string); 208 } 209 /** 210 * Adds the argument to the receiver's list at the given 211 * zero-relative index. 212 * <p> 213 * Note: To add an item at the end of the list, use the 214 * result of calling <code>getItemCount()</code> as the 215 * index or use <code>add(String)</code>. 216 * </p> 217 * 218 * @param string the new item 219 * @param index the index for the item 220 * 221 * @exception IllegalArgumentException <ul> 222 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li> 223 * </ul> 224 * @exception SWTException <ul> 225 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 226 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 227 * </ul> 228 * 229 * @see #add(String) 230 */ 231 public void add (String string, int index) { 232 checkWidget(); 233 // SWT extension: allow null for zero length string 234 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 235 list.add (string, index); 236 } 237 /** 238 * Adds the listener to the collection of listeners who will 239 * be notified when the receiver's text is modified, by sending 240 * it one of the messages defined in the <code>ModifyListener</code> 241 * interface. 242 * 243 * @param listener the listener which should be notified 244 * 245 * @exception IllegalArgumentException <ul> 246 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 247 * </ul> 248 * @exception SWTException <ul> 249 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 250 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 251 * </ul> 252 * 253 * @see ModifyListener 254 * @see #removeModifyListener 255 */ 256 public void addModifyListener (ModifyListener listener) { 257 checkWidget(); 258 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 259 TypedListener typedListener = new TypedListener (listener); 260 addListener (SWT.Modify, typedListener); 261 } 262 /** 263 * Adds the listener to the collection of listeners who will 264 * be notified when the user changes the receiver's selection, by sending 265 * it one of the messages defined in the <code>SelectionListener</code> 266 * interface. 267 * <p> 268 * <code>widgetSelected</code> is called when the combo's list selection changes. 269 * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed the combo's text area. 270 * </p> 271 * 272 * @param listener the listener which should be notified when the user changes the receiver's selection 273 * 274 * @exception IllegalArgumentException <ul> 275 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 276 * </ul> 277 * @exception SWTException <ul> 278 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 279 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 280 * </ul> 281 * 282 * @see SelectionListener 283 * @see #removeSelectionListener 284 * @see SelectionEvent 285 */ 286 public void addSelectionListener(SelectionListener listener) { 287 checkWidget(); 288 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 289 TypedListener typedListener = new TypedListener (listener); 290 addListener (SWT.Selection,typedListener); 291 addListener (SWT.DefaultSelection,typedListener); 292 } 293 /** 294 * Adds the listener to the collection of listeners who will 295 * be notified when the receiver's text is verified, by sending 296 * it one of the messages defined in the <code>VerifyListener</code> 297 * interface. 298 * 299 * @param listener the listener which should be notified 300 * 301 * @exception IllegalArgumentException <ul> 302 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 303 * </ul> 304 * @exception SWTException <ul> 305 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 306 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 307 * </ul> 308 * 309 * @see VerifyListener 310 * @see #removeVerifyListener 311 * 312 * @since 3.3 313 */ 314 public void addVerifyListener (VerifyListener listener) { 315 checkWidget(); 316 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 317 TypedListener typedListener = new TypedListener (listener); 318 addListener (SWT.Verify,typedListener); 319 } 320 void arrowEvent (Event event) { 321 switch (event.type) { 322 case SWT.FocusIn: { 323 handleFocus (SWT.FocusIn); 324 break; 325 } 326 case SWT.MouseDown: { 327 Event mouseEvent = new Event (); 328 mouseEvent.button = event.button; 329 mouseEvent.count = event.count; 330 mouseEvent.stateMask = event.stateMask; 331 mouseEvent.time = event.time; 332 mouseEvent.x = event.x; mouseEvent.y = event.y; 333 notifyListeners (SWT.MouseDown, mouseEvent); 334 event.doit = mouseEvent.doit; 335 break; 336 } 337 case SWT.MouseUp: { 338 Event mouseEvent = new Event (); 339 mouseEvent.button = event.button; 340 mouseEvent.count = event.count; 341 mouseEvent.stateMask = event.stateMask; 342 mouseEvent.time = event.time; 343 mouseEvent.x = event.x; mouseEvent.y = event.y; 344 notifyListeners (SWT.MouseUp, mouseEvent); 345 event.doit = mouseEvent.doit; 346 break; 347 } 348 case SWT.Selection: { 349 text.setFocus(); 350 dropDown (!isDropped ()); 351 break; 352 } 353 default: 354 } 355 } 356 /** 357 * Sets the selection in the receiver's text field to an empty 358 * selection starting just before the first character. If the 359 * text field is editable, this has the effect of placing the 360 * i-beam at the start of the text. 361 * <p> 362 * Note: To clear the selected items in the receiver's list, 363 * use <code>deselectAll()</code>. 364 * </p> 365 * 366 * @exception SWTException <ul> 367 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 368 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 369 * </ul> 370 * 371 * @see #deselectAll 372 */ 373 public void clearSelection () { 374 checkWidget (); 375 text.clearSelection (); 376 list.deselectAll (); 377 } 378 void comboEvent (Event event) { 379 switch (event.type) { 380 case SWT.Dispose: 381 if (popup !is null && !popup.isDisposed ()) { 382 list.removeListener (SWT.Dispose, listener); 383 popup.dispose (); 384 } 385 Shell shell = getShell (); 386 shell.removeListener (SWT.Deactivate, listener); 387 Display display = getDisplay (); 388 display.removeFilter (SWT.FocusIn, filter); 389 popup = null; 390 text = null; 391 list = null; 392 arrow = null; 393 break; 394 case SWT.FocusIn: 395 Control focusControl = getDisplay ().getFocusControl (); 396 if (focusControl is arrow || focusControl is list) return; 397 if (isDropped()) { 398 list.setFocus(); 399 } else { 400 text.setFocus(); 401 } 402 break; 403 case SWT.Move: 404 dropDown (false); 405 break; 406 case SWT.Resize: 407 internalLayout (false); 408 break; 409 default: 410 } 411 } 412 413 public override Point computeSize (int wHint, int hHint, bool changed) { 414 checkWidget (); 415 int width = 0, height = 0; 416 String[] items = list.getItems (); 417 GC gc = new GC (text); 418 int spacer = gc.stringExtent (" ").x; //$NON-NLS-1$ 419 int textWidth = gc.stringExtent (text.getText ()).x; 420 for (int i = 0; i < items.length; i++) { 421 textWidth = Math.max (gc.stringExtent (items[i]).x, textWidth); 422 } 423 gc.dispose (); 424 Point textSize = text.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed); 425 Point arrowSize = arrow.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed); 426 Point listSize = list.computeSize (SWT.DEFAULT, SWT.DEFAULT, changed); 427 int borderWidth = getBorderWidth (); 428 429 height = Math.max (textSize.y, arrowSize.y); 430 width = Math.max (textWidth + 2*spacer + arrowSize.x + 2*borderWidth, listSize.x); 431 if (wHint !is SWT.DEFAULT) width = wHint; 432 if (hHint !is SWT.DEFAULT) height = hHint; 433 return new Point (width + 2*borderWidth, height + 2*borderWidth); 434 } 435 /** 436 * Copies the selected text. 437 * <p> 438 * The current selection is copied to the clipboard. 439 * </p> 440 * 441 * @exception SWTException <ul> 442 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 443 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 444 * </ul> 445 * 446 * @since 3.3 447 */ 448 public void copy () { 449 checkWidget (); 450 text.copy (); 451 } 452 void createPopup(String[] items, int selectionIndex) { 453 // create shell and list 454 popup = new Shell (getShell (), SWT.NO_TRIM | SWT.ON_TOP); 455 int style = getStyle (); 456 int listStyle = SWT.SINGLE | SWT.V_SCROLL; 457 if ((style & SWT.FLAT) !is 0) listStyle |= SWT.FLAT; 458 if ((style & SWT.RIGHT_TO_LEFT) !is 0) listStyle |= SWT.RIGHT_TO_LEFT; 459 if ((style & SWT.LEFT_TO_RIGHT) !is 0) listStyle |= SWT.LEFT_TO_RIGHT; 460 list = new List (popup, listStyle); 461 if (font !is null) list.setFont (font); 462 if (foreground !is null) list.setForeground (foreground); 463 if (background !is null) list.setBackground (background); 464 465 int [] popupEvents = [SWT.Close, SWT.Paint, SWT.Deactivate]; 466 for (int i=0; i<popupEvents.length; i++) popup.addListener (popupEvents [i], listener); 467 int [] listEvents = [SWT.MouseUp, SWT.Selection, SWT.Traverse, SWT.KeyDown, SWT.KeyUp, SWT.FocusIn, SWT.Dispose]; 468 for (int i=0; i<listEvents.length; i++) list.addListener (listEvents [i], listener); 469 470 if (items !is null) list.setItems (items); 471 if (selectionIndex !is -1) list.setSelection (selectionIndex); 472 } 473 /** 474 * Cuts the selected text. 475 * <p> 476 * The current selection is first copied to the 477 * clipboard and then deleted from the widget. 478 * </p> 479 * 480 * @exception SWTException <ul> 481 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 482 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 483 * </ul> 484 * 485 * @since 3.3 486 */ 487 public void cut () { 488 checkWidget (); 489 text.cut (); 490 } 491 /** 492 * Deselects the item at the given zero-relative index in the receiver's 493 * list. If the item at the index was already deselected, it remains 494 * deselected. Indices that are out of range are ignored. 495 * 496 * @param index the index of the item to deselect 497 * 498 * @exception SWTException <ul> 499 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 500 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 501 * </ul> 502 */ 503 public void deselect (int index) { 504 checkWidget (); 505 if (0 <= index && index < list.getItemCount () && 506 index is list.getSelectionIndex() && 507 text.getText().equals(list.getItem(index))) { 508 text.setText(""); //$NON-NLS-1$ 509 list.deselect (index); 510 } 511 } 512 /** 513 * Deselects all selected items in the receiver's list. 514 * <p> 515 * Note: To clear the selection in the receiver's text field, 516 * use <code>clearSelection()</code>. 517 * </p> 518 * 519 * @exception SWTException <ul> 520 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 521 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 522 * </ul> 523 * 524 * @see #clearSelection 525 */ 526 public void deselectAll () { 527 checkWidget (); 528 text.setText(""); //$NON-NLS-1$ 529 list.deselectAll (); 530 } 531 void dropDown (bool drop) { 532 if (drop is isDropped ()) return; 533 if (!drop) { 534 popup.setVisible (false); 535 if (!isDisposed () && isFocusControl()) { 536 text.setFocus(); 537 } 538 return; 539 } 540 if (!isVisible()) return; 541 if (getShell() !is popup.getParent ()) { 542 String[] items = list.getItems (); 543 int selectionIndex = list.getSelectionIndex (); 544 list.removeListener (SWT.Dispose, listener); 545 popup.dispose(); 546 popup = null; 547 list = null; 548 createPopup (items, selectionIndex); 549 } 550 551 Point size = getSize (); 552 int itemCount = list.getItemCount (); 553 itemCount = (itemCount is 0) ? visibleItemCount : Math.min(visibleItemCount, itemCount); 554 int itemHeight = list.getItemHeight () * itemCount; 555 Point listSize = list.computeSize (SWT.DEFAULT, itemHeight, false); 556 list.setBounds (1, 1, Math.max (size.x - 2, listSize.x), listSize.y); 557 558 int index = list.getSelectionIndex (); 559 if (index !is -1) list.setTopIndex (index); 560 Display display = getDisplay (); 561 Rectangle listRect = list.getBounds (); 562 Rectangle parentRect = display.map (getParent (), null, getBounds ()); 563 Point comboSize = getSize (); 564 Rectangle displayRect = getMonitor ().getClientArea (); 565 int width = Math.max (comboSize.x, listRect.width + 2); 566 int height = listRect.height + 2; 567 int x = parentRect.x; 568 int y = parentRect.y + comboSize.y; 569 if (y + height > displayRect.y + displayRect.height) y = parentRect.y - height; 570 if (x + width > displayRect.x + displayRect.width) x = displayRect.x + displayRect.width - listRect.width; 571 popup.setBounds (x, y, width, height); 572 popup.setVisible (true); 573 if (isFocusControl()) list.setFocus (); 574 } 575 /* 576 * Return the lowercase of the first non-'&' character following 577 * an '&' character in the given string. If there are no '&' 578 * characters in the given string, return '\0'. 579 */ 580 dchar _findMnemonic (String str) { 581 if (str is null) return '\0'; 582 int index = 0; 583 auto length = str.length; 584 do { 585 while (index < length && str[index] !is '&') index++; 586 if (++index >= length) return '\0'; 587 if (str[index] !is '&') return Character.toLowerCase( str.dcharAt(index) ); 588 index++; 589 } while (index < length); 590 return '\0'; 591 } 592 /* 593 * Return the Label immediately preceding the receiver in the z-order, 594 * or null if none. 595 */ 596 Label getAssociatedLabel () { 597 Control[] siblings = getParent ().getChildren (); 598 for (int i = 0; i < siblings.length; i++) { 599 if (siblings [i] is this) { 600 if (i > 0 && ( null !is cast(Label)siblings [i-1] )) { 601 return cast(Label) siblings [i-1]; 602 } 603 } 604 } 605 return null; 606 } 607 public override Control [] getChildren () { 608 checkWidget(); 609 return new Control [0]; 610 } 611 /** 612 * Gets the editable state. 613 * 614 * @return whether or not the receiver is editable 615 * 616 * @exception SWTException <ul> 617 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 618 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 619 * </ul> 620 * 621 * @since 3.0 622 */ 623 public bool getEditable () { 624 checkWidget (); 625 return text.getEditable(); 626 } 627 /** 628 * Returns the item at the given, zero-relative index in the 629 * receiver's list. Throws an exception if the index is out 630 * of range. 631 * 632 * @param index the index of the item to return 633 * @return the item at the given index 634 * 635 * @exception IllegalArgumentException <ul> 636 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> 637 * </ul> 638 * @exception SWTException <ul> 639 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 640 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 641 * </ul> 642 */ 643 public String getItem (int index) { 644 checkWidget(); 645 return list.getItem (index); 646 } 647 /** 648 * Returns the number of items contained in the receiver's list. 649 * 650 * @return the number of items 651 * 652 * @exception SWTException <ul> 653 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 654 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 655 * </ul> 656 */ 657 public int getItemCount () { 658 checkWidget (); 659 return list.getItemCount (); 660 } 661 /** 662 * Returns the height of the area which would be used to 663 * display <em>one</em> of the items in the receiver's list. 664 * 665 * @return the height of one item 666 * 667 * @exception SWTException <ul> 668 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 669 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 670 * </ul> 671 */ 672 public int getItemHeight () { 673 checkWidget (); 674 return list.getItemHeight (); 675 } 676 /** 677 * Returns an array of <code>String</code>s which are the items 678 * in the receiver's list. 679 * <p> 680 * Note: This is not the actual structure used by the receiver 681 * to maintain its list of items, so modifying the array will 682 * not affect the receiver. 683 * </p> 684 * 685 * @return the items in the receiver's list 686 * 687 * @exception SWTException <ul> 688 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 689 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 690 * </ul> 691 */ 692 public String [] getItems () { 693 checkWidget (); 694 return list.getItems (); 695 } 696 /** 697 * Returns <code>true</code> if the receiver's list is visible, 698 * and <code>false</code> otherwise. 699 * <p> 700 * If one of the receiver's ancestors is not visible or some 701 * other condition makes the receiver not visible, this method 702 * may still indicate that it is considered visible even though 703 * it may not actually be showing. 704 * </p> 705 * 706 * @return the receiver's list's visibility state 707 * 708 * @exception SWTException <ul> 709 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 710 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 711 * </ul> 712 * 713 * @since 3.4 714 */ 715 public bool getListVisible () { 716 checkWidget (); 717 return isDropped(); 718 } 719 public override Menu getMenu() { 720 return text.getMenu(); 721 } 722 /** 723 * Returns a <code>Point</code> whose x coordinate is the start 724 * of the selection in the receiver's text field, and whose y 725 * coordinate is the end of the selection. The returned values 726 * are zero-relative. An "empty" selection as indicated by 727 * the the x and y coordinates having the same value. 728 * 729 * @return a point representing the selection start and end 730 * 731 * @exception SWTException <ul> 732 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 733 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 734 * </ul> 735 */ 736 public Point getSelection () { 737 checkWidget (); 738 return text.getSelection (); 739 } 740 /** 741 * Returns the zero-relative index of the item which is currently 742 * selected in the receiver's list, or -1 if no item is selected. 743 * 744 * @return the index of the selected item 745 * 746 * @exception SWTException <ul> 747 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 748 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 749 * </ul> 750 */ 751 public int getSelectionIndex () { 752 checkWidget (); 753 return list.getSelectionIndex (); 754 } 755 public override int getStyle () { 756 int style = super.getStyle (); 757 style &= ~SWT.READ_ONLY; 758 if (!text.getEditable()) style |= SWT.READ_ONLY; 759 return style; 760 } 761 /** 762 * Returns a string containing a copy of the contents of the 763 * receiver's text field. 764 * 765 * @return the receiver's text 766 * 767 * @exception SWTException <ul> 768 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 769 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 770 * </ul> 771 */ 772 public String getText () { 773 checkWidget (); 774 return text.getText (); 775 } 776 /** 777 * Returns the height of the receivers's text field. 778 * 779 * @return the text height 780 * 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> 784 * </ul> 785 */ 786 public int getTextHeight () { 787 checkWidget (); 788 return text.getLineHeight (); 789 } 790 /** 791 * Returns the maximum number of characters that the receiver's 792 * text field is capable of holding. If this has not been changed 793 * by <code>setTextLimit()</code>, it will be the constant 794 * <code>Combo.LIMIT</code>. 795 * 796 * @return the text limit 797 * 798 * @exception SWTException <ul> 799 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 800 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 801 * </ul> 802 */ 803 public int getTextLimit () { 804 checkWidget (); 805 return text.getTextLimit (); 806 } 807 /** 808 * Gets the number of items that are visible in the drop 809 * down portion of the receiver's list. 810 * 811 * @return the number of items that are visible 812 * 813 * @exception SWTException <ul> 814 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 815 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 816 * </ul> 817 * 818 * @since 3.0 819 */ 820 public int getVisibleItemCount () { 821 checkWidget (); 822 return visibleItemCount; 823 } 824 void handleFocus (int type) { 825 if (isDisposed ()) return; 826 switch (type) { 827 case SWT.FocusIn: { 828 if (hasFocus) return; 829 if (getEditable ()) text.selectAll (); 830 hasFocus = true; 831 Shell shell = getShell (); 832 shell.removeListener (SWT.Deactivate, listener); 833 shell.addListener (SWT.Deactivate, listener); 834 Display display = getDisplay (); 835 display.removeFilter (SWT.FocusIn, filter); 836 display.addFilter (SWT.FocusIn, filter); 837 Event e = new Event (); 838 notifyListeners (SWT.FocusIn, e); 839 break; 840 } 841 case SWT.FocusOut: { 842 if (!hasFocus) return; 843 Control focusControl = getDisplay ().getFocusControl (); 844 if (focusControl is arrow || focusControl is list || focusControl is text) return; 845 hasFocus = false; 846 Shell shell = getShell (); 847 shell.removeListener(SWT.Deactivate, listener); 848 Display display = getDisplay (); 849 display.removeFilter (SWT.FocusIn, filter); 850 Event e = new Event (); 851 notifyListeners (SWT.FocusOut, e); 852 break; 853 } 854 default: 855 } 856 } 857 /** 858 * Searches the receiver's list starting at the first item 859 * (index 0) until an item is found that is equal to the 860 * argument, and returns the index of that item. If no item 861 * is found, returns -1. 862 * 863 * @param string the search item 864 * @return the index of the item 865 * 866 * @exception SWTException <ul> 867 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 868 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 869 * </ul> 870 */ 871 public int indexOf (String string) { 872 checkWidget (); 873 // SWT extension: allow null for zero length string 874 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 875 return list.indexOf (string); 876 } 877 /** 878 * Searches the receiver's list starting at the given, 879 * zero-relative index until an item is found that is equal 880 * to the argument, and returns the index of that item. If 881 * no item is found or the starting index is out of range, 882 * returns -1. 883 * 884 * @param string the search item 885 * @param start the zero-relative index at which to begin the search 886 * @return the index of the item 887 * 888 * @exception SWTException <ul> 889 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 890 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 891 * </ul> 892 */ 893 public int indexOf (String string, int start) { 894 checkWidget (); 895 // SWT extension: allow null for zero length string 896 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 897 return list.indexOf (string, start); 898 } 899 900 void initAccessible() { 901 AccessibleAdapter accessibleAdapter = new class() AccessibleAdapter { 902 override 903 public void getName (AccessibleEvent e) { 904 String name = null; 905 Label label = getAssociatedLabel (); 906 if (label !is null) { 907 name = stripMnemonic (label.getText()); 908 } 909 e.result = name; 910 } 911 override 912 public void getKeyboardShortcut(AccessibleEvent e) { 913 String shortcut = null; 914 Label label = getAssociatedLabel (); 915 if (label !is null) { 916 String text = label.getText (); 917 if (text !is null) { 918 dchar mnemonic = _findMnemonic (text); 919 if (mnemonic !is '\0') { 920 shortcut = Format( "Alt+{}", mnemonic ); //$NON-NLS-1$ 921 } 922 } 923 } 924 e.result = shortcut; 925 } 926 override 927 public void getHelp (AccessibleEvent e) { 928 e.result = getToolTipText (); 929 } 930 }; 931 getAccessible ().addAccessibleListener (accessibleAdapter); 932 text.getAccessible ().addAccessibleListener (accessibleAdapter); 933 list.getAccessible ().addAccessibleListener (accessibleAdapter); 934 935 arrow.getAccessible ().addAccessibleListener (new class() AccessibleAdapter { 936 override 937 public void getName (AccessibleEvent e) { 938 e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$ 939 } 940 override 941 public void getKeyboardShortcut (AccessibleEvent e) { 942 e.result = "Alt+Down Arrow"; //$NON-NLS-1$ 943 } 944 override 945 public void getHelp (AccessibleEvent e) { 946 e.result = getToolTipText (); 947 } 948 }); 949 950 getAccessible().addAccessibleTextListener (new class() AccessibleTextAdapter { 951 override 952 public void getCaretOffset (AccessibleTextEvent e) { 953 e.offset = text.getCaretPosition (); 954 } 955 override 956 public void getSelectionRange(AccessibleTextEvent e) { 957 Point sel = text.getSelection(); 958 e.offset = sel.x; 959 e.length = sel.y - sel.x; 960 } 961 }); 962 963 getAccessible().addAccessibleControlListener (new class() AccessibleControlAdapter { 964 override 965 public void getChildAtPoint (AccessibleControlEvent e) { 966 Point testPoint = toControl (e.x, e.y); 967 if (getBounds ().contains (testPoint)) { 968 e.childID = ACC.CHILDID_SELF; 969 } 970 } 971 972 override 973 public void getLocation (AccessibleControlEvent e) { 974 Rectangle location = getBounds (); 975 Point pt = getParent().toDisplay (location.x, location.y); 976 e.x = pt.x; 977 e.y = pt.y; 978 e.width = location.width; 979 e.height = location.height; 980 } 981 982 override 983 public void getChildCount (AccessibleControlEvent e) { 984 e.detail = 0; 985 } 986 987 override 988 public void getRole (AccessibleControlEvent e) { 989 e.detail = ACC.ROLE_COMBOBOX; 990 } 991 992 override 993 public void getState (AccessibleControlEvent e) { 994 e.detail = ACC.STATE_NORMAL; 995 } 996 997 override 998 public void getValue (AccessibleControlEvent e) { 999 e.result = getText (); 1000 } 1001 }); 1002 1003 text.getAccessible ().addAccessibleControlListener (new class() AccessibleControlAdapter { 1004 override 1005 public void getRole (AccessibleControlEvent e) { 1006 e.detail = text.getEditable () ? ACC.ROLE_TEXT : ACC.ROLE_LABEL; 1007 } 1008 }); 1009 1010 arrow.getAccessible ().addAccessibleControlListener (new class() AccessibleControlAdapter { 1011 override 1012 public void getDefaultAction (AccessibleControlEvent e) { 1013 e.result = isDropped () ? SWT.getMessage ("SWT_Close") : SWT.getMessage ("SWT_Open"); //$NON-NLS-1$ //$NON-NLS-2$ 1014 } 1015 }); 1016 } 1017 bool isDropped () { 1018 return popup.getVisible (); 1019 } 1020 public override bool isFocusControl () { 1021 checkWidget(); 1022 if (text.isFocusControl () || arrow.isFocusControl () || list.isFocusControl () || popup.isFocusControl ()) { 1023 return true; 1024 } 1025 return super.isFocusControl (); 1026 } 1027 void internalLayout (bool changed) { 1028 if (isDropped ()) dropDown (false); 1029 Rectangle rect = getClientArea (); 1030 int width = rect.width; 1031 int height = rect.height; 1032 Point arrowSize = arrow.computeSize (SWT.DEFAULT, height, changed); 1033 text.setBounds (0, 0, width - arrowSize.x, height); 1034 arrow.setBounds (width - arrowSize.x, 0, arrowSize.x, arrowSize.y); 1035 } 1036 void listEvent (Event event) { 1037 switch (event.type) { 1038 case SWT.Dispose: 1039 if (getShell () !is popup.getParent ()) { 1040 String[] items = list.getItems (); 1041 int selectionIndex = list.getSelectionIndex (); 1042 popup = null; 1043 list = null; 1044 createPopup (items, selectionIndex); 1045 } 1046 break; 1047 case SWT.FocusIn: { 1048 handleFocus (SWT.FocusIn); 1049 break; 1050 } 1051 case SWT.MouseUp: { 1052 if (event.button !is 1) return; 1053 dropDown (false); 1054 break; 1055 } 1056 case SWT.Selection: { 1057 int index = list.getSelectionIndex (); 1058 if (index is -1) return; 1059 text.setText (list.getItem (index)); 1060 text.selectAll (); 1061 list.setSelection (index); 1062 Event e = new Event (); 1063 e.time = event.time; 1064 e.stateMask = event.stateMask; 1065 e.doit = event.doit; 1066 notifyListeners (SWT.Selection, e); 1067 event.doit = e.doit; 1068 break; 1069 } 1070 case SWT.Traverse: { 1071 switch (event.detail) { 1072 case SWT.TRAVERSE_RETURN: 1073 case SWT.TRAVERSE_ESCAPE: 1074 case SWT.TRAVERSE_ARROW_PREVIOUS: 1075 case SWT.TRAVERSE_ARROW_NEXT: 1076 event.doit = false; 1077 break; 1078 case SWT.TRAVERSE_TAB_NEXT: 1079 case SWT.TRAVERSE_TAB_PREVIOUS: 1080 event.doit = text.traverse(event.detail); 1081 event.detail = SWT.TRAVERSE_NONE; 1082 if (event.doit) dropDown(false); 1083 return; 1084 default: 1085 } 1086 Event e = new Event (); 1087 e.time = event.time; 1088 e.detail = event.detail; 1089 e.doit = event.doit; 1090 e.character = event.character; 1091 e.keyCode = event.keyCode; 1092 notifyListeners (SWT.Traverse, e); 1093 event.doit = e.doit; 1094 event.detail = e.detail; 1095 break; 1096 } 1097 case SWT.KeyUp: { 1098 Event e = new Event (); 1099 e.time = event.time; 1100 e.character = event.character; 1101 e.keyCode = event.keyCode; 1102 e.stateMask = event.stateMask; 1103 notifyListeners (SWT.KeyUp, e); 1104 break; 1105 } 1106 case SWT.KeyDown: { 1107 if (event.character is SWT.ESC) { 1108 // Escape key cancels popup list 1109 dropDown (false); 1110 } 1111 if ((event.stateMask & SWT.ALT) !is 0 && (event.keyCode is SWT.ARROW_UP || event.keyCode is SWT.ARROW_DOWN)) { 1112 dropDown (false); 1113 } 1114 if (event.character is SWT.CR) { 1115 // Enter causes default selection 1116 dropDown (false); 1117 Event e = new Event (); 1118 e.time = event.time; 1119 e.stateMask = event.stateMask; 1120 notifyListeners (SWT.DefaultSelection, e); 1121 } 1122 // At this point the widget may have been disposed. 1123 // If so, do not continue. 1124 if (isDisposed ()) break; 1125 Event e = new Event(); 1126 e.time = event.time; 1127 e.character = event.character; 1128 e.keyCode = event.keyCode; 1129 e.stateMask = event.stateMask; 1130 notifyListeners(SWT.KeyDown, e); 1131 break; 1132 1133 } 1134 default: 1135 } 1136 } 1137 /** 1138 * Pastes text from clipboard. 1139 * <p> 1140 * The selected text is deleted from the widget 1141 * and new text inserted from the clipboard. 1142 * </p> 1143 * 1144 * @exception SWTException <ul> 1145 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1146 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1147 * </ul> 1148 * 1149 * @since 3.3 1150 */ 1151 public void paste () { 1152 checkWidget (); 1153 text.paste (); 1154 } 1155 void popupEvent(Event event) { 1156 switch (event.type) { 1157 case SWT.Paint: 1158 // draw black rectangle around list 1159 Rectangle listRect = list.getBounds(); 1160 Color black = getDisplay().getSystemColor(SWT.COLOR_BLACK); 1161 event.gc.setForeground(black); 1162 event.gc.drawRectangle(0, 0, listRect.width + 1, listRect.height + 1); 1163 break; 1164 case SWT.Close: 1165 event.doit = false; 1166 dropDown (false); 1167 break; 1168 case SWT.Deactivate: 1169 /* 1170 * Bug in GTK. When the arrow button is pressed the popup control receives a 1171 * deactivate event and then the arrow button receives a selection event. If 1172 * we hide the popup in the deactivate event, the selection event will show 1173 * it again. To prevent the popup from showing again, we will let the selection 1174 * event of the arrow button hide the popup. 1175 * In Windows, hiding the popup during the deactivate causes the deactivate 1176 * to be called twice and the selection event to be disappear. 1177 */ 1178 if ("carbon" != (SWT.getPlatform())) { 1179 Point point = arrow.toControl(getDisplay().getCursorLocation()); 1180 Point size = arrow.getSize(); 1181 Rectangle rect = new Rectangle(0, 0, size.x, size.y); 1182 if (!rect.contains(point)) dropDown (false); 1183 } else { 1184 dropDown(false); 1185 } 1186 break; 1187 default: 1188 } 1189 } 1190 public override void redraw () { 1191 super.redraw(); 1192 text.redraw(); 1193 arrow.redraw(); 1194 if (popup.isVisible()) list.redraw(); 1195 } 1196 public override void redraw (int x, int y, int width, int height, bool all) { 1197 super.redraw(x, y, width, height, true); 1198 } 1199 1200 /** 1201 * Removes the item from the receiver's list at the given 1202 * zero-relative index. 1203 * 1204 * @param index the index for the item 1205 * 1206 * @exception IllegalArgumentException <ul> 1207 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> 1208 * </ul> 1209 * @exception SWTException <ul> 1210 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1211 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1212 * </ul> 1213 */ 1214 public void remove (int index) { 1215 checkWidget(); 1216 list.remove (index); 1217 } 1218 /** 1219 * Removes the items from the receiver's list which are 1220 * between the given zero-relative start and end 1221 * indices (inclusive). 1222 * 1223 * @param start the start of the range 1224 * @param end the end of the range 1225 * 1226 * @exception IllegalArgumentException <ul> 1227 * <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> 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 start, int end) { 1235 checkWidget(); 1236 list.remove (start, end); 1237 } 1238 /** 1239 * Searches the receiver's list starting at the first item 1240 * until an item is found that is equal to the argument, 1241 * and removes that item from the list. 1242 * 1243 * @param string the item to remove 1244 * 1245 * @exception IllegalArgumentException <ul> 1246 * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li> 1247 * </ul> 1248 * @exception SWTException <ul> 1249 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1250 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1251 * </ul> 1252 */ 1253 public void remove (String string) { 1254 checkWidget(); 1255 // SWT extension: allow null for zero length string 1256 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1257 list.remove (string); 1258 } 1259 /** 1260 * Removes all of the items from the receiver's list and clear the 1261 * contents of receiver's text field. 1262 * <p> 1263 * @exception SWTException <ul> 1264 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1265 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1266 * </ul> 1267 */ 1268 public void removeAll () { 1269 checkWidget(); 1270 text.setText (""); //$NON-NLS-1$ 1271 list.removeAll (); 1272 } 1273 /** 1274 * Removes the listener from the collection of listeners who will 1275 * be notified when the receiver's text is modified. 1276 * 1277 * @param listener the listener which should no longer be notified 1278 * 1279 * @exception IllegalArgumentException <ul> 1280 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 1281 * </ul> 1282 * @exception SWTException <ul> 1283 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1284 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1285 * </ul> 1286 * 1287 * @see ModifyListener 1288 * @see #addModifyListener 1289 */ 1290 public void removeModifyListener (ModifyListener listener) { 1291 checkWidget(); 1292 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1293 removeListener(SWT.Modify, listener); 1294 } 1295 /** 1296 * Removes the listener from the collection of listeners who will 1297 * be notified when the user changes the receiver's selection. 1298 * 1299 * @param listener the listener which should no longer be notified 1300 * 1301 * @exception IllegalArgumentException <ul> 1302 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 1303 * </ul> 1304 * @exception SWTException <ul> 1305 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1306 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1307 * </ul> 1308 * 1309 * @see SelectionListener 1310 * @see #addSelectionListener 1311 */ 1312 public void removeSelectionListener (SelectionListener listener) { 1313 checkWidget(); 1314 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1315 removeListener(SWT.Selection, listener); 1316 removeListener(SWT.DefaultSelection,listener); 1317 } 1318 /** 1319 * Removes the listener from the collection of listeners who will 1320 * be notified when the control is verified. 1321 * 1322 * @param listener the listener which should no longer be notified 1323 * 1324 * @exception IllegalArgumentException <ul> 1325 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 1326 * </ul> 1327 * @exception SWTException <ul> 1328 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1329 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1330 * </ul> 1331 * 1332 * @see VerifyListener 1333 * @see #addVerifyListener 1334 * 1335 * @since 3.3 1336 */ 1337 public void removeVerifyListener (VerifyListener listener) { 1338 checkWidget(); 1339 if (listener is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1340 removeListener(SWT.Verify, listener); 1341 } 1342 /** 1343 * Selects the item at the given zero-relative index in the receiver's 1344 * list. If the item at the index was already selected, it remains 1345 * selected. Indices that are out of range are ignored. 1346 * 1347 * @param index the index of the item to select 1348 * 1349 * @exception SWTException <ul> 1350 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1351 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1352 * </ul> 1353 */ 1354 public void select (int index) { 1355 checkWidget(); 1356 if (index is -1) { 1357 list.deselectAll (); 1358 text.setText (""); //$NON-NLS-1$ 1359 return; 1360 } 1361 if (0 <= index && index < list.getItemCount()) { 1362 if (index !is getSelectionIndex()) { 1363 text.setText (list.getItem (index)); 1364 text.selectAll (); 1365 list.select (index); 1366 list.showSelection (); 1367 } 1368 } 1369 } 1370 public override void setBackground (Color color) { 1371 super.setBackground(color); 1372 background = color; 1373 if (text !is null) text.setBackground(color); 1374 if (list !is null) list.setBackground(color); 1375 if (arrow !is null) arrow.setBackground(color); 1376 } 1377 /** 1378 * Sets the editable state. 1379 * 1380 * @param editable the new editable state 1381 * 1382 * @exception SWTException <ul> 1383 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1384 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1385 * </ul> 1386 * 1387 * @since 3.0 1388 */ 1389 public void setEditable (bool editable) { 1390 checkWidget (); 1391 text.setEditable(editable); 1392 } 1393 public override void setEnabled (bool enabled) { 1394 super.setEnabled(enabled); 1395 if (popup !is null) popup.setVisible (false); 1396 if (text !is null) text.setEnabled(enabled); 1397 if (arrow !is null) arrow.setEnabled(enabled); 1398 } 1399 public override bool setFocus () { 1400 checkWidget(); 1401 if (!isEnabled () || !isVisible ()) return false; 1402 if (isFocusControl ()) return true; 1403 return text.setFocus (); 1404 } 1405 public override void setFont (Font font) { 1406 super.setFont (font); 1407 this.font = font; 1408 text.setFont (font); 1409 list.setFont (font); 1410 internalLayout (true); 1411 } 1412 public override void setForeground (Color color) { 1413 super.setForeground(color); 1414 foreground = color; 1415 if (text !is null) text.setForeground(color); 1416 if (list !is null) list.setForeground(color); 1417 if (arrow !is null) arrow.setForeground(color); 1418 } 1419 /** 1420 * Sets the text of the item in the receiver's list at the given 1421 * zero-relative index to the string argument. This is equivalent 1422 * to <code>remove</code>'ing the old item at the index, and then 1423 * <code>add</code>'ing the new item at that index. 1424 * 1425 * @param index the index for the item 1426 * @param string the new text for the item 1427 * 1428 * @exception IllegalArgumentException <ul> 1429 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> 1430 * </ul> 1431 * @exception SWTException <ul> 1432 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1433 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1434 * </ul> 1435 */ 1436 public void setItem (int index, String string) { 1437 checkWidget(); 1438 list.setItem (index, string); 1439 } 1440 /** 1441 * Sets the receiver's list to be the given array of items. 1442 * 1443 * @param items the array of items 1444 * 1445 * @exception IllegalArgumentException <ul> 1446 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li> 1447 * </ul> 1448 * @exception SWTException <ul> 1449 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1450 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1451 * </ul> 1452 */ 1453 public void setItems (String [] items) { 1454 checkWidget (); 1455 list.setItems (items); 1456 if (!text.getEditable ()) text.setText (""); //$NON-NLS-1$ 1457 } 1458 /** 1459 * Sets the layout which is associated with the receiver to be 1460 * the argument which may be null. 1461 * <p> 1462 * Note: No Layout can be set on this Control because it already 1463 * manages the size and position of its children. 1464 * </p> 1465 * 1466 * @param layout the receiver's new layout or null 1467 * 1468 * @exception SWTException <ul> 1469 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1470 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1471 * </ul> 1472 */ 1473 public override void setLayout (Layout layout) { 1474 checkWidget (); 1475 return; 1476 } 1477 /** 1478 * Marks the receiver's list as visible if the argument is <code>true</code>, 1479 * and marks it invisible otherwise. 1480 * <p> 1481 * If one of the receiver's ancestors is not visible or some 1482 * other condition makes the receiver not visible, marking 1483 * it visible may not actually cause it to be displayed. 1484 * </p> 1485 * 1486 * @param visible the new visibility state 1487 * 1488 * @exception SWTException <ul> 1489 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1490 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1491 * </ul> 1492 * 1493 * @since 3.4 1494 */ 1495 public void setListVisible (bool visible) { 1496 checkWidget (); 1497 dropDown(visible); 1498 } 1499 public override void setMenu(Menu menu) { 1500 text.setMenu(menu); 1501 } 1502 /** 1503 * Sets the selection in the receiver's text field to the 1504 * range specified by the argument whose x coordinate is the 1505 * start of the selection and whose y coordinate is the end 1506 * of the selection. 1507 * 1508 * @param selection a point representing the new selection start and end 1509 * 1510 * @exception IllegalArgumentException <ul> 1511 * <li>ERROR_NULL_ARGUMENT - if the point is null</li> 1512 * </ul> 1513 * @exception SWTException <ul> 1514 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1515 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1516 * </ul> 1517 */ 1518 public void setSelection (Point selection) { 1519 checkWidget(); 1520 if (selection is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1521 text.setSelection (selection.x, selection.y); 1522 } 1523 1524 /** 1525 * Sets the contents of the receiver's text field to the 1526 * given string. 1527 * <p> 1528 * Note: The text field in a <code>Combo</code> is typically 1529 * only capable of displaying a single line of text. Thus, 1530 * setting the text to a string containing line breaks or 1531 * other special characters will probably cause it to 1532 * display incorrectly. 1533 * </p> 1534 * 1535 * @param string the new text 1536 * 1537 * @exception SWTException <ul> 1538 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1539 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1540 * </ul> 1541 */ 1542 public void setText (String string) { 1543 checkWidget(); 1544 // SWT extension: allow null for zero length string 1545 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1546 int index = list.indexOf (string); 1547 if (index is -1) { 1548 list.deselectAll (); 1549 text.setText (string); 1550 return; 1551 } 1552 text.setText (string); 1553 text.selectAll (); 1554 list.setSelection (index); 1555 list.showSelection (); 1556 } 1557 /** 1558 * Sets the maximum number of characters that the receiver's 1559 * text field is capable of holding to be the argument. 1560 * 1561 * @param limit new text limit 1562 * 1563 * @exception IllegalArgumentException <ul> 1564 * <li>ERROR_CANNOT_BE_ZERO - if the limit is zero</li> 1565 * </ul> 1566 * @exception SWTException <ul> 1567 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1568 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1569 * </ul> 1570 */ 1571 public void setTextLimit (int limit) { 1572 checkWidget(); 1573 text.setTextLimit (limit); 1574 } 1575 1576 public override void setToolTipText (String string) { 1577 checkWidget(); 1578 super.setToolTipText(string); 1579 arrow.setToolTipText (string); 1580 text.setToolTipText (string); 1581 } 1582 1583 public override void setVisible (bool visible) { 1584 super.setVisible(visible); 1585 /* 1586 * At this point the widget may have been disposed in a FocusOut event. 1587 * If so then do not continue. 1588 */ 1589 if (isDisposed ()) return; 1590 // TEMPORARY CODE 1591 if (popup is null || popup.isDisposed ()) return; 1592 if (!visible) popup.setVisible (false); 1593 } 1594 /** 1595 * Sets the number of items that are visible in the drop 1596 * down portion of the receiver's list. 1597 * 1598 * @param count the new number of items to be visible 1599 * 1600 * @exception SWTException <ul> 1601 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1602 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1603 * </ul> 1604 * 1605 * @since 3.0 1606 */ 1607 public void setVisibleItemCount (int count) { 1608 checkWidget (); 1609 if (count < 0) return; 1610 visibleItemCount = count; 1611 } 1612 String stripMnemonic (String string) { 1613 int index = 0; 1614 int length_ = cast(int)/*64bit*/string.length; 1615 do { 1616 while ((index < length_) && (string[index] !is '&')) index++; 1617 if (++index >= length_) return string; 1618 if (string[index] !is '&') { 1619 return string[0 .. index-1] ~ string[index .. length_]; 1620 } 1621 index++; 1622 } while (index < length_); 1623 return string; 1624 } 1625 void textEvent (Event event) { 1626 switch (event.type) { 1627 case SWT.FocusIn: { 1628 handleFocus (SWT.FocusIn); 1629 break; 1630 } 1631 case SWT.DefaultSelection: { 1632 dropDown (false); 1633 Event e = new Event (); 1634 e.time = event.time; 1635 e.stateMask = event.stateMask; 1636 notifyListeners (SWT.DefaultSelection, e); 1637 break; 1638 } 1639 case SWT.KeyDown: { 1640 Event keyEvent = new Event (); 1641 keyEvent.time = event.time; 1642 keyEvent.character = event.character; 1643 keyEvent.keyCode = event.keyCode; 1644 keyEvent.stateMask = event.stateMask; 1645 notifyListeners (SWT.KeyDown, keyEvent); 1646 if (isDisposed ()) break; 1647 event.doit = keyEvent.doit; 1648 if (!event.doit) break; 1649 if (event.keyCode is SWT.ARROW_UP || event.keyCode is SWT.ARROW_DOWN) { 1650 event.doit = false; 1651 if ((event.stateMask & SWT.ALT) !is 0) { 1652 bool dropped = isDropped (); 1653 text.selectAll (); 1654 if (!dropped) setFocus (); 1655 dropDown (!dropped); 1656 break; 1657 } 1658 1659 int oldIndex = getSelectionIndex (); 1660 if (event.keyCode is SWT.ARROW_UP) { 1661 select (Math.max (oldIndex - 1, 0)); 1662 } else { 1663 select (Math.min (oldIndex + 1, getItemCount () - 1)); 1664 } 1665 if (oldIndex !is getSelectionIndex ()) { 1666 Event e = new Event(); 1667 e.time = event.time; 1668 e.stateMask = event.stateMask; 1669 notifyListeners (SWT.Selection, e); 1670 } 1671 if (isDisposed ()) break; 1672 } 1673 1674 // Further work : Need to add support for incremental search in 1675 // pop up list as characters typed in text widget 1676 break; 1677 } 1678 case SWT.KeyUp: { 1679 Event e = new Event (); 1680 e.time = event.time; 1681 e.character = event.character; 1682 e.keyCode = event.keyCode; 1683 e.stateMask = event.stateMask; 1684 notifyListeners (SWT.KeyUp, e); 1685 event.doit = e.doit; 1686 break; 1687 } 1688 case SWT.MenuDetect: { 1689 Event e = new Event (); 1690 e.time = event.time; 1691 notifyListeners (SWT.MenuDetect, e); 1692 break; 1693 } 1694 case SWT.Modify: { 1695 list.deselectAll (); 1696 Event e = new Event (); 1697 e.time = event.time; 1698 notifyListeners (SWT.Modify, e); 1699 break; 1700 } 1701 case SWT.MouseDown: { 1702 Event mouseEvent = new Event (); 1703 mouseEvent.button = event.button; 1704 mouseEvent.count = event.count; 1705 mouseEvent.stateMask = event.stateMask; 1706 mouseEvent.time = event.time; 1707 mouseEvent.x = event.x; mouseEvent.y = event.y; 1708 notifyListeners (SWT.MouseDown, mouseEvent); 1709 if (isDisposed ()) break; 1710 event.doit = mouseEvent.doit; 1711 if (!event.doit) break; 1712 if (event.button !is 1) return; 1713 if (text.getEditable ()) return; 1714 bool dropped = isDropped (); 1715 text.selectAll (); 1716 if (!dropped) setFocus (); 1717 dropDown (!dropped); 1718 break; 1719 } 1720 case SWT.MouseUp: { 1721 Event mouseEvent = new Event (); 1722 mouseEvent.button = event.button; 1723 mouseEvent.count = event.count; 1724 mouseEvent.stateMask = event.stateMask; 1725 mouseEvent.time = event.time; 1726 mouseEvent.x = event.x; mouseEvent.y = event.y; 1727 notifyListeners (SWT.MouseUp, mouseEvent); 1728 if (isDisposed ()) break; 1729 event.doit = mouseEvent.doit; 1730 if (!event.doit) break; 1731 if (event.button !is 1) return; 1732 if (text.getEditable ()) return; 1733 text.selectAll (); 1734 break; 1735 } 1736 case SWT.MouseDoubleClick: { 1737 Event mouseEvent = new Event (); 1738 mouseEvent.button = event.button; 1739 mouseEvent.count = event.count; 1740 mouseEvent.stateMask = event.stateMask; 1741 mouseEvent.time = event.time; 1742 mouseEvent.x = event.x; mouseEvent.y = event.y; 1743 notifyListeners (SWT.MouseDoubleClick, mouseEvent); 1744 break; 1745 } 1746 case SWT.MouseWheel: { 1747 Event keyEvent = new Event (); 1748 keyEvent.time = event.time; 1749 keyEvent.keyCode = event.count > 0 ? SWT.ARROW_UP : SWT.ARROW_DOWN; 1750 keyEvent.stateMask = event.stateMask; 1751 notifyListeners (SWT.KeyDown, keyEvent); 1752 if (isDisposed ()) break; 1753 event.doit = keyEvent.doit; 1754 if (!event.doit) break; 1755 if (event.count !is 0) { 1756 event.doit = false; 1757 int oldIndex = getSelectionIndex (); 1758 if (event.count > 0) { 1759 select (Math.max (oldIndex - 1, 0)); 1760 } else { 1761 select (Math.min (oldIndex + 1, getItemCount () - 1)); 1762 } 1763 if (oldIndex !is getSelectionIndex ()) { 1764 Event e = new Event(); 1765 e.time = event.time; 1766 e.stateMask = event.stateMask; 1767 notifyListeners (SWT.Selection, e); 1768 } 1769 if (isDisposed ()) break; 1770 } 1771 break; 1772 } 1773 case SWT.Traverse: { 1774 switch (event.detail) { 1775 case SWT.TRAVERSE_ARROW_PREVIOUS: 1776 case SWT.TRAVERSE_ARROW_NEXT: 1777 // The enter causes default selection and 1778 // the arrow keys are used to manipulate the list contents so 1779 // do not use them for traversal. 1780 event.doit = false; 1781 break; 1782 case SWT.TRAVERSE_TAB_PREVIOUS: 1783 event.doit = traverse(SWT.TRAVERSE_TAB_PREVIOUS); 1784 event.detail = SWT.TRAVERSE_NONE; 1785 return; 1786 default: 1787 } 1788 Event e = new Event (); 1789 e.time = event.time; 1790 e.detail = event.detail; 1791 e.doit = event.doit; 1792 e.character = event.character; 1793 e.keyCode = event.keyCode; 1794 notifyListeners (SWT.Traverse, e); 1795 event.doit = e.doit; 1796 event.detail = e.detail; 1797 break; 1798 } 1799 case SWT.Verify: { 1800 Event e = new Event (); 1801 e.text = event.text; 1802 e.start = event.start; 1803 e.end = event.end; 1804 e.character = event.character; 1805 e.keyCode = event.keyCode; 1806 e.stateMask = event.stateMask; 1807 notifyListeners (SWT.Verify, e); 1808 event.doit = e.doit; 1809 break; 1810 } 1811 default: 1812 } 1813 } 1814 }