comparison dwt/widgets/TabFolder.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 649b8e223d5a
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 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 *******************************************************************************/
11 module dwt.widgets.TabFolder;
12
13 import dwt.dwthelper.utils;
14
15
16 import dwt.DWT;
17 import dwt.DWTException;
18 import dwt.events.SelectionEvent;
19 import dwt.events.SelectionListener;
20 import dwt.graphics.Point;
21 import dwt.graphics.Rectangle;
22 import dwt.internal.cocoa.NSFont;
23 import dwt.internal.cocoa.NSPoint;
24 import dwt.internal.cocoa.NSRect;
25 import dwt.internal.cocoa.NSSize;
26 import dwt.internal.cocoa.NSTabView;
27 import dwt.internal.cocoa.NSTabViewItem;
28 import dwt.internal.cocoa.OS;
29 import dwt.internal.cocoa.SWTTabView;
30
31 /**
32 * Instances of this class implement the notebook user interface
33 * metaphor. It allows the user to select a notebook page from
34 * set of pages.
35 * <p>
36 * The item children that may be added to instances of this class
37 * must be of type <code>TabItem</code>.
38 * <code>Control</code> children are created and then set into a
39 * tab item using <code>TabItem#setControl</code>.
40 * </p><p>
41 * Note that although this class is a subclass of <code>Composite</code>,
42 * it does not make sense to set a layout on it.
43 * </p><p>
44 * <dl>
45 * <dt><b>Styles:</b></dt>
46 * <dd>TOP, BOTTOM</dd>
47 * <dt><b>Events:</b></dt>
48 * <dd>Selection</dd>
49 * </dl>
50 * <p>
51 * Note: Only one of the styles TOP and BOTTOM may be specified.
52 * </p><p>
53 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
54 * </p>
55 */
56 public class TabFolder extends Composite {
57 TabItem [] items;
58 int itemCount;
59
60 /**
61 * Constructs a new instance of this class given its parent
62 * and a style value describing its behavior and appearance.
63 * <p>
64 * The style value is either one of the style constants defined in
65 * class <code>DWT</code> which is applicable to instances of this
66 * class, or must be built by <em>bitwise OR</em>'ing together
67 * (that is, using the <code>int</code> "|" operator) two or more
68 * of those <code>DWT</code> style constants. The class description
69 * lists the style constants that are applicable to the class.
70 * Style bits are also inherited from superclasses.
71 * </p>
72 *
73 * @param parent a composite control which will be the parent of the new instance (cannot be null)
74 * @param style the style of control to construct
75 *
76 * @exception IllegalArgumentException <ul>
77 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
78 * </ul>
79 * @exception DWTException <ul>
80 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
81 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
82 * </ul>
83 *
84 * @see DWT
85 * @see Widget#checkSubclass
86 * @see Widget#getStyle
87 */
88 public TabFolder (Composite parent, int style) {
89 super (parent, checkStyle (style));
90 }
91
92 /**
93 * Adds the listener to the collection of listeners who will
94 * be notified when the user changes the receiver's selection, 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 when the user changes the receiver's selection
103 *
104 * @exception IllegalArgumentException <ul>
105 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
106 * </ul>
107 * @exception DWTException <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 is null) error (DWT.ERROR_NULL_ARGUMENT);
119 TypedListener typedListener = new TypedListener (listener);
120 addListener (DWT.Selection,typedListener);
121 addListener (DWT.DefaultSelection,typedListener);
122 }
123
124 static int checkStyle (int style) {
125 style = checkBits (style, DWT.TOP, DWT.BOTTOM, 0, 0, 0, 0);
126 /*
127 * Even though it is legal to create this widget
128 * with scroll bars, they serve no useful purpose
129 * because they do not automatically scroll the
130 * widget's client area. The fix is to clear
131 * the DWT style.
132 */
133 return style & ~(DWT.H_SCROLL | DWT.V_SCROLL);
134 }
135
136 protected void checkSubclass () {
137 if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
138 }
139
140 public Point computeSize (int wHint, int hHint, bool changed) {
141 Point size = super.computeSize (wHint, hHint, changed);
142 if (wHint is DWT.DEFAULT && items.length > 0) {
143 NSSize mimSize = ((NSTabView)view).minimumSize();
144 Rectangle trim = computeTrim (0, 0, (int)mimSize.width, 0);
145 size.x = Math.max (trim.width, size.x);
146 }
147 return size;
148 }
149
150 public Rectangle computeTrim (int x, int y, int width, int height) {
151 checkWidget ();
152 // CGRect oldBounds = new CGRect (), bounds = oldBounds;
153 // OS.HIViewGetFrame (handle, oldBounds);
154 // int MIN_SIZE = 100;
155 // if (oldBounds.width < MIN_SIZE || oldBounds.height < MIN_SIZE) {
156 // OS.HIViewSetDrawingEnabled (handle, false);
157 // bounds = new CGRect ();
158 // bounds.width = bounds.height = 100;
159 // OS.HIViewSetFrame (handle, bounds);
160 // }
161 // Rect client = new Rect ();
162 // OS.GetTabContentRect (handle, client);
163 // if (oldBounds.width < MIN_SIZE || oldBounds.height < MIN_SIZE) {
164 // OS.HIViewSetFrame (handle, oldBounds);
165 // OS.HIViewSetDrawingEnabled (handle, drawCount is 0);
166 // }
167 // x -= client.left;
168 // y -= client.top;
169 // width += (int) bounds.width - (client.right - client.left);
170 // height += (int) bounds.height - (client.bottom - client.top);
171 // Rect inset = getInset ();
172 // x -= inset.left;
173 // y -= inset.top;
174 // width += inset.left + inset.right;
175 // height += inset.top + inset.bottom;
176 // return new Rectangle (-client.left, -client.top, width, height);
177 return super.computeTrim(x, y, width, height);
178 }
179
180 void createHandle () {
181 SWTTabView widget = (SWTTabView)new SWTTabView().alloc();
182 widget.initWithFrame (new NSRect());
183 widget.setTag(jniRef);
184 widget.setDelegate(widget);
185 if ((style & DWT.BOTTOM) !is 0) {
186 widget.setTabViewType(OS.NSBottomTabsBezelBorder);
187 }
188 view = widget;
189 parent.contentView().addSubview_(view);
190 }
191
192 void createItem (TabItem item, int index) {
193 int count = itemCount;
194 if (!(0 <= index && index <= count)) error (DWT.ERROR_INVALID_RANGE);
195 if (count is items.length) {
196 TabItem [] newItems = new TabItem [items.length + 4];
197 System.arraycopy (items, 0, newItems, 0, items.length);
198 items = newItems;
199 }
200 System.arraycopy (items, index, items, index + 1, count - index);
201 items [index] = item;
202 itemCount++;
203 NSTabViewItem nsItem = (NSTabViewItem)new NSTabViewItem().alloc().init();
204 item.nsItem = nsItem;
205 ((NSTabView)view).insertTabViewItem(nsItem, index);
206 }
207
208 void createWidget () {
209 super.createWidget ();
210 items = new TabItem [4];
211 }
212
213 void destroyItem (TabItem item) {
214 int count = itemCount;
215 int index = 0;
216 while (index < count) {
217 if (items [index] is item) break;
218 index++;
219 }
220 if (index is count) return;
221 --count;
222 System.arraycopy (items, index + 1, items, index, count - index);
223 items [count] = null;
224 if (count is 0) {
225 items = new TabItem [4];
226 }
227 itemCount = count;
228 ((NSTabView)view).removeTabViewItem(item.nsItem);
229 }
230
231 public Rectangle getClientArea () {
232 checkWidget ();
233 NSRect rect = ((NSTabView)view).contentRect();
234 int x = Math.max (0, (int)rect.x);
235 int y = Math.max (0, (int)rect.y);
236 int width = Math.max (0, (int)rect.width);
237 int height = Math.max (0, (int)rect.height);
238 return new Rectangle (x, y, width, height);
239 }
240
241 /**
242 * Returns the item at the given, zero-relative index in the
243 * receiver. Throws an exception if the index is out of range.
244 *
245 * @param index the index of the item to return
246 * @return the item at the given index
247 *
248 * @exception IllegalArgumentException <ul>
249 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
250 * </ul>
251 * @exception DWTException <ul>
252 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
254 * </ul>
255 */
256 public TabItem getItem (int index) {
257 checkWidget ();
258 int count = itemCount;
259 if (!(0 <= index && index < count)) error (DWT.ERROR_INVALID_RANGE);
260 return items [index];
261 }
262
263 public TabItem getItem (Point point) {
264 checkWidget ();
265 if (point is null) error (DWT.ERROR_NULL_ARGUMENT);
266 NSPoint nsPoint = new NSPoint ();
267 nsPoint.x = point.x;
268 nsPoint.y = point.y;
269 NSTabView tabView = (NSTabView) view;
270 NSTabViewItem tabViewItem = tabView.tabViewItemAtPoint (nsPoint);
271 for (int i = 0; i < itemCount; i++) {
272 NSTabViewItem item = items[i].nsItem;
273 if (item.isEqual (tabViewItem)) {
274 return items [i];
275 }
276 }
277 return null;
278 }
279
280 /**
281 * Returns the number of items contained in the receiver.
282 *
283 * @return the number of items
284 *
285 * @exception DWTException <ul>
286 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
287 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
288 * </ul>
289 */
290 public int getItemCount () {
291 checkWidget ();
292 return itemCount;
293 }
294
295 /**
296 * Returns an array of <code>TabItem</code>s which are the items
297 * in the receiver.
298 * <p>
299 * Note: This is not the actual structure used by the receiver
300 * to maintain its list of items, so modifying the array will
301 * not affect the receiver.
302 * </p>
303 *
304 * @return the items in the receiver
305 *
306 * @exception DWTException <ul>
307 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
308 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
309 * </ul>
310 */
311 public TabItem [] getItems () {
312 checkWidget ();
313 int count = itemCount;
314 TabItem [] result = new TabItem [count];
315 System.arraycopy (items, 0, result, 0, count);
316 return result;
317 }
318
319 /**
320 * Returns an array of <code>TabItem</code>s that are currently
321 * selected in the receiver. An empty array indicates that no
322 * items are selected.
323 * <p>
324 * Note: This is not the actual structure used by the receiver
325 * to maintain its selection, so modifying the array will
326 * not affect the receiver.
327 * </p>
328 * @return an array representing the selection
329 *
330 * @exception DWTException <ul>
331 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
332 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
333 * </ul>
334 */
335 public TabItem [] getSelection () {
336 checkWidget ();
337 int index = getSelectionIndex ();
338 if (index is -1) return new TabItem [0];
339 return new TabItem [] {items [index]};
340 }
341
342 /**
343 * Returns the zero-relative index of the item which is currently
344 * selected in the receiver, or -1 if no item is selected.
345 *
346 * @return the index of the selected item
347 *
348 * @exception DWTException <ul>
349 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
350 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
351 * </ul>
352 */
353 public int getSelectionIndex () {
354 checkWidget ();
355 NSTabViewItem selected = ((NSTabView)view).selectedTabViewItem();
356 if (selected is null) return -1;
357 for (int i = 0; i < itemCount; i++) {
358 if (items[i].nsItem.id is selected.id) return i;
359 }
360 return -1;
361 }
362
363 /**
364 * Searches the receiver's list starting at the first item
365 * (index 0) until an item is found that is equal to the
366 * argument, and returns the index of that item. If no item
367 * is found, returns -1.
368 *
369 * @param item the search item
370 * @return the index of the item
371 *
372 * @exception IllegalArgumentException <ul>
373 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
374 * </ul>
375 * @exception DWTException <ul>
376 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
377 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
378 * </ul>
379 */
380 public int indexOf (TabItem item) {
381 checkWidget ();
382 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
383 int count = itemCount;
384 for (int i=0; i<count; i++) {
385 if (items [i] is item) return i;
386 }
387 return -1;
388 }
389
390 Point minimumSize (int wHint, int hHint, bool flushCache) {
391 Control [] children = _getChildren ();
392 int width = 0, height = 0;
393 for (int i=0; i<children.length; i++) {
394 Control child = children [i];
395 int index = 0;
396 int count = itemCount;
397 while (index < count) {
398 if (items [index].control is child) break;
399 index++;
400 }
401 if (index is count) {
402 Rectangle rect = child.getBounds ();
403 width = Math.max (width, rect.x + rect.width);
404 height = Math.max (height, rect.y + rect.height);
405 } else {
406 Point size = child.computeSize (wHint, hHint, flushCache);
407 width = Math.max (width, size.x);
408 height = Math.max (height, size.y);
409 }
410 }
411 return new Point (width, height);
412 }
413
414 void releaseChildren (bool destroy) {
415 if (items !is null) {
416 for (int i=0; i<items.length; i++) {
417 TabItem item = items [i];
418 if (item !is null && !item.isDisposed ()) {
419 item.release (false);
420 }
421 }
422 items = null;
423 }
424 super.releaseChildren (destroy);
425 }
426
427 void removeControl (Control control) {
428 super.removeControl (control);
429 int count = itemCount;
430 for (int i=0; i<count; i++) {
431 TabItem item = items [i];
432 if (item.control is control) item.setControl (null);
433 }
434 }
435
436 /**
437 * Removes the listener from the collection of listeners who will
438 * be notified when the user changes the receiver's selection.
439 *
440 * @param listener the listener which should no longer be notified
441 *
442 * @exception IllegalArgumentException <ul>
443 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
444 * </ul>
445 * @exception DWTException <ul>
446 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
447 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
448 * </ul>
449 *
450 * @see SelectionListener
451 * @see #addSelectionListener
452 */
453 public void removeSelectionListener (SelectionListener listener) {
454 checkWidget ();
455 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
456 if (eventTable is null) return;
457 eventTable.unhook (DWT.Selection, listener);
458 eventTable.unhook (DWT.DefaultSelection,listener);
459 }
460
461 int setBounds (int x, int y, int width, int height, bool move, bool resize) {
462 int result = super.setBounds(x, y, width, height, move, resize);
463 if ((result & RESIZED) !is 0) {
464 int index = getSelectionIndex ();
465 if (index !is -1) {
466 TabItem item = items [index];
467 Control control = item.control;
468 if (control !is null && !control.isDisposed ()) {
469 control.setBounds (getClientArea ());
470 }
471 }
472 }
473 return result;
474 }
475
476 void setFont (NSFont font) {
477 ((NSTabView)view).setFont(font);
478 }
479
480 /**
481 * Sets the receiver's selection to the given item.
482 * The current selected is first cleared, then the new item is
483 * selected.
484 *
485 * @param item the item to select
486 *
487 * @exception IllegalArgumentException <ul>
488 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
489 * </ul>
490 * @exception DWTException <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 * @since 3.2
496 */
497 public void setSelection (TabItem item) {
498 checkWidget ();
499 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
500 setSelection (new TabItem [] {item});
501 }
502
503 /**
504 * Sets the receiver's selection to be the given array of items.
505 * The current selected is first cleared, then the new items are
506 * selected.
507 *
508 * @param items the array of items
509 *
510 * @exception IllegalArgumentException <ul>
511 * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
512 * </ul>
513 * @exception DWTException <ul>
514 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
515 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
516 * </ul>
517 */
518 public void setSelection (TabItem [] items) {
519 checkWidget ();
520 if (items is null) error (DWT.ERROR_NULL_ARGUMENT);
521 if (items.length is 0) {
522 setSelection (-1, false, false);
523 } else {
524 for (int i=items.length - 1; i>=0; --i) {
525 int index = indexOf (items [i]);
526 if (index !is -1) setSelection (index, false, false);
527 }
528 }
529 }
530
531 /**
532 * Selects the item at the given zero-relative index in the receiver.
533 * If the item at the index was already selected, it remains selected.
534 * The current selection is first cleared, then the new items are
535 * selected. Indices that are out of range are ignored.
536 *
537 * @param index the index of the item to select
538 *
539 * @exception DWTException <ul>
540 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
541 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
542 * </ul>
543 */
544 public void setSelection (int index) {
545 checkWidget ();
546 int count = itemCount;
547 if (!(0 <= index && index < count)) return;
548 setSelection (index, false, false);
549 }
550
551 void setSelection (int index, bool notify, bool force) {
552 if (index >= itemCount) return;
553 int currentIndex = getSelectionIndex ();
554 if (!force && currentIndex is index) return;
555 if (currentIndex !is -1) {
556 TabItem item = items [currentIndex];
557 if (item !is null) {
558 Control control = item.control;
559 if (control !is null && !control.isDisposed ()) {
560 control.setVisible (false);
561 }
562 }
563 }
564 ((NSTabView)view).selectTabViewItemAtIndex(index);
565 index = getSelectionIndex();
566 if (index !is -1) {
567 TabItem item = items [index];
568 if (item !is null) {
569 Control control = item.control;
570 if (control !is null && !control.isDisposed ()) {
571 control.setBounds (getClientArea ());
572 control.setVisible (true);
573 }
574 if (notify) {
575 Event event = new Event ();
576 event.item = item;
577 sendEvent (DWT.Selection, event);
578 }
579 }
580 }
581 }
582
583 bool traversePage (bool next) {
584 int count = getItemCount ();
585 if (count is 0) return false;
586 int index = getSelectionIndex ();
587 if (index is -1) {
588 index = 0;
589 } else {
590 int offset = (next) ? 1 : -1;
591 index = (index + offset + count) % count;
592 }
593 setSelection (index, true, false);
594 return index is getSelectionIndex ();
595 }
596
597 void willSelectTabViewItem(int tabView, int tabViewItem) {
598 if (tabViewItem is 0) return;
599 for (int i = 0; i < itemCount; i++) {
600 TabItem item = items [i];
601 if (item.nsItem.id is tabViewItem) {
602 int currentIndex = getSelectionIndex ();
603 if (currentIndex !is -1) {
604 TabItem selected = items [currentIndex];
605 if (selected !is null) {
606 Control control = selected.control;
607 if (control !is null && !control.isDisposed ()) {
608 control.setVisible (false);
609 }
610 }
611 }
612 Control control = item.control;
613 if (control !is null && !control.isDisposed ()) {
614 control.setBounds (getClientArea ());
615 control.setVisible (true);
616 }
617 Event event = new Event ();
618 event.item = item;
619 sendEvent (DWT.Selection, event);
620 }
621 }
622 }
623
624 }