Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/swt/widgets/TabFolder.java


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