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 }