comparison dwt/widgets/List.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.List;
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.Color;
21 import dwt.graphics.GC;
22 import dwt.graphics.Point;
23 import dwt.graphics.Rectangle;
24 import dwt.internal.cocoa.NSAttributedString;
25 import dwt.internal.cocoa.NSColor;
26 import dwt.internal.cocoa.NSIndexSet;
27 import dwt.internal.cocoa.NSMutableDictionary;
28 import dwt.internal.cocoa.NSMutableIndexSet;
29 import dwt.internal.cocoa.NSPoint;
30 import dwt.internal.cocoa.NSRange;
31 import dwt.internal.cocoa.NSRect;
32 import dwt.internal.cocoa.NSString;
33 import dwt.internal.cocoa.NSTableColumn;
34 import dwt.internal.cocoa.NSTableView;
35 import dwt.internal.cocoa.OS;
36 import dwt.internal.cocoa.SWTScrollView;
37 import dwt.internal.cocoa.SWTTableView;
38
39 /**
40 * Instances of this class represent a selectable user interface
41 * object that displays a list of strings and issues notification
42 * when a string is selected. A list may be single or multi select.
43 * <p>
44 * <dl>
45 * <dt><b>Styles:</b></dt>
46 * <dd>SINGLE, MULTI</dd>
47 * <dt><b>Events:</b></dt>
48 * <dd>Selection, DefaultSelection</dd>
49 * </dl>
50 * <p>
51 * Note: Only one of SINGLE and MULTI may be specified.
52 * </p><p>
53 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
54 * </p>
55 */
56 public class List extends Scrollable {
57 NSTableColumn column;
58 String [] items;
59 int itemCount;
60 bool ignoreSelect;
61
62 /**
63 * Constructs a new instance of this class given its parent
64 * and a style value describing its behavior and appearance.
65 * <p>
66 * The style value is either one of the style constants defined in
67 * class <code>DWT</code> which is applicable to instances of this
68 * class, or must be built by <em>bitwise OR</em>'ing together
69 * (that is, using the <code>int</code> "|" operator) two or more
70 * of those <code>DWT</code> style constants. The class description
71 * lists the style constants that are applicable to the class.
72 * Style bits are also inherited from superclasses.
73 * </p>
74 *
75 * @param parent a composite control which will be the parent of the new instance (cannot be null)
76 * @param style the style of control to construct
77 *
78 * @exception IllegalArgumentException <ul>
79 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
80 * </ul>
81 * @exception DWTException <ul>
82 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
83 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
84 * </ul>
85 *
86 * @see DWT#SINGLE
87 * @see DWT#MULTI
88 * @see Widget#checkSubclass
89 * @see Widget#getStyle
90 */
91 public List (Composite parent, int style) {
92 super (parent, checkStyle (style));
93 }
94
95 /**
96 * Adds the argument to the end of the receiver's list.
97 *
98 * @param string the new item
99 *
100 * @exception IllegalArgumentException <ul>
101 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
102 * </ul>
103 * @exception DWTException <ul>
104 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
105 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
106 * </ul>
107 *
108 * @see #add(String,int)
109 */
110 public void add (String string) {
111 checkWidget();
112 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
113 if (itemCount is items.length) {
114 String [] newItems = new String [itemCount + 4];
115 System.arraycopy (items, 0, newItems, 0, items.length);
116 items = newItems;
117 }
118 items [itemCount++] = string;
119 ((NSTableView)view).reloadData();
120 //TODO adjust horizontal scrollbar
121 }
122
123 /**
124 * Adds the argument to the receiver's list at the given
125 * zero-relative index.
126 * <p>
127 * Note: To add an item at the end of the list, use the
128 * result of calling <code>getItemCount()</code> as the
129 * index or use <code>add(String)</code>.
130 * </p>
131 *
132 * @param string the new item
133 * @param index the index for the item
134 *
135 * @exception IllegalArgumentException <ul>
136 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
137 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
138 * </ul>
139 * @exception DWTException <ul>
140 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
141 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
142 * </ul>
143 *
144 * @see #add(String)
145 */
146 public void add (String string, int index) {
147 checkWidget();
148 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
149 if (!(0 <= index && index <= itemCount)) error (DWT.ERROR_INVALID_RANGE);
150 if (index !is itemCount) fixSelection (index, true);
151 if (itemCount is items.length) {
152 String [] newItems = new String [itemCount + 4];
153 System.arraycopy (items, 0, newItems, 0, items.length);
154 items = newItems;
155 }
156 System.arraycopy (items, index, items, index + 1, itemCount++ - index);
157 items [index] = string;
158 ((NSTableView)view).reloadData();
159 }
160
161 /**
162 * Adds the listener to the collection of listeners who will
163 * be notified when the user changes the receiver's selection, by sending
164 * it one of the messages defined in the <code>SelectionListener</code>
165 * interface.
166 * <p>
167 * <code>widgetSelected</code> is called when the selection changes.
168 * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
169 * </p>
170 *
171 * @param listener the listener which should be notified when the user changes the receiver's selection
172 *
173 * @exception IllegalArgumentException <ul>
174 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
175 * </ul>
176 * @exception DWTException <ul>
177 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
178 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
179 * </ul>
180 *
181 * @see SelectionListener
182 * @see #removeSelectionListener
183 * @see SelectionEvent
184 */
185 public void addSelectionListener(SelectionListener listener) {
186 checkWidget();
187 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
188 TypedListener typedListener = new TypedListener(listener);
189 addListener(DWT.Selection,typedListener);
190 addListener(DWT.DefaultSelection,typedListener);
191 }
192
193 static int checkStyle (int style) {
194 return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0);
195 }
196
197 public Point computeSize (int wHint, int hHint, bool changed) {
198 checkWidget();
199 int width = 0;
200 if (wHint is DWT.DEFAULT) {
201 GC gc = new GC (this);
202 for (int i=0; i<itemCount; i++) {
203 Point extent = gc.stringExtent (items [i]);
204 width = Math.max (width, extent.x);
205 }
206 gc.dispose ();
207 // width += EXTRA_WIDTH;
208 } else {
209 width = wHint;
210 }
211 if (width <= 0) width = DEFAULT_WIDTH;
212 int height = 0;
213 if (hHint is DWT.DEFAULT) {
214 height = itemCount * getItemHeight ();
215 } else {
216 height = hHint;
217 }
218 if (height <= 0) height = DEFAULT_HEIGHT;
219 Rectangle rect = computeTrim (0, 0, width, height);
220 return new Point (rect.width, rect.height);
221 }
222
223 void createHandle () {
224 SWTScrollView scrollWidget = (SWTScrollView)new SWTScrollView().alloc();
225 scrollWidget.initWithFrame(new NSRect ());
226 if ((style & DWT.H_SCROLL) !is 0) scrollWidget.setHasHorizontalScroller(true);
227 if ((style & DWT.V_SCROLL) !is 0) scrollWidget.setHasVerticalScroller(true);
228 scrollWidget.setAutohidesScrollers(true);
229 scrollWidget.setBorderType((style & DWT.BORDER) !is 0 ? OS.NSBezelBorder : OS.NSNoBorder);
230 scrollWidget.setTag(jniRef);
231
232 NSTableView widget = (NSTableView)new SWTTableView().alloc();
233 widget.initWithFrame(new NSRect());
234 widget.setAllowsMultipleSelection((style & DWT.MULTI) !is 0);
235 widget.setDataSource(widget);
236 widget.setHeaderView(null);
237 widget.setDelegate(widget);
238 widget.setDoubleAction(OS.sel_sendDoubleSelection);
239 if (!hasBorder()) widget.setFocusRingType(OS.NSFocusRingTypeNone);
240 widget.setTag(jniRef);
241
242 column = (NSTableColumn)new NSTableColumn().alloc();
243 column.initWithIdentifier(NSString.stringWith(""));
244 widget.addTableColumn (column);
245
246 scrollView = scrollWidget;
247 view = widget;
248 scrollView.setDocumentView(widget);
249 parent.contentView().addSubview_(scrollView);
250 }
251
252 void createWidget () {
253 super.createWidget ();
254 items = new String [4];
255 }
256
257 Color defaultBackground () {
258 return display.getSystemColor (DWT.COLOR_LIST_BACKGROUND);
259 }
260
261 Color defaultForeground () {
262 return display.getSystemColor (DWT.COLOR_LIST_FOREGROUND);
263 }
264
265 /**
266 * Deselects the item at the given zero-relative index in the receiver.
267 * If the item at the index was already deselected, it remains
268 * deselected. Indices that are out of range are ignored.
269 *
270 * @param index the index of the item to deselect
271 *
272 * @exception DWTException <ul>
273 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
274 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
275 * </ul>
276 */
277 public void deselect (int index) {
278 checkWidget();
279 if (0 <= index && index < itemCount) {
280 NSTableView widget = (NSTableView)view;
281 ignoreSelect = true;
282 widget.deselectRow (index);
283 ignoreSelect = false;
284 }
285 }
286
287 /**
288 * Deselects the items at the given zero-relative indices in the receiver.
289 * If the item at the given zero-relative index in the receiver
290 * is selected, it is deselected. If the item at the index
291 * was not selected, it remains deselected. The range of the
292 * indices is inclusive. Indices that are out of range are ignored.
293 *
294 * @param start the start index of the items to deselect
295 * @param end the end index of the items to deselect
296 *
297 * @exception DWTException <ul>
298 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
299 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
300 * </ul>
301 */
302 public void deselect (int start, int end) {
303 checkWidget();
304 if (start > end) return;
305 if (end < 0 || start >= itemCount) return;
306 start = Math.max (0, start);
307 end = Math.min (itemCount - 1, end);
308 int length = end - start + 1;
309 if (length <= 0) return;
310 if (start is 0 && end is itemCount - 1) {
311 deselectAll ();
312 } else {
313 NSTableView widget = (NSTableView)view;
314 ignoreSelect = true;
315 for (int i=0; i<length; i++) {
316 widget.deselectRow (i);
317 }
318 ignoreSelect = false;
319 }
320 }
321
322 /**
323 * Deselects the items at the given zero-relative indices in the receiver.
324 * If the item at the given zero-relative index in the receiver
325 * is selected, it is deselected. If the item at the index
326 * was not selected, it remains deselected. Indices that are out
327 * of range and duplicate indices are ignored.
328 *
329 * @param indices the array of indices for the items to deselect
330 *
331 * @exception IllegalArgumentException <ul>
332 * <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
333 * </ul>
334 * @exception DWTException <ul>
335 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
336 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
337 * </ul>
338 */
339 public void deselect (int [] indices) {
340 checkWidget();
341 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
342 NSTableView widget = (NSTableView)view;
343 ignoreSelect = true;
344 for (int i=0; i<indices.length; i++) {
345 widget.deselectRow (indices [i]);
346 }
347 ignoreSelect = false;
348 }
349
350 /**
351 * Deselects all selected items in the receiver.
352 *
353 * @exception DWTException <ul>
354 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
355 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
356 * </ul>
357 */
358 public void deselectAll () {
359 checkWidget ();
360 NSTableView widget = (NSTableView)view;
361 ignoreSelect = true;
362 widget.deselectAll(null);
363 ignoreSelect = false;
364 }
365
366 void fixSelection (int index, bool add) {
367 int [] selection = getSelectionIndices ();
368 if (selection.length is 0) return;
369 int newCount = 0;
370 bool fix = false;
371 for (int i = 0; i < selection.length; i++) {
372 if (!add && selection [i] is index) {
373 fix = true;
374 } else {
375 int newIndex = newCount++;
376 selection [newIndex] = selection [i] + 1;
377 if (selection [newIndex] - 1 >= index) {
378 selection [newIndex] += add ? 1 : -1;
379 fix = true;
380 }
381 }
382 }
383 if (fix) select (selection, newCount, true);
384 }
385
386 /**
387 * Returns the zero-relative index of the item which currently
388 * has the focus in the receiver, or -1 if no item has focus.
389 *
390 * @return the index of the selected item
391 *
392 * @exception DWTException <ul>
393 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
394 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
395 * </ul>
396 */
397 public int getFocusIndex () {
398 checkWidget();
399 // int [] first = new int [1], last = new int [1];
400 // if (OS.GetDataBrowserSelectionAnchor (handle, first, last) !is OS.noErr) return -1;
401 // return first [0] - 1;
402 return -1;
403 }
404
405 /**
406 * Returns the item at the given, zero-relative index in the
407 * receiver. Throws an exception if the index is out of range.
408 *
409 * @param index the index of the item to return
410 * @return the item at the given index
411 *
412 * @exception IllegalArgumentException <ul>
413 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
414 * </ul>
415 * @exception DWTException <ul>
416 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
417 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
418 * </ul>
419 */
420 public String getItem (int index) {
421 checkWidget();
422 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
423 return items [index];
424 }
425
426 /**
427 * Returns the number of items contained in the receiver.
428 *
429 * @return the number of items
430 *
431 * @exception DWTException <ul>
432 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
433 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
434 * </ul>
435 */
436 public int getItemCount () {
437 checkWidget();
438 return itemCount;
439 }
440
441 /**
442 * Returns the height of the area which would be used to
443 * display <em>one</em> of the items in the list.
444 *
445 * @return the height of one item
446 *
447 * @exception DWTException <ul>
448 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
449 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
450 * </ul>
451 */
452 public int getItemHeight () {
453 checkWidget ();
454 return (int)((NSTableView)view).rowHeight();
455 }
456
457 /**
458 * Returns a (possibly empty) array of <code>String</code>s which
459 * are the items in the receiver.
460 * <p>
461 * Note: This is not the actual structure used by the receiver
462 * to maintain its list of items, so modifying the array will
463 * not affect the receiver.
464 * </p>
465 *
466 * @return the items in the receiver's list
467 *
468 * @exception DWTException <ul>
469 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
470 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
471 * </ul>
472 */
473 public String [] getItems () {
474 checkWidget();
475 String [] result = new String [itemCount];
476 System.arraycopy (items, 0, result, 0, itemCount);
477 return result;
478 }
479
480 /**
481 * Returns an array of <code>String</code>s that are currently
482 * selected in the receiver. The order of the items is unspecified.
483 * An empty array indicates that no items are selected.
484 * <p>
485 * Note: This is not the actual structure used by the receiver
486 * to maintain its selection, so modifying the array will
487 * not affect the receiver.
488 * </p>
489 * @return an array representing the selection
490 *
491 * @exception DWTException <ul>
492 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
493 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
494 * </ul>
495 */
496 public String [] getSelection () {
497 checkWidget ();
498 NSTableView widget = (NSTableView)view;
499 if (widget.numberOfSelectedRows() is 0) {
500 return new String [0];
501 }
502 NSIndexSet selection = widget.selectedRowIndexes();
503 int count = selection.count();
504 int [] indexBuffer = new int [count];
505 selection.getIndexes(indexBuffer, count, 0);
506 String [] result = new String [count];
507 for (int i=0; i<count; i++) {
508 result [i] = items [indexBuffer [i]];
509 }
510 return result;
511 }
512
513 /**
514 * Returns the number of selected items contained in the receiver.
515 *
516 * @return the number of selected items
517 *
518 * @exception DWTException <ul>
519 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
520 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
521 * </ul>
522 */
523 public int getSelectionCount () {
524 checkWidget ();
525 return ((NSTableView)view).numberOfSelectedRows();
526 }
527
528 /**
529 * Returns the zero-relative index of the item which is currently
530 * selected in the receiver, or -1 if no item is selected.
531 *
532 * @return the index of the selected item or -1
533 *
534 * @exception DWTException <ul>
535 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
536 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
537 * </ul>
538 */
539 public int getSelectionIndex () {
540 checkWidget();
541 //TODO - check empty selection case
542 return ((NSTableView)view).selectedRow();
543 }
544
545 /**
546 * Returns the zero-relative indices of the items which are currently
547 * selected in the receiver. The order of the indices is unspecified.
548 * The array is empty if no items are selected.
549 * <p>
550 * Note: This is not the actual structure used by the receiver
551 * to maintain its selection, so modifying the array will
552 * not affect the receiver.
553 * </p>
554 * @return the array of indices of the selected items
555 *
556 * @exception DWTException <ul>
557 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
558 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
559 * </ul>
560 */
561 public int [] getSelectionIndices () {
562 checkWidget ();
563 NSTableView widget = (NSTableView)view;
564 if (widget.numberOfSelectedRows() is 0) {
565 return new int [0];
566 }
567 NSIndexSet selection = widget.selectedRowIndexes();
568 int count = selection.count();
569 int [] result = new int [count];
570 selection.getIndexes(result, count, 0);
571 return result;
572 }
573
574 /**
575 * Returns the zero-relative index of the item which is currently
576 * at the top of the receiver. This index can change when items are
577 * scrolled or new items are added or removed.
578 *
579 * @return the index of the top item
580 *
581 * @exception DWTException <ul>
582 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
583 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
584 * </ul>
585 */
586 public int getTopIndex () {
587 checkWidget();
588 //TODO - partial item at the top
589 NSRect rect = scrollView.documentVisibleRect();
590 NSPoint point = new NSPoint();
591 point.x = rect.x;
592 point.y = rect.y;
593 return ((NSTableView)view).rowAtPoint(point);
594 }
595
596 /**
597 * Gets the index of an item.
598 * <p>
599 * The list is searched starting at 0 until an
600 * item is found that is equal to the search item.
601 * If no item is found, -1 is returned. Indexing
602 * is zero based.
603 *
604 * @param string the search item
605 * @return the index of the item
606 *
607 * @exception IllegalArgumentException <ul>
608 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
609 * </ul>
610 * @exception DWTException <ul>
611 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
612 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
613 * </ul>
614 */
615 public int indexOf (String item) {
616 checkWidget();
617 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
618 for (int i=0; i<itemCount; i++) {
619 if (items [i].equals (item)) return i;
620 }
621 return -1;
622 }
623
624 /**
625 * Searches the receiver's list starting at the given,
626 * zero-relative index until an item is found that is equal
627 * to the argument, and returns the index of that item. If
628 * no item is found or the starting index is out of range,
629 * returns -1.
630 *
631 * @param string the search item
632 * @param start the zero-relative index at which to start the search
633 * @return the index of the item
634 *
635 * @exception IllegalArgumentException <ul>
636 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
637 * </ul>
638 * @exception DWTException <ul>
639 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
640 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
641 * </ul>
642 */
643 public int indexOf (String string, int start) {
644 checkWidget();
645 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
646 for (int i=start; i<itemCount; i++) {
647 if (items [i].equals (string)) return i;
648 }
649 return -1;
650 }
651
652 /**
653 * Returns <code>true</code> if the item is selected,
654 * and <code>false</code> otherwise. Indices out of
655 * range are ignored.
656 *
657 * @param index the index of the item
658 * @return the selection state of the item at the index
659 *
660 * @exception DWTException <ul>
661 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
662 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
663 * </ul>
664 */
665 public bool isSelected (int index) {
666 checkWidget();
667 //TODO - range check
668 return ((NSTableView)view).isRowSelected(index);
669 }
670
671 int numberOfRowsInTableView(int aTableView) {
672 return itemCount;
673 }
674
675 void releaseHandle () {
676 super.releaseHandle ();
677 if (column !is null) column.release();
678 column = null;
679 }
680
681 void releaseWidget () {
682 super.releaseWidget ();
683 items = null;
684 }
685
686 /**
687 * Removes the item from the receiver at the given
688 * zero-relative index.
689 *
690 * @param index the index for the item
691 *
692 * @exception IllegalArgumentException <ul>
693 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
694 * </ul>
695 * @exception DWTException <ul>
696 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
697 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
698 * </ul>
699 */
700 public void remove (int index) {
701 checkWidget();
702 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
703 if (index !is itemCount - 1) fixSelection (index, false);
704 System.arraycopy (items, index + 1, items, index, --itemCount - index);
705 items [itemCount] = null;
706 ((NSTableView)view).noteNumberOfRowsChanged();
707 }
708
709 /**
710 * Removes the items from the receiver which are
711 * between the given zero-relative start and end
712 * indices (inclusive).
713 *
714 * @param start the start of the range
715 * @param end the end of the range
716 *
717 * @exception IllegalArgumentException <ul>
718 * <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
719 * </ul>
720 * @exception DWTException <ul>
721 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
722 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
723 * </ul>
724 */
725 public void remove (int start, int end) {
726 checkWidget();
727 if (start > end) return;
728 if (!(0 <= start && start <= end && end < itemCount)) {
729 error (DWT.ERROR_INVALID_RANGE);
730 }
731 int length = end - start + 1;
732 for (int i=0; i<length; i++) remove (start);
733 }
734
735 /**
736 * Searches the receiver's list starting at the first item
737 * until an item is found that is equal to the argument,
738 * and removes that item from the list.
739 *
740 * @param string the item to remove
741 *
742 * @exception IllegalArgumentException <ul>
743 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
744 * <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
745 * </ul>
746 * @exception DWTException <ul>
747 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
748 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
749 * </ul>
750 */
751 public void remove (String string) {
752 checkWidget();
753 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
754 int index = indexOf (string, 0);
755 if (index is -1) error (DWT.ERROR_INVALID_ARGUMENT);
756 remove (index);
757 }
758
759 /**
760 * Removes the items from the receiver at the given
761 * zero-relative indices.
762 *
763 * @param indices the array of indices of the items
764 *
765 * @exception IllegalArgumentException <ul>
766 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
767 * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
768 * </ul>
769 * @exception DWTException <ul>
770 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
771 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
772 * </ul>
773 */
774 public void remove (int [] indices) {
775 checkWidget ();
776 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
777 if (indices.length is 0) return;
778 int [] newIndices = new int [indices.length];
779 System.arraycopy (indices, 0, newIndices, 0, indices.length);
780 sort (newIndices);
781 int start = newIndices [newIndices.length - 1], end = newIndices [0];
782 int count = getItemCount ();
783 if (!(0 <= start && start <= end && end < count)) {
784 error (DWT.ERROR_INVALID_RANGE);
785 }
786 int last = -1;
787 for (int i=0; i<newIndices.length; i++) {
788 int index = newIndices [i];
789 if (index !is last) {
790 remove (index);
791 last = index;
792 }
793 }
794 }
795
796 /**
797 * Removes all of the items from the receiver.
798 * <p>
799 * @exception DWTException <ul>
800 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
801 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
802 * </ul>
803 */
804 public void removeAll () {
805 checkWidget();
806 items = new String [4];
807 itemCount = 0;
808 ((NSTableView)view).noteNumberOfRowsChanged();
809 }
810
811 /**
812 * Removes the listener from the collection of listeners who will
813 * be notified when the user changes the receiver's selection.
814 *
815 * @param listener the listener which should no longer be notified
816 *
817 * @exception IllegalArgumentException <ul>
818 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
819 * </ul>
820 * @exception DWTException <ul>
821 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
822 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
823 * </ul>
824 *
825 * @see SelectionListener
826 * @see #addSelectionListener
827 */
828 public void removeSelectionListener(SelectionListener listener) {
829 checkWidget();
830 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
831 if (eventTable is null) return;
832 eventTable.unhook(DWT.Selection, listener);
833 eventTable.unhook(DWT.DefaultSelection,listener);
834 }
835
836 /**
837 * Selects the item at the given zero-relative index in the receiver's
838 * list. If the item at the index was already selected, it remains
839 * selected. Indices that are out of range are ignored.
840 *
841 * @param index the index of the item to select
842 *
843 * @exception DWTException <ul>
844 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
845 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
846 * </ul>
847 */
848 public void select (int index) {
849 checkWidget();
850 if (0 <= index && index < itemCount) {
851 NSIndexSet indexes = (NSIndexSet)new NSIndexSet().alloc();
852 indexes.initWithIndex(index);
853 NSTableView widget = (NSTableView)view;
854 ignoreSelect = true;
855 ((NSTableView)view).selectRowIndexes(indexes, true);
856 ignoreSelect = false;
857 }
858 }
859
860 /**
861 * Selects the items in the range specified by the given zero-relative
862 * indices in the receiver. The range of indices is inclusive.
863 * The current selection is not cleared before the new items are selected.
864 * <p>
865 * If an item in the given range is not selected, it is selected.
866 * If an item in the given range was already selected, it remains selected.
867 * Indices that are out of range are ignored and no items will be selected
868 * if start is greater than end.
869 * If the receiver is single-select and there is more than one item in the
870 * given range, then all indices are ignored.
871 *
872 * @param start the start of the range
873 * @param end the end of the range
874 *
875 * @exception DWTException <ul>
876 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
877 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
878 * </ul>
879 *
880 * @see List#setSelection(int,int)
881 */
882 public void select (int start, int end) {
883 checkWidget ();
884 if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return;
885 if (itemCount is 0 || start >= itemCount) return;
886 if (start is 0 && end is itemCount - 1) {
887 selectAll ();
888 } else {
889 start = Math.max (0, start);
890 end = Math.min (end, itemCount - 1);
891 int length = end - start + 1;
892 NSIndexSet indexes = (NSIndexSet)new NSIndexSet().alloc();
893 NSRange range = new NSRange();
894 range.location = start;
895 range.length = length;
896 indexes.initWithIndexesInRange(range);
897 NSTableView widget = (NSTableView)view;
898 ignoreSelect = true;
899 widget.selectRowIndexes(indexes, true);
900 ignoreSelect = false;
901 }
902 }
903
904 /**
905 * Selects the items at the given zero-relative indices in the receiver.
906 * The current selection is not cleared before the new items are selected.
907 * <p>
908 * If the item at a given index is not selected, it is selected.
909 * If the item at a given index was already selected, it remains selected.
910 * Indices that are out of range and duplicate indices are ignored.
911 * If the receiver is single-select and multiple indices are specified,
912 * then all indices are ignored.
913 *
914 * @param indices the array of indices for the items to select
915 *
916 * @exception IllegalArgumentException <ul>
917 * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
918 * </ul>
919 * @exception DWTException <ul>
920 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
921 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
922 * </ul>
923 *
924 * @see List#setSelection(int[])
925 */
926 public void select (int [] indices) {
927 checkWidget ();
928 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
929 int length = indices.length;
930 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
931 int count = 0;
932 NSMutableIndexSet indexes = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
933 for (int i=0; i<length; i++) {
934 int index = indices [length - i - 1];
935 if (index >= 0 && index < itemCount) {
936 indexes.addIndex (indices [i]);
937 count++;
938 }
939 }
940 if (count > 0) {
941 NSTableView widget = (NSTableView)view;
942 ignoreSelect = true;
943 widget.selectRowIndexes(indexes, true);
944 ignoreSelect = false;
945 }
946 }
947
948 void select (int [] ids, int count, bool clear) {
949 NSMutableIndexSet indexes = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
950 for (int i=0; i<count; i++) indexes.addIndex (ids [i] - 1); //WRONG -1
951 NSTableView widget = (NSTableView)view;
952 ignoreSelect = true;
953 widget.selectRowIndexes(indexes, !clear);
954 ignoreSelect = false;
955 }
956
957 /**
958 * Selects all of the items in the receiver.
959 * <p>
960 * If the receiver is single-select, do nothing.
961 *
962 * @exception DWTException <ul>
963 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
964 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
965 * </ul>
966 */
967 public void selectAll () {
968 checkWidget ();
969 if ((style & DWT.SINGLE) !is 0) return;
970 NSTableView widget = (NSTableView)view;
971 ignoreSelect = true;
972 widget.selectAll(null);
973 ignoreSelect = false;
974 }
975
976 void sendDoubleSelection() {
977 postEvent (DWT.DefaultSelection);
978 }
979
980 /**
981 * Sets the text of the item in the receiver's list at the given
982 * zero-relative index to the string argument.
983 *
984 * @param index the index for the item
985 * @param string the new text for the item
986 *
987 * @exception IllegalArgumentException <ul>
988 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
989 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
990 * </ul>
991 * @exception DWTException <ul>
992 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
993 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
994 * </ul>
995 */
996 public void setItem (int index, String string) {
997 checkWidget();
998 if (string is null) error (DWT.ERROR_NULL_ARGUMENT);
999 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
1000 items [index] = string;
1001 ((NSTableView)view).reloadData();
1002 }
1003
1004 /**
1005 * Sets the receiver's items to be the given array of items.
1006 *
1007 * @param items the array of items
1008 *
1009 * @exception IllegalArgumentException <ul>
1010 * <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1011 * <li>ERROR_INVALID_ARGUMENT - if an item in the items array is null</li>
1012 * </ul>
1013 * @exception DWTException <ul>
1014 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1015 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1016 * </ul>
1017 */
1018 public void setItems (String [] items) {
1019 checkWidget();
1020 if (items is null) error (DWT.ERROR_NULL_ARGUMENT);
1021 for (int i=0; i<items.length; i++) {
1022 if (items [i] is null) error (DWT.ERROR_INVALID_ARGUMENT);
1023 }
1024 this.items = new String [items.length];
1025 System.arraycopy (items, 0, this.items, 0, items.length);
1026 itemCount = items.length;
1027 ((NSTableView)view).reloadData();
1028 }
1029
1030 /**
1031 * Selects the item at the given zero-relative index in the receiver.
1032 * If the item at the index was already selected, it remains selected.
1033 * The current selection is first cleared, then the new item is selected.
1034 * Indices that are out of range are ignored.
1035 *
1036 * @param index the index of the item to select
1037 *
1038 * @exception DWTException <ul>
1039 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1040 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1041 * </ul>
1042 * @see List#deselectAll()
1043 * @see List#select(int)
1044 */
1045 public void setSelection (int index) {
1046 checkWidget();
1047 deselectAll ();
1048 setSelection (index, false);
1049 }
1050
1051 void setSelection (int index, bool notify) {
1052 // checkWidget();
1053 if (0 <= index && index < itemCount) {
1054 int [] ids = new int [] {index + 1};
1055 select (ids, ids.length, true);
1056 showIndex (index);
1057 if (notify) postEvent (DWT.Selection);
1058 }
1059 }
1060
1061 /**
1062 * Selects the items in the range specified by the given zero-relative
1063 * indices in the receiver. The range of indices is inclusive.
1064 * The current selection is cleared before the new items are selected.
1065 * <p>
1066 * Indices that are out of range are ignored and no items will be selected
1067 * if start is greater than end.
1068 * If the receiver is single-select and there is more than one item in the
1069 * given range, then all indices are ignored.
1070 *
1071 * @param start the start index of the items to select
1072 * @param end the end index of the items to select
1073 *
1074 * @exception DWTException <ul>
1075 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1076 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1077 * </ul>
1078 *
1079 * @see List#deselectAll()
1080 * @see List#select(int,int)
1081 */
1082 public void setSelection (int start, int end) {
1083 checkWidget ();
1084 deselectAll ();
1085 if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return;
1086 if (itemCount is 0 || start >= itemCount) return;
1087 start = Math.max (0, start);
1088 end = Math.min (end, itemCount - 1);
1089 int length = end - start + 1;
1090 int [] ids = new int [length];
1091 for (int i=0; i<length; i++) ids [i] = end - i + 1;
1092 select (ids, length, true);
1093 if (ids.length > 0) showIndex (ids [0] - 1);
1094 }
1095
1096 /**
1097 * Selects the items at the given zero-relative indices in the receiver.
1098 * The current selection is cleared before the new items are selected.
1099 * <p>
1100 * Indices that are out of range and duplicate indices are ignored.
1101 * If the receiver is single-select and multiple indices are specified,
1102 * then all indices are ignored.
1103 *
1104 * @param indices the indices of the items to select
1105 *
1106 * @exception IllegalArgumentException <ul>
1107 * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1108 * </ul>
1109 * @exception DWTException <ul>
1110 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1111 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1112 * </ul>
1113 *
1114 * @see List#deselectAll()
1115 * @see List#select(int[])
1116 */
1117 public void setSelection (int [] indices) {
1118 checkWidget ();
1119 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
1120 deselectAll ();
1121 int length = indices.length;
1122 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
1123 int [] ids = new int [length];
1124 int count = 0;
1125 for (int i=0; i<length; i++) {
1126 int index = indices [length - i - 1];
1127 if (index >= 0 && index < itemCount) {
1128 ids [count++] = index + 1;
1129 }
1130 }
1131 if (count > 0) {
1132 select (ids, count, true);
1133 showIndex (ids [0] - 1);
1134 }
1135 }
1136
1137 /**
1138 * Sets the receiver's selection to be the given array of items.
1139 * The current selection is cleared before the new items are selected.
1140 * <p>
1141 * Items that are not in the receiver are ignored.
1142 * If the receiver is single-select and multiple items are specified,
1143 * then all items are ignored.
1144 *
1145 * @param items the array of items
1146 *
1147 * @exception IllegalArgumentException <ul>
1148 * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
1149 * </ul>
1150 * @exception DWTException <ul>
1151 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1152 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1153 * </ul>
1154 *
1155 * @see List#deselectAll()
1156 * @see List#select(int[])
1157 * @see List#setSelection(int[])
1158 */
1159 public void setSelection (String [] items) {
1160 checkWidget ();
1161 if (items is null) error (DWT.ERROR_NULL_ARGUMENT);
1162 deselectAll ();
1163 int length = items.length;
1164 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
1165 int count = 0;
1166 int [] ids = new int [length];
1167 for (int i=0; i<length; i++) {
1168 String string = items [length - i - 1];
1169 if ((style & DWT.SINGLE) !is 0) {
1170 int index = indexOf (string, 0);
1171 if (index !is -1) {
1172 count = 1;
1173 ids = new int [] {index + 1};
1174 }
1175 } else {
1176 int index = 0;
1177 while ((index = indexOf (string, index)) !is -1) {
1178 if (count is ids.length) {
1179 int [] newIds = new int [ids.length + 4];
1180 System.arraycopy (ids, 0, newIds, 0, ids.length);
1181 ids = newIds;
1182 }
1183 ids [count++] = index + 1;
1184 index++;
1185 }
1186 }
1187 }
1188 if (count > 0) {
1189 select (ids, count, true);
1190 showIndex (ids [0] - 1);
1191 }
1192 }
1193
1194 /**
1195 * Sets the zero-relative index of the item which is currently
1196 * at the top of the receiver. This index can change when items
1197 * are scrolled or new items are added and removed.
1198 *
1199 * @param index the index of the top item
1200 *
1201 * @exception DWTException <ul>
1202 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1203 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1204 * </ul>
1205 */
1206 public void setTopIndex (int index) {
1207 checkWidget();
1208 NSRect rect = ((NSTableView)view).rectOfRow(index);
1209 ((NSTableView)view).scrollRectToVisible(rect);
1210 }
1211
1212 void showIndex (int index) {
1213 if (0 <= index && index < itemCount) {
1214 ((NSTableView)view).scrollRowToVisible(index);
1215 }
1216 }
1217
1218 /**
1219 * Shows the selection. If the selection is already showing in the receiver,
1220 * this method simply returns. Otherwise, the items are scrolled until
1221 * the selection is visible.
1222 *
1223 * @exception DWTException <ul>
1224 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1225 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1226 * </ul>
1227 */
1228 public void showSelection () {
1229 checkWidget();
1230 int index = getSelectionIndex ();
1231 if (index >= 0) showIndex (index);
1232 }
1233
1234 void tableViewSelectionDidChange (int aNotification) {
1235 if (ignoreSelect) return;
1236 postEvent (DWT.Selection);
1237 }
1238
1239 bool tableView_shouldEditTableColumn_row(int aTableView, int aTableColumn, int rowIndex) {
1240 return false;
1241 }
1242
1243 int tableView_objectValueForTableColumn_row(int aTableView, int aTableColumn, int rowIndex) {
1244 NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4);
1245 if (foreground !is null) {
1246 NSColor color = NSColor.colorWithDeviceRed(foreground.handle[0], foreground.handle[1], foreground.handle[2], 1);
1247 dict.setObject(color, OS.NSForegroundColorAttributeName());
1248 }
1249 if (font !is null) {
1250 dict.setObject(font.handle, OS.NSFontAttributeName());
1251 }
1252 if (background !is null) {
1253 NSColor color = NSColor.colorWithDeviceRed(background.handle[0], background.handle[1], background.handle[2], 1);
1254 dict.setObject(color, OS.NSBackgroundColorAttributeName());
1255 }
1256 String text = items[rowIndex];
1257 int length = text.length();
1258 char[] chars = new char[length];
1259 text.getChars(0, length, chars, 0);
1260 NSString str = NSString.stringWithCharacters(chars, length);
1261 NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString_attributes_(str, dict);
1262 attribStr.autorelease();
1263 return attribStr.id;
1264 }
1265
1266 }