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.widgets.TabFolder; 14 15 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.SWTException; 19 import org.eclipse.swt.events.SelectionEvent; 20 import org.eclipse.swt.events.SelectionListener; 21 import org.eclipse.swt.graphics.Point; 22 import org.eclipse.swt.graphics.Rectangle; 23 import org.eclipse.swt.internal.gtk.OS; 24 import org.eclipse.swt.widgets.Composite; 25 import org.eclipse.swt.widgets.TabItem; 26 import org.eclipse.swt.widgets.ImageList; 27 import org.eclipse.swt.widgets.Control; 28 import org.eclipse.swt.widgets.TypedListener; 29 import org.eclipse.swt.widgets.Event; 30 import java.lang.all; 31 32 /** 33 * Instances of this class implement the notebook user interface 34 * metaphor. It allows the user to select a notebook page from 35 * set of pages. 36 * <p> 37 * The item children that may be added to instances of this class 38 * must be of type <code>TabItem</code>. 39 * <code>Control</code> children are created and then set into a 40 * tab item using <code>TabItem#setControl</code>. 41 * </p><p> 42 * Note that although this class is a subclass of <code>Composite</code>, 43 * it does not make sense to set a layout on it. 44 * </p><p> 45 * <dl> 46 * <dt><b>Styles:</b></dt> 47 * <dd>TOP, BOTTOM</dd> 48 * <dt><b>Events:</b></dt> 49 * <dd>Selection</dd> 50 * </dl> 51 * <p> 52 * Note: Only one of the styles TOP and BOTTOM may be specified. 53 * </p><p> 54 * IMPORTANT: This class is <em>not</em> intended to be subclassed. 55 * </p> 56 * 57 * @see <a href="http://www.eclipse.org/swt/snippets/#tabfolder">TabFolder, TabItem snippets</a> 58 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> 59 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 60 */ 61 public class TabFolder : Composite { 62 63 alias Composite.computeSize computeSize; 64 alias Composite.createHandle createHandle; 65 alias Composite.mnemonicHit mnemonicHit; 66 alias Composite.mnemonicMatch mnemonicMatch; 67 alias Composite.setBounds setBounds; 68 alias Composite.setForegroundColor setForegroundColor; 69 70 TabItem [] items; 71 ImageList imageList; 72 73 /** 74 * Constructs a new instance of this class given its parent 75 * and a style value describing its behavior and appearance. 76 * <p> 77 * The style value is either one of the style constants defined in 78 * class <code>SWT</code> which is applicable to instances of this 79 * class, or must be built by <em>bitwise OR</em>'ing together 80 * (that is, using the <code>int</code> "|" operator) two or more 81 * of those <code>SWT</code> style constants. The class description 82 * lists the style constants that are applicable to the class. 83 * Style bits are also inherited from superclasses. 84 * </p> 85 * 86 * @param parent a composite control which will be the parent of the new instance (cannot be null) 87 * @param style the style of control to construct 88 * 89 * @exception IllegalArgumentException <ul> 90 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> 91 * </ul> 92 * @exception SWTException <ul> 93 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> 94 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> 95 * </ul> 96 * 97 * @see SWT 98 * @see Widget#checkSubclass 99 * @see Widget#getStyle 100 */ 101 public this (Composite parent, int style) { 102 super (parent, checkStyle (style)); 103 } 104 105 static int checkStyle (int style) { 106 style = checkBits (style, SWT.TOP, SWT.BOTTOM, 0, 0, 0, 0); 107 /* 108 * Even though it is legal to create this widget 109 * with scroll bars, they serve no useful purpose 110 * because they do not automatically scroll the 111 * widget's client area. The fix is to clear 112 * the SWT style. 113 */ 114 return style & ~(SWT.H_SCROLL | SWT.V_SCROLL); 115 } 116 117 protected override void checkSubclass () { 118 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); 119 } 120 121 override GtkStyle* childStyle () { 122 auto rcStyle = OS.gtk_widget_get_modifier_style (handle); 123 if ((OS.gtk_rc_style_get_color_flags (rcStyle, 0) & OS.GTK_RC_BG) !is 0) return null; 124 OS.gtk_widget_realize (handle); 125 return OS.gtk_widget_get_style (handle); 126 } 127 128 /** 129 * Adds the listener to the collection of listeners who will 130 * be notified when the user changes the receiver's selection, by sending 131 * it one of the messages defined in the <code>SelectionListener</code> 132 * interface. 133 * <p> 134 * When <code>widgetSelected</code> is called, the item field of the event object is valid. 135 * <code>widgetDefaultSelected</code> is not called. 136 * </p> 137 * 138 * @param listener the listener which should be notified when the user changes the receiver's selection 139 * 140 * @exception IllegalArgumentException <ul> 141 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 142 * </ul> 143 * @exception SWTException <ul> 144 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 145 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 146 * </ul> 147 * 148 * @see SelectionListener 149 * @see #removeSelectionListener 150 * @see SelectionEvent 151 */ 152 public void addSelectionListener(SelectionListener listener) { 153 checkWidget (); 154 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); 155 TypedListener typedListener = new TypedListener(listener); 156 addListener(SWT.Selection,typedListener); 157 addListener(SWT.DefaultSelection,typedListener); 158 } 159 160 override GtkWidget* clientHandle () { 161 int index = OS.gtk_notebook_get_current_page (handle); 162 if (index !is -1 && items [index] !is null) { 163 return items [index].pageHandle; 164 } 165 return handle; 166 } 167 168 public override Point computeSize (int wHint, int hHint, bool changed) { 169 checkWidget (); 170 Point size = super.computeSize (wHint, hHint, changed); 171 if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0; 172 if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0; 173 bool scrollable = cast(bool)OS.gtk_notebook_get_scrollable (handle); 174 OS.gtk_notebook_set_scrollable (handle, false); 175 Point notebookSize = computeNativeSize (handle, wHint, hHint, changed); 176 OS.gtk_notebook_set_scrollable (handle, scrollable); 177 size.x = Math.max (notebookSize.x, size.x); 178 size.y = Math.max (notebookSize.y, size.y); 179 return size; 180 } 181 182 public override Rectangle computeTrim (int x, int y, int width, int height) { 183 checkWidget(); 184 forceResize (); 185 auto clientHandle = clientHandle (); 186 int clientX = OS.GTK_WIDGET_X (clientHandle); 187 int clientY = OS.GTK_WIDGET_Y (clientHandle); 188 x -= clientX; 189 y -= clientY; 190 width += clientX + clientX; 191 if ((style & SWT.BOTTOM) !is 0) { 192 int parentHeight = OS.GTK_WIDGET_HEIGHT (handle); 193 int clientHeight = OS.GTK_WIDGET_HEIGHT (clientHandle); 194 height += parentHeight - clientHeight; 195 } else { 196 height += clientX + clientY; 197 } 198 return new Rectangle (x, y, width, height); 199 } 200 201 override void createHandle (int index) { 202 state |= HANDLE; 203 fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null); 204 if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES); 205 OS.gtk_fixed_set_has_window (fixedHandle, true); 206 handle = cast(GtkWidget*)OS.gtk_notebook_new (); 207 if (handle is null) error (SWT.ERROR_NO_HANDLES); 208 OS.gtk_container_add (fixedHandle, handle); 209 OS.gtk_notebook_set_scrollable (handle, true); 210 OS.gtk_notebook_set_show_tabs (handle, true); 211 if ((style & SWT.BOTTOM) !is 0) { 212 OS.gtk_notebook_set_tab_pos (handle, OS.GTK_POS_BOTTOM); 213 } 214 } 215 216 override void createWidget (int index) { 217 super.createWidget(index); 218 items = new TabItem [4]; 219 } 220 221 void createItem (TabItem item, int index) { 222 auto list = OS.gtk_container_get_children (handle); 223 int itemCount = 0; 224 if (list !is null) { 225 itemCount = OS.g_list_length (list); 226 OS.g_list_free (list); 227 } 228 if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE); 229 if (itemCount is items.length) { 230 TabItem [] newItems = new TabItem [items.length + 4]; 231 System.arraycopy (items, 0, newItems, 0, items.length); 232 items = newItems; 233 } 234 auto boxHandle = OS.gtk_hbox_new (false, 0); 235 if (boxHandle is null) error (SWT.ERROR_NO_HANDLES); 236 auto labelHandle = OS.gtk_label_new_with_mnemonic (null); 237 if (labelHandle is null) error (SWT.ERROR_NO_HANDLES); 238 auto imageHandle = OS.gtk_image_new (); 239 if (imageHandle is null) error (SWT.ERROR_NO_HANDLES); 240 OS.gtk_container_add (boxHandle, imageHandle); 241 OS.gtk_container_add (boxHandle, labelHandle); 242 auto pageHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null); 243 if (pageHandle is null) error (SWT.ERROR_NO_HANDLES); 244 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 245 OS.gtk_notebook_insert_page (handle, pageHandle, boxHandle, index); 246 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 247 OS.gtk_widget_show (boxHandle); 248 OS.gtk_widget_show (labelHandle); 249 OS.gtk_widget_show (pageHandle); 250 item.state |= HANDLE; 251 item.handle = boxHandle; 252 item.labelHandle = labelHandle; 253 item.imageHandle = imageHandle; 254 item.pageHandle = pageHandle; 255 System.arraycopy (items, index, items, index + 1, itemCount++ - index); 256 items [index] = item; 257 if ((state & FOREGROUND) !is 0) { 258 item.setForegroundColor (getForegroundColor()); 259 } 260 if ((state & FONT) !is 0) { 261 item.setFontDescription (getFontDescription()); 262 } 263 if (itemCount is 1) { 264 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 265 OS.gtk_notebook_set_current_page (handle, 0); 266 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 267 Event event = new Event(); 268 event.item = items[0]; 269 sendEvent (SWT.Selection, event); 270 // the widget could be destroyed at this point 271 } 272 } 273 274 void destroyItem (TabItem item) { 275 int index = 0; 276 int itemCount = getItemCount(); 277 while (index < itemCount) { 278 if (items [index] is item) break; 279 index++; 280 } 281 if (index is itemCount) error (SWT.ERROR_ITEM_NOT_REMOVED); 282 int oldIndex = OS.gtk_notebook_get_current_page (handle); 283 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 284 OS.gtk_notebook_remove_page (handle, index); 285 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 286 System.arraycopy (items, index + 1, items, index, --itemCount - index); 287 items [itemCount] = null; 288 if (index is oldIndex) { 289 int newIndex = OS.gtk_notebook_get_current_page (handle); 290 if (newIndex !is -1) { 291 Control control = items [newIndex].getControl (); 292 if (control !is null && !control.isDisposed ()) { 293 control.setBounds (getClientArea()); 294 control.setVisible (true); 295 } 296 Event event = new Event (); 297 event.item = items [newIndex]; 298 sendEvent (SWT.Selection, event); 299 // the widget could be destroyed at this point 300 } 301 } 302 } 303 304 override GtkWidget* eventHandle () { 305 return handle; 306 } 307 308 /** 309 * Returns the item at the given, zero-relative index in the 310 * receiver. Throws an exception if the index is out of range. 311 * 312 * @param index the index of the item to return 313 * @return the item at the given index 314 * 315 * @exception IllegalArgumentException <ul> 316 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> 317 * </ul> 318 * @exception SWTException <ul> 319 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 320 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 321 * </ul> 322 */ 323 public TabItem getItem (int index) { 324 checkWidget(); 325 if (!(0 <= index && index < getItemCount())) error (SWT.ERROR_INVALID_RANGE); 326 auto list = OS.gtk_container_get_children (handle); 327 if (list is null) error (SWT.ERROR_CANNOT_GET_ITEM); 328 int itemCount = OS.g_list_length (list); 329 OS.g_list_free (list); 330 if (!(0 <= index && index < itemCount)) error (SWT.ERROR_CANNOT_GET_ITEM); 331 return items [index]; 332 } 333 334 /** 335 * Returns the tab item at the given point in the receiver 336 * or null if no such item exists. The point is in the 337 * coordinate system of the receiver. 338 * 339 * @param point the point used to locate the item 340 * @return the tab item at the given point, or null if the point is not in a tab item 341 * 342 * @exception IllegalArgumentException <ul> 343 * <li>ERROR_NULL_ARGUMENT - if the point is null</li> 344 * </ul> 345 * @exception SWTException <ul> 346 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 347 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 348 * </ul> 349 * 350 * @since 3.4 351 */ 352 public TabItem getItem(Point point) { 353 checkWidget(); 354 if (point is null) error (SWT.ERROR_NULL_ARGUMENT); 355 auto list = OS.gtk_container_get_children (handle); 356 if (list is null) return null; 357 int itemCount = OS.g_list_length (list); 358 OS.g_list_free (list); 359 for (int i = 0; i < itemCount; i++) { 360 TabItem item = items[i]; 361 Rectangle rect = item.getBounds(); 362 if (rect.contains(point)) return item; 363 } 364 return null; 365 } 366 367 /** 368 * Returns the number of items contained in the receiver. 369 * 370 * @return the number of items 371 * 372 * @exception SWTException <ul> 373 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 374 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 375 * </ul> 376 */ 377 public int getItemCount () { 378 checkWidget(); 379 auto list = OS.gtk_container_get_children (handle); 380 if (list is null) return 0; 381 int itemCount = OS.g_list_length (list); 382 OS.g_list_free (list); 383 return itemCount; 384 } 385 386 /** 387 * Returns an array of <code>TabItem</code>s which are the items 388 * in the receiver. 389 * <p> 390 * Note: This is not the actual structure used by the receiver 391 * to maintain its list of items, so modifying the array will 392 * not affect the receiver. 393 * </p> 394 * 395 * @return the items in the receiver 396 * 397 * @exception SWTException <ul> 398 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 399 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 400 * </ul> 401 */ 402 public TabItem [] getItems () { 403 checkWidget(); 404 int count = getItemCount (); 405 TabItem [] result = new TabItem [count]; 406 System.arraycopy (items, 0, result, 0, count); 407 return result; 408 } 409 410 /** 411 * Returns an array of <code>TabItem</code>s that are currently 412 * selected in the receiver. An empty array indicates that no 413 * items are selected. 414 * <p> 415 * Note: This is not the actual structure used by the receiver 416 * to maintain its selection, so modifying the array will 417 * not affect the receiver. 418 * </p> 419 * @return an array representing the selection 420 * 421 * @exception SWTException <ul> 422 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 423 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 424 * </ul> 425 */ 426 public TabItem [] getSelection () { 427 checkWidget(); 428 int index = OS.gtk_notebook_get_current_page (handle); 429 if (index is -1) return new TabItem [0]; 430 return [ items [index] ]; 431 } 432 433 /** 434 * Returns the zero-relative index of the item which is currently 435 * selected in the receiver, or -1 if no item is selected. 436 * 437 * @return the index of the selected item 438 * 439 * @exception SWTException <ul> 440 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 441 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 442 * </ul> 443 */ 444 public int getSelectionIndex () { 445 checkWidget(); 446 return OS.gtk_notebook_get_current_page (handle); 447 } 448 449 override int gtk_focus (GtkWidget* widget, ptrdiff_t directionType) { 450 return 0; 451 } 452 453 override int gtk_switch_page (GtkWidget* widget, ptrdiff_t page, ptrdiff_t page_num) { 454 int index = OS.gtk_notebook_get_current_page (handle); 455 if (index !is -1) { 456 Control control = items [index].getControl (); 457 if (control !is null && !control.isDisposed ()) { 458 control.setVisible (false); 459 } 460 } 461 TabItem item = items [page_num]; 462 Control control = item.getControl (); 463 if (control !is null && !control.isDisposed ()) { 464 control.setBounds(getClientArea()); 465 control.setVisible (true); 466 } 467 Event event = new Event(); 468 event.item = item; 469 postEvent(SWT.Selection, event); 470 return 0; 471 } 472 473 override void hookEvents () { 474 super.hookEvents (); 475 OS.g_signal_connect_closure (handle, OS.switch_page.ptr, display.closures [SWITCH_PAGE], false); 476 } 477 478 /** 479 * Searches the receiver's list starting at the first item 480 * (index 0) until an item is found that is equal to the 481 * argument, and returns the index of that item. If no item 482 * is found, returns -1. 483 * 484 * @param item the search item 485 * @return the index of the item 486 * 487 * @exception IllegalArgumentException <ul> 488 * <li>ERROR_NULL_ARGUMENT - if the item is null</li> 489 * </ul> 490 * @exception SWTException <ul> 491 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 492 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 493 * </ul> 494 */ 495 public int indexOf (TabItem item) { 496 checkWidget(); 497 if (item is null) error (SWT.ERROR_NULL_ARGUMENT); 498 auto list = OS.gtk_container_get_children (handle); 499 if (list is null) return -1; 500 int count = OS.g_list_length (list); 501 OS.g_list_free (list); 502 for (int i=0; i<count; i++) { 503 if (items [i] is item) return i; 504 } 505 return -1; 506 } 507 508 override Point minimumSize (int wHint, int hHint, bool flushCache) { 509 Control [] children = _getChildren (); 510 int width = 0, height = 0; 511 for (int i=0; i<children.length; i++) { 512 Control child = children [i]; 513 int index = 0; 514 int count = 0; 515 auto list = OS.gtk_container_get_children (handle); 516 if (list !is null) { 517 count = OS.g_list_length (list); 518 OS.g_list_free (list); 519 } 520 while (index < count) { 521 if (items [index].control is child) break; 522 index++; 523 } 524 if (index is count) { 525 Rectangle rect = child.getBounds (); 526 width = Math.max (width, rect.x + rect.width); 527 height = Math.max (height, rect.y + rect.height); 528 } else { 529 Point size = child.computeSize (wHint, hHint, flushCache); 530 width = Math.max (width, size.x); 531 height = Math.max (height, size.y); 532 } 533 } 534 return new Point (width, height); 535 } 536 537 override bool mnemonicHit (wchar key) { 538 int itemCount = getItemCount (); 539 for (int i=0; i<itemCount; i++) { 540 auto labelHandle = items [i].labelHandle; 541 if (labelHandle !is null && mnemonicHit (labelHandle, key)) return true; 542 } 543 return false; 544 } 545 546 override bool mnemonicMatch (wchar key) { 547 int itemCount = getItemCount (); 548 for (int i=0; i<itemCount; i++) { 549 auto labelHandle = items [i].labelHandle; 550 if (labelHandle !is null && mnemonicHit (labelHandle, key)) return true; 551 } 552 return false; 553 } 554 555 override void releaseChildren (bool destroy) { 556 if (items !is null) { 557 for (int i=0; i<items.length; i++) { 558 TabItem item = items [i]; 559 if (item !is null && !item.isDisposed ()) { 560 item.release (false); 561 } 562 } 563 items = null; 564 } 565 super.releaseChildren (destroy); 566 } 567 568 override void releaseWidget () { 569 super.releaseWidget (); 570 if (imageList !is null) imageList.dispose (); 571 imageList = null; 572 } 573 574 override void removeControl (Control control) { 575 super.removeControl (control); 576 int count = getItemCount (); 577 for (int i=0; i<count; i++) { 578 TabItem item = items [i]; 579 if (item.control is control) item.setControl (null); 580 } 581 } 582 583 /** 584 * Removes the listener from the collection of listeners who will 585 * be notified when the user changes the receiver's selection. 586 * 587 * @param listener the listener which should no longer be notified 588 * 589 * @exception IllegalArgumentException <ul> 590 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 591 * </ul> 592 * @exception SWTException <ul> 593 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 594 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 595 * </ul> 596 * 597 * @see SelectionListener 598 * @see #addSelectionListener 599 */ 600 public void removeSelectionListener (SelectionListener listener) { 601 checkWidget (); 602 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT); 603 if (eventTable is null) return; 604 eventTable.unhook (SWT.Selection, listener); 605 eventTable.unhook (SWT.DefaultSelection,listener); 606 } 607 608 override int setBounds (int x, int y, int width, int height, bool move, bool resize) { 609 int result = super.setBounds (x, y, width, height, move, resize); 610 if ((result & RESIZED) !is 0) { 611 int index = getSelectionIndex (); 612 if (index !is -1) { 613 TabItem item = items [index]; 614 Control control = item.control; 615 if (control !is null && !control.isDisposed ()) { 616 control.setBounds (getClientArea ()); 617 } 618 } 619 } 620 return result; 621 } 622 623 override void setFontDescription (PangoFontDescription* font) { 624 super.setFontDescription (font); 625 TabItem [] items = getItems (); 626 for (int i = 0; i < items.length; i++) { 627 if (items[i] !is null) { 628 items[i].setFontDescription (font); 629 } 630 } 631 } 632 633 override void setForegroundColor (GdkColor* color) { 634 super.setForegroundColor (color); 635 TabItem [] items = getItems (); 636 for (int i = 0; i < items.length; i++) { 637 if (items[i] !is null) { 638 items[i].setForegroundColor (color); 639 } 640 } 641 } 642 643 /** 644 * Selects the item at the given zero-relative index in the receiver. 645 * If the item at the index was already selected, it remains selected. 646 * The current selection is first cleared, then the new items are 647 * selected. Indices that are out of range are ignored. 648 * 649 * @param index the index of the item to select 650 * 651 * @exception SWTException <ul> 652 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 653 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 654 * </ul> 655 */ 656 public void setSelection (int index) { 657 checkWidget (); 658 if (!(0 <= index && index < getItemCount ())) return; 659 setSelection (index, false); 660 } 661 662 void setSelection (int index, bool notify) { 663 if (index < 0) return; 664 int oldIndex = OS.gtk_notebook_get_current_page (handle); 665 if (oldIndex is index) return; 666 if (oldIndex !is -1) { 667 TabItem item = items [oldIndex]; 668 Control control = item.control; 669 if (control !is null && !control.isDisposed ()) { 670 control.setVisible (false); 671 } 672 } 673 OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 674 OS.gtk_notebook_set_current_page (handle, index); 675 OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udSWITCH_PAGE); 676 int newIndex = OS.gtk_notebook_get_current_page (handle); 677 if (newIndex !is -1) { 678 TabItem item = items [newIndex]; 679 Control control = item.control; 680 if (control !is null && !control.isDisposed ()) { 681 control.setBounds (getClientArea ()); 682 control.setVisible (true); 683 } 684 if (notify) { 685 Event event = new Event (); 686 event.item = item; 687 sendEvent (SWT.Selection, event); 688 } 689 } 690 } 691 692 /** 693 * Sets the receiver's selection to the given item. 694 * The current selected is first cleared, then the new item is 695 * selected. 696 * 697 * @param item the item to select 698 * 699 * @exception IllegalArgumentException <ul> 700 * <li>ERROR_NULL_ARGUMENT - if the item is null</li> 701 * </ul> 702 * @exception SWTException <ul> 703 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 704 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 705 * </ul> 706 * 707 * @since 3.2 708 */ 709 public void setSelection (TabItem item) { 710 if (item is null) error (SWT.ERROR_NULL_ARGUMENT); 711 setSelection( [item] ); 712 } 713 714 /** 715 * Sets the receiver's selection to be the given array of items. 716 * The current selected is first cleared, then the new items are 717 * selected. 718 * 719 * @param items the array of items 720 * 721 * @exception SWTException <ul> 722 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 723 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 724 * </ul> 725 */ 726 public void setSelection (TabItem [] items) { 727 checkWidget(); 728 // SWT extension: allow null for zero length string 729 //if (items is null) error (SWT.ERROR_NULL_ARGUMENT); 730 if (items.length is 0) { 731 setSelection (-1, false); 732 } else { 733 for (ptrdiff_t i=cast(ptrdiff_t) (items.length)-1; i>=0; --i) { 734 int index = indexOf (items [i]); 735 if (index !is -1) setSelection (index, false); 736 } 737 } 738 } 739 740 override bool traversePage (bool next) { 741 if (next) { 742 OS.gtk_notebook_next_page (handle); 743 } else { 744 OS.gtk_notebook_prev_page (handle); 745 } 746 return true; 747 } 748 749 }