comparison dwt/widgets/Table.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.Table;
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.Font;
22 import dwt.graphics.GC;
23 import dwt.graphics.Image;
24 import dwt.graphics.Point;
25 import dwt.graphics.Rectangle;
26 import dwt.internal.cocoa.NSBrowserCell;
27 import dwt.internal.cocoa.NSButtonCell;
28 import dwt.internal.cocoa.NSCell;
29 import dwt.internal.cocoa.NSIndexSet;
30 import dwt.internal.cocoa.NSMutableIndexSet;
31 import dwt.internal.cocoa.NSNumber;
32 import dwt.internal.cocoa.NSPoint;
33 import dwt.internal.cocoa.NSRange;
34 import dwt.internal.cocoa.NSRect;
35 import dwt.internal.cocoa.NSString;
36 import dwt.internal.cocoa.NSTableColumn;
37 import dwt.internal.cocoa.NSTableHeaderView;
38 import dwt.internal.cocoa.NSTableView;
39 import dwt.internal.cocoa.OS;
40 import dwt.internal.cocoa.SWTScrollView;
41 import dwt.internal.cocoa.SWTTableView;
42
43 /**
44 * Instances of this class implement a selectable user interface
45 * object that displays a list of images and strings and issues
46 * notification when selected.
47 * <p>
48 * The item children that may be added to instances of this class
49 * must be of type <code>TableItem</code>.
50 * </p><p>
51 * Style <code>VIRTUAL</code> is used to create a <code>Table</code> whose
52 * <code>TableItem</code>s are to be populated by the client on an on-demand basis
53 * instead of up-front. This can provide significant performance improvements for
54 * tables that are very large or for which <code>TableItem</code> population is
55 * expensive (for example, retrieving values from an external source).
56 * </p><p>
57 * Here is an example of using a <code>Table</code> with style <code>VIRTUAL</code>:
58 * <code><pre>
59 * final Table table = new Table (parent, DWT.VIRTUAL | DWT.BORDER);
60 * table.setItemCount (1000000);
61 * table.addListener (DWT.SetData, new Listener () {
62 * public void handleEvent (Event event) {
63 * TableItem item = (TableItem) event.item;
64 * int index = table.indexOf (item);
65 * item.setText ("Item " + index);
66 * System.out.println (item.getText ());
67 * }
68 * });
69 * </pre></code>
70 * </p><p>
71 * Note that although this class is a subclass of <code>Composite</code>,
72 * it does not make sense to add <code>Control</code> children to it,
73 * or set a layout on it.
74 * </p><p>
75 * <dl>
76 * <dt><b>Styles:</b></dt>
77 * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL</dd>
78 * <dt><b>Events:</b></dt>
79 * <dd>Selection, DefaultSelection, SetData, MeasureItem, EraseItem, PaintItem</dd>
80 * </dl>
81 * </p><p>
82 * Note: Only one of the styles SINGLE, and MULTI may be specified.
83 * </p><p>
84 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
85 * </p>
86 */
87 public class Table extends Composite {
88 TableItem [] items;
89 TableColumn [] columns;
90 TableColumn sortColumn;
91 TableItem currentItem;
92 NSTableHeaderView headerView;
93 NSTableColumn firstColumn, checkColumn;
94 int columnCount, itemCount, lastIndexOf, sortDirection;
95 bool ignoreSelect;
96
97 /**
98 * Constructs a new instance of this class given its parent
99 * and a style value describing its behavior and appearance.
100 * <p>
101 * The style value is either one of the style constants defined in
102 * class <code>DWT</code> which is applicable to instances of this
103 * class, or must be built by <em>bitwise OR</em>'ing together
104 * (that is, using the <code>int</code> "|" operator) two or more
105 * of those <code>DWT</code> style constants. The class description
106 * lists the style constants that are applicable to the class.
107 * Style bits are also inherited from superclasses.
108 * </p>
109 *
110 * @param parent a composite control which will be the parent of the new instance (cannot be null)
111 * @param style the style of control to construct
112 *
113 * @exception IllegalArgumentException <ul>
114 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
115 * </ul>
116 * @exception DWTException <ul>
117 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
118 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
119 * </ul>
120 *
121 * @see DWT#SINGLE
122 * @see DWT#MULTI
123 * @see DWT#CHECK
124 * @see DWT#FULL_SELECTION
125 * @see DWT#HIDE_SELECTION
126 * @see DWT#VIRTUAL
127 * @see Widget#checkSubclass
128 * @see Widget#getStyle
129 */
130 public Table (Composite parent, int style) {
131 super (parent, checkStyle (style));
132 }
133
134 /**
135 * Adds the listener to the collection of listeners who will
136 * be notified when the user changes the receiver's selection, by sending
137 * it one of the messages defined in the <code>SelectionListener</code>
138 * interface.
139 * <p>
140 * When <code>widgetSelected</code> is called, the item field of the event object is valid.
141 * If the receiver has the <code>DWT.CHECK</code> style and the check selection changes,
142 * the event object detail field contains the value <code>DWT.CHECK</code>.
143 * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
144 * The item field of the event object is valid for default selection, but the detail field is not used.
145 * </p>
146 *
147 * @param listener the listener which should be notified when the user changes the receiver's selection
148 *
149 * @exception IllegalArgumentException <ul>
150 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
151 * </ul>
152 * @exception DWTException <ul>
153 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
154 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
155 * </ul>
156 *
157 * @see SelectionListener
158 * @see #removeSelectionListener
159 * @see SelectionEvent
160 */
161 public void addSelectionListener (SelectionListener listener) {
162 checkWidget ();
163 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
164 TypedListener typedListener = new TypedListener (listener);
165 addListener (DWT.Selection, typedListener);
166 addListener (DWT.DefaultSelection, typedListener);
167 }
168
169 TableItem _getItem (int index) {
170 if ((style & DWT.VIRTUAL) is 0) return items [index];
171 if (items [index] !is null) return items [index];
172 return items [index] = new TableItem (this, DWT.NULL, -1, false);
173 }
174
175 bool checkData (TableItem item, bool redraw) {
176 if (item.cached) return true;
177 if ((style & DWT.VIRTUAL) !is 0) {
178 item.cached = true;
179 Event event = new Event ();
180 event.item = item;
181 event.index = indexOf (item);
182 currentItem = item;
183 sendEvent (DWT.SetData, event);
184 //widget could be disposed at this point
185 currentItem = null;
186 if (isDisposed () || item.isDisposed ()) return false;
187 if (redraw) {
188 // if (!setScrollWidth (item)) item.redraw (OS.kDataBrowserNoItem);
189 }
190 }
191 return true;
192 }
193
194 static int checkStyle (int style) {
195 /*
196 * Feature in Windows. Even when WS_HSCROLL or
197 * WS_VSCROLL is not specified, Windows creates
198 * trees and tables with scroll bars. The fix
199 * is to set H_SCROLL and V_SCROLL.
200 *
201 * NOTE: This code appears on all platforms so that
202 * applications have consistent scroll bar behavior.
203 */
204 if ((style & DWT.NO_SCROLL) is 0) {
205 style |= DWT.H_SCROLL | DWT.V_SCROLL;
206 }
207 return checkBits (style, DWT.SINGLE, DWT.MULTI, 0, 0, 0, 0);
208 }
209
210 protected void checkSubclass () {
211 if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS);
212 }
213
214 /**
215 * Clears the item at the given zero-relative index in the receiver.
216 * The text, icon and other attributes of the item are set to the default
217 * value. If the table was created with the <code>DWT.VIRTUAL</code> style,
218 * these attributes are requested again as needed.
219 *
220 * @param index the index of the item to clear
221 *
222 * @exception IllegalArgumentException <ul>
223 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
224 * </ul>
225 * @exception DWTException <ul>
226 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
227 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
228 * </ul>
229 *
230 * @see DWT#VIRTUAL
231 * @see DWT#SetData
232 *
233 * @since 3.0
234 */
235 public void clear (int index) {
236 checkWidget();
237 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
238 TableItem item = items [index];
239 if (item !is null) {
240 if (currentItem !is item) item.clear ();
241 if (currentItem is null && drawCount is 0) {
242 int [] id = new int [] {index + 1};
243 // OS.UpdateDataBrowserItems (handle, 0, id.length, id, OS.kDataBrowserItemNoProperty, OS.kDataBrowserNoItem);
244 }
245 // setScrollWidth (item);
246 }
247 }
248
249 /**
250 * Removes the items from the receiver which are between the given
251 * zero-relative start and end indices (inclusive). The text, icon
252 * and other attributes of the items are set to their default values.
253 * If the table was created with the <code>DWT.VIRTUAL</code> style,
254 * these attributes are requested again as needed.
255 *
256 * @param start the start index of the item to clear
257 * @param end the end index of the item to clear
258 *
259 * @exception IllegalArgumentException <ul>
260 * <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>
261 * </ul>
262 * @exception DWTException <ul>
263 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
264 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
265 * </ul>
266 *
267 * @see DWT#VIRTUAL
268 * @see DWT#SetData
269 *
270 * @since 3.0
271 */
272 public void clear (int start, int end) {
273 checkWidget();
274 if (start > end) return;
275 if (!(0 <= start && start <= end && end < itemCount)) {
276 error (DWT.ERROR_INVALID_RANGE);
277 }
278 if (start is 0 && end is itemCount - 1) {
279 clearAll ();
280 } else {
281 for (int i=start; i<=end; i++) {
282 clear (i);
283 }
284 }
285 }
286
287 /**
288 * Clears the items at the given zero-relative indices in the receiver.
289 * The text, icon and other attributes of the items are set to their default
290 * values. If the table was created with the <code>DWT.VIRTUAL</code> style,
291 * these attributes are requested again as needed.
292 *
293 * @param indices the array of indices of the items
294 *
295 * @exception IllegalArgumentException <ul>
296 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
297 * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
298 * </ul>
299 * @exception DWTException <ul>
300 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
301 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
302 * </ul>
303 *
304 * @see DWT#VIRTUAL
305 * @see DWT#SetData
306 *
307 * @since 3.0
308 */
309 public void clear (int [] indices) {
310 checkWidget();
311 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
312 if (indices.length is 0) return;
313 for (int i=0; i<indices.length; i++) {
314 if (!(0 <= indices [i] && indices [i] < itemCount)) {
315 error (DWT.ERROR_INVALID_RANGE);
316 }
317 }
318 for (int i=0; i<indices.length; i++) {
319 clear (indices [i]);
320 }
321 }
322
323 /**
324 * Clears all the items in the receiver. The text, icon and other
325 * attributes of the items are set to their default values. If the
326 * table was created with the <code>DWT.VIRTUAL</code> style, these
327 * attributes are requested again as needed.
328 *
329 * @exception DWTException <ul>
330 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
331 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
332 * </ul>
333 *
334 * @see DWT#VIRTUAL
335 * @see DWT#SetData
336 *
337 * @since 3.0
338 */
339 public void clearAll () {
340 checkWidget();
341 for (int i=0; i<itemCount; i++) {
342 TableItem item = items [i];
343 if (item !is null) item.clear ();
344 }
345 if (currentItem is null && drawCount is 0) {
346 // OS.UpdateDataBrowserItems (handle, 0, 0, null, OS.kDataBrowserItemNoProperty, OS.kDataBrowserNoItem);
347 }
348 // setScrollWidth (items, true);
349 }
350
351 public Point computeSize (int wHint, int hHint, bool changed) {
352 checkWidget();
353 int width = 0;
354 if (wHint is DWT.DEFAULT) {
355 if (columnCount !is 0) {
356 for (int i=0; i<columnCount; i++) {
357 width += columns [i].getWidth ();
358 }
359 } else {
360 int columnWidth = 0;
361 GC gc = new GC (this);
362 for (int i=0; i<itemCount; i++) {
363 TableItem item = items [i];
364 if (item !is null) {
365 columnWidth = Math.max (columnWidth, item.calculateWidth (0, gc));
366 }
367 }
368 gc.dispose ();
369 width += columnWidth + getInsetWidth ();
370 }
371 if ((style & DWT.CHECK) !is 0) width += getCheckColumnWidth ();
372 } else {
373 width = wHint;
374 }
375 if (width <= 0) width = DEFAULT_WIDTH;
376 int height = 0;
377 if (hHint is DWT.DEFAULT) {
378 height = itemCount * getItemHeight () + getHeaderHeight();
379 } else {
380 height = hHint;
381 }
382 if (height <= 0) height = DEFAULT_HEIGHT;
383 Rectangle rect = computeTrim (0, 0, width, height);
384 return new Point (rect.width, rect.height);
385 }
386
387 void createHandle () {
388 //TODO - DWT.CHECK
389 SWTScrollView scrollWidget = (SWTScrollView)new SWTScrollView().alloc();
390 scrollWidget.initWithFrame(new NSRect ());
391 scrollWidget.setHasHorizontalScroller(true);
392 scrollWidget.setHasVerticalScroller(true);
393 scrollWidget.setAutohidesScrollers(true);
394 scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder);
395 scrollWidget.setTag(jniRef);
396
397 NSTableView widget = (NSTableView)new SWTTableView().alloc();
398 widget.initWithFrame(new NSRect());
399 widget.setAllowsMultipleSelection((style & DWT.MULTI) !is 0);
400 widget.setDataSource(widget);
401 widget.setDelegate(widget);
402 widget.setDoubleAction(OS.sel_sendDoubleSelection);
403 if (!hasBorder()) widget.setFocusRingType(OS.NSFocusRingTypeNone);
404 widget.setTag(jniRef);
405
406 headerView = widget.headerView();
407 headerView.retain();
408 widget.setHeaderView(null);
409
410 NSString str = NSString.stringWith("");
411 if ((style & DWT.CHECK) !is 0) {
412 checkColumn = (NSTableColumn)new NSTableColumn().alloc();
413 checkColumn.initWithIdentifier(str);
414 checkColumn.headerCell().setTitle(str);
415 widget.addTableColumn (checkColumn);
416 NSButtonCell cell = (NSButtonCell)new NSButtonCell().alloc().init();
417 checkColumn.setDataCell(cell);
418 cell.setButtonType(OS.NSSwitchButton);
419 cell.setImagePosition(OS.NSImageOnly);
420 cell.setAllowsMixedState(true);
421 cell.release();
422 checkColumn.setWidth(getCheckColumnWidth());
423 checkColumn.setResizingMask(OS.NSTableColumnNoResizing);
424 checkColumn.setEditable(false);
425 }
426
427 firstColumn = (NSTableColumn)new NSTableColumn().alloc();
428 firstColumn.initWithIdentifier(str);
429 //column.setResizingMask(OS.NSTableColumnAutoresizingMask);
430 NSCell cell = (NSBrowserCell)new NSBrowserCell().alloc().init();
431 firstColumn.setDataCell(cell);
432 cell.release();
433 widget.addTableColumn (firstColumn);
434
435 scrollView = scrollWidget;
436 view = widget;
437 scrollView.setDocumentView(widget);
438 parent.contentView().addSubview_(scrollView);
439 }
440
441 void createItem (TableColumn column, int index) {
442 if (!(0 <= index && index <= columnCount)) error (DWT.ERROR_INVALID_RANGE);
443 if (columnCount is columns.length) {
444 TableColumn [] newColumns = new TableColumn [columnCount + 4];
445 System.arraycopy (columns, 0, newColumns, 0, columns.length);
446 columns = newColumns;
447 }
448 NSTableColumn nsColumn;
449 if (columnCount is 0) {
450 //TODO - clear attributes, alignment etc.
451 nsColumn = firstColumn;
452 firstColumn = null;
453 } else {
454 //TODO - set attributes, alignment etc.
455 nsColumn = (NSTableColumn)new NSTableColumn().alloc();
456 nsColumn.initWithIdentifier(NSString.stringWith(""));
457 ((NSTableView)view).addTableColumn (nsColumn);
458 int checkColumn = (style & DWT.CHECK) !is 0 ? 1 : 0;
459 ((NSTableView)view).moveColumn (columnCount + checkColumn, index + checkColumn);
460 NSCell cell = (NSBrowserCell)new NSBrowserCell().alloc().init();
461 nsColumn.setDataCell(cell);
462 cell.release();
463 }
464 column.nsColumn = nsColumn;
465 nsColumn.headerCell().setTitle(NSString.stringWith(""));
466 nsColumn.setWidth(0);
467 System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
468 columns [index] = column;
469 if (columnCount > 1) {
470 for (int i=0; i<itemCount; i++) {
471 TableItem item = items [i];
472 if (item !is null) {
473 String [] strings = item.strings;
474 if (strings !is null) {
475 String [] temp = new String [columnCount];
476 System.arraycopy (strings, 0, temp, 0, index);
477 System.arraycopy (strings, index, temp, index+1, columnCount-index-1);
478 temp [index] = "";
479 item.strings = temp;
480 }
481 if (index is 0) item.text = "";
482 Image [] images = item.images;
483 if (images !is null) {
484 Image [] temp = new Image [columnCount];
485 System.arraycopy (images, 0, temp, 0, index);
486 System.arraycopy (images, index, temp, index+1, columnCount-index-1);
487 item.images = temp;
488 }
489 if (index is 0) item.image = null;
490 Color [] cellBackground = item.cellBackground;
491 if (cellBackground !is null) {
492 Color [] temp = new Color [columnCount];
493 System.arraycopy (cellBackground, 0, temp, 0, index);
494 System.arraycopy (cellBackground, index, temp, index+1, columnCount-index-1);
495 item.cellBackground = temp;
496 }
497 Color [] cellForeground = item.cellForeground;
498 if (cellForeground !is null) {
499 Color [] temp = new Color [columnCount];
500 System.arraycopy (cellForeground, 0, temp, 0, index);
501 System.arraycopy (cellForeground, index, temp, index+1, columnCount-index-1);
502 item.cellForeground = temp;
503 }
504 Font [] cellFont = item.cellFont;
505 if (cellFont !is null) {
506 Font [] temp = new Font [columnCount];
507 System.arraycopy (cellFont, 0, temp, 0, index);
508 System.arraycopy (cellFont, index, temp, index+1, columnCount-index-1);
509 item.cellFont = temp;
510 }
511 }
512 }
513 }
514 }
515
516 void createItem (TableItem item, int index) {
517 if (!(0 <= index && index <= itemCount)) error (DWT.ERROR_INVALID_RANGE);
518 if (itemCount is items.length) {
519 /* Grow the array faster when redraw is off */
520 int length = drawCount is 0 ? items.length + 4 : Math.max (4, items.length * 3 / 2);
521 TableItem [] newItems = new TableItem [length];
522 System.arraycopy (items, 0, newItems, 0, items.length);
523 items = newItems;
524 }
525 System.arraycopy (items, index, items, index + 1, itemCount++ - index);
526 items [index] = item;
527 //TODO - use noteNumberOfRowsChanged?
528 ((NSTableView)view).reloadData();
529 }
530
531 void createWidget () {
532 super.createWidget ();
533 items = new TableItem [4];
534 columns = new TableColumn [4];
535 }
536
537 Color defaultBackground () {
538 return display.getSystemColor (DWT.COLOR_LIST_BACKGROUND);
539 }
540
541 Color defaultForeground () {
542 return display.getSystemColor (DWT.COLOR_LIST_FOREGROUND);
543 }
544
545 /**
546 * Deselects the item at the given zero-relative index in the receiver.
547 * If the item at the index was already deselected, it remains
548 * deselected. Indices that are out of range are ignored.
549 *
550 * @param index the index of the item to deselect
551 *
552 * @exception DWTException <ul>
553 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
554 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
555 * </ul>
556 */
557 public void deselect (int index) {
558 checkWidget();
559 if (0 <= index && index < itemCount) {
560 NSTableView widget = (NSTableView)view;
561 ignoreSelect = true;
562 widget.deselectRow (index);
563 ignoreSelect = false;
564 }
565 }
566
567 /**
568 * Deselects the items at the given zero-relative indices in the receiver.
569 * If the item at the given zero-relative index in the receiver
570 * is selected, it is deselected. If the item at the index
571 * was not selected, it remains deselected. The range of the
572 * indices is inclusive. Indices that are out of range are ignored.
573 *
574 * @param start the start index of the items to deselect
575 * @param end the end index of the items to deselect
576 *
577 * @exception DWTException <ul>
578 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
579 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
580 * </ul>
581 */
582 public void deselect (int start, int end) {
583 checkWidget();
584 //TODO - check range
585 if (start is 0 && end is itemCount - 1) {
586 deselectAll ();
587 } else {
588 int length = end - start + 1;
589 NSTableView widget = (NSTableView)view;
590 ignoreSelect = true;
591 for (int i=0; i<length; i++) {
592 widget.deselectRow (i);
593 }
594 ignoreSelect = false;
595 }
596 }
597
598 /**
599 * Deselects the items at the given zero-relative indices in the receiver.
600 * If the item at the given zero-relative index in the receiver
601 * is selected, it is deselected. If the item at the index
602 * was not selected, it remains deselected. Indices that are out
603 * of range and duplicate indices are ignored.
604 *
605 * @param indices the array of indices for the items to deselect
606 *
607 * @exception IllegalArgumentException <ul>
608 * <li>ERROR_NULL_ARGUMENT - if the set of indices 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 void deselect (int [] indices) {
616 checkWidget();
617 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
618 NSTableView widget = (NSTableView)view;
619 ignoreSelect = true;
620 for (int i=0; i<indices.length; i++) {
621 widget.deselectRow (indices [i]);
622 }
623 ignoreSelect = false;
624 }
625
626 /**
627 * Deselects all selected items in the receiver.
628 *
629 * @exception DWTException <ul>
630 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
631 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
632 * </ul>
633 */
634 public void deselectAll () {
635 checkWidget ();
636 NSTableView widget = (NSTableView)view;
637 ignoreSelect = true;
638 widget.deselectAll(null);
639 ignoreSelect = false;
640 }
641
642 void destroyItem (TableColumn column) {
643 int index = 0;
644 while (index < columnCount) {
645 if (columns [index] is column) break;
646 index++;
647 }
648 for (int i=0; i<itemCount; i++) {
649 TableItem item = items [i];
650 if (item !is null) {
651 if (columnCount <= 1) {
652 item.strings = null;
653 item.images = null;
654 item.cellBackground = null;
655 item.cellForeground = null;
656 item.cellFont = null;
657 } else {
658 if (item.strings !is null) {
659 String [] strings = item.strings;
660 if (index is 0) {
661 item.text = strings [1] !is null ? strings [1] : "";
662 }
663 String [] temp = new String [columnCount - 1];
664 System.arraycopy (strings, 0, temp, 0, index);
665 System.arraycopy (strings, index + 1, temp, index, columnCount - 1 - index);
666 item.strings = temp;
667 } else {
668 if (index is 0) item.text = "";
669 }
670 if (item.images !is null) {
671 Image [] images = item.images;
672 if (index is 0) item.image = images [1];
673 Image [] temp = new Image [columnCount - 1];
674 System.arraycopy (images, 0, temp, 0, index);
675 System.arraycopy (images, index + 1, temp, index, columnCount - 1 - index);
676 item.images = temp;
677 } else {
678 if (index is 0) item.image = null;
679 }
680 if (item.cellBackground !is null) {
681 Color [] cellBackground = item.cellBackground;
682 Color [] temp = new Color [columnCount - 1];
683 System.arraycopy (cellBackground, 0, temp, 0, index);
684 System.arraycopy (cellBackground, index + 1, temp, index, columnCount - 1 - index);
685 item.cellBackground = temp;
686 }
687 if (item.cellForeground !is null) {
688 Color [] cellForeground = item.cellForeground;
689 Color [] temp = new Color [columnCount - 1];
690 System.arraycopy (cellForeground, 0, temp, 0, index);
691 System.arraycopy (cellForeground, index + 1, temp, index, columnCount - 1 - index);
692 item.cellForeground = temp;
693 }
694 if (item.cellFont !is null) {
695 Font [] cellFont = item.cellFont;
696 Font [] temp = new Font [columnCount - 1];
697 System.arraycopy (cellFont, 0, temp, 0, index);
698 System.arraycopy (cellFont, index + 1, temp, index, columnCount - 1 - index);
699 item.cellFont = temp;
700 }
701 }
702 }
703 }
704 if (columnCount is 1) {
705 //TODO - reset attributes
706 firstColumn = column.nsColumn;
707 firstColumn.setWidth (0);
708 } else {
709 ((NSTableView)view).removeTableColumn(column.nsColumn);
710 }
711 System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
712 columns [columnCount] = null;
713 for (int i=index; i<columnCount; i++) {
714 columns [i].sendEvent (DWT.Move);
715 }
716 }
717
718 void destroyItem (TableItem item) {
719 int index = 0;
720 while (index < itemCount) {
721 if (items [index] is item) break;
722 index++;
723 }
724 if (index !is itemCount - 1) fixSelection (index, false);
725 System.arraycopy (items, index + 1, items, index, --itemCount - index);
726 items [itemCount] = null;
727 ((NSTableView)view).noteNumberOfRowsChanged();
728 if (itemCount is 0) {
729 setTableEmpty ();
730 } else {
731 // fixScrollBar ();
732 }
733 }
734
735 void fixSelection (int index, bool add) {
736 int [] selection = getSelectionIndices ();
737 if (selection.length is 0) return;
738 int newCount = 0;
739 bool fix = false;
740 for (int i = 0; i < selection.length; i++) {
741 if (!add && selection [i] is index) {
742 fix = true;
743 } else {
744 int newIndex = newCount++;
745 selection [newIndex] = selection [i] + 1;
746 if (selection [newIndex] - 1 >= index) {
747 selection [newIndex] += add ? 1 : -1;
748 fix = true;
749 }
750 }
751 }
752 if (fix) select (selection, newCount, true);
753 }
754
755 int getCheckColumnWidth () {
756 return 20; //TODO - compute width
757 }
758
759 /**
760 * Returns the column at the given, zero-relative index in the
761 * receiver. Throws an exception if the index is out of range.
762 * Columns are returned in the order that they were created.
763 * If no <code>TableColumn</code>s were created by the programmer,
764 * this method will throw <code>ERROR_INVALID_RANGE</code> despite
765 * the fact that a single column of data may be visible in the table.
766 * This occurs when the programmer uses the table like a list, adding
767 * items but never creating a column.
768 *
769 * @param index the index of the column to return
770 * @return the column at the given index
771 *
772 * @exception IllegalArgumentException <ul>
773 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
774 * </ul>
775 * @exception DWTException <ul>
776 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
777 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
778 * </ul>
779 *
780 * @see Table#getColumnOrder()
781 * @see Table#setColumnOrder(int[])
782 * @see TableColumn#getMoveable()
783 * @see TableColumn#setMoveable(bool)
784 * @see DWT#Move
785 */
786 public TableColumn getColumn (int index) {
787 checkWidget ();
788 if (!(0 <=index && index < columnCount)) error (DWT.ERROR_INVALID_RANGE);
789 return columns [index];
790 }
791
792 /**
793 * Returns the number of columns contained in the receiver.
794 * If no <code>TableColumn</code>s were created by the programmer,
795 * this value is zero, despite the fact that visually, one column
796 * of items may be visible. This occurs when the programmer uses
797 * the table like a list, adding items but never creating a column.
798 *
799 * @return the number of columns
800 *
801 * @exception DWTException <ul>
802 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
803 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
804 * </ul>
805 */
806 public int getColumnCount () {
807 checkWidget ();
808 return columnCount;
809 }
810
811 /**
812 * Returns an array of zero-relative integers that map
813 * the creation order of the receiver's items to the
814 * order in which they are currently being displayed.
815 * <p>
816 * Specifically, the indices of the returned array represent
817 * the current visual order of the items, and the contents
818 * of the array represent the creation order of the items.
819 * </p><p>
820 * Note: This is not the actual structure used by the receiver
821 * to maintain its list of items, so modifying the array will
822 * not affect the receiver.
823 * </p>
824 *
825 * @return the current visual order of the receiver's items
826 *
827 * @exception DWTException <ul>
828 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
829 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
830 * </ul>
831 *
832 * @see Table#setColumnOrder(int[])
833 * @see TableColumn#getMoveable()
834 * @see TableColumn#setMoveable(bool)
835 * @see DWT#Move
836 *
837 * @since 3.1
838 */
839 public int [] getColumnOrder () {
840 checkWidget ();
841 int [] order = new int [columnCount];
842 int [] position = new int [1];
843 for (int i=0; i<columnCount; i++) {
844 TableColumn column = columns [i];
845 // OS.GetDataBrowserTableViewColumnPosition (handle, column.id, position);
846 // if ((style & DWT.CHECK) !is 0) position [0] -= 1;
847 order [position [0]] = i;
848 }
849 return order;
850 }
851
852 /**
853 * Returns an array of <code>TableColumn</code>s which are the
854 * columns in the receiver. Columns are returned in the order
855 * that they were created. If no <code>TableColumn</code>s were
856 * created by the programmer, the array is empty, despite the fact
857 * that visually, one column of items may be visible. This occurs
858 * when the programmer uses the table like a list, adding items but
859 * never creating a column.
860 * <p>
861 * Note: This is not the actual structure used by the receiver
862 * to maintain its list of items, so modifying the array will
863 * not affect the receiver.
864 * </p>
865 *
866 * @return the items in the receiver
867 *
868 * @exception DWTException <ul>
869 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
870 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
871 * </ul>
872 *
873 * @see Table#getColumnOrder()
874 * @see Table#setColumnOrder(int[])
875 * @see TableColumn#getMoveable()
876 * @see TableColumn#setMoveable(bool)
877 * @see DWT#Move
878 */
879 public TableColumn [] getColumns () {
880 checkWidget ();
881 TableColumn [] result = new TableColumn [columnCount];
882 System.arraycopy (columns, 0, result, 0, columnCount);
883 return result;
884 }
885
886 /**
887 * Returns the width in pixels of a grid line.
888 *
889 * @return the width of a grid line in pixels
890 *
891 * @exception DWTException <ul>
892 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
893 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
894 * </ul>
895 */
896 public int getGridLineWidth () {
897 checkWidget ();
898 return 0;
899 }
900
901 /**
902 * Returns the height of the receiver's header
903 *
904 * @return the height of the header or zero if the header is not visible
905 *
906 * @exception DWTException <ul>
907 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
908 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
909 * </ul>
910 *
911 * @since 2.0
912 */
913 public int getHeaderHeight () {
914 checkWidget ();
915 NSTableHeaderView headerView = ((NSTableView)view).headerView();
916 if (headerView is null) return 0;
917 return (int)headerView.bounds().height;
918 }
919
920 /**
921 * Returns <code>true</code> if the receiver's header is visible,
922 * and <code>false</code> otherwise.
923 * <p>
924 * If one of the receiver's ancestors is not visible or some
925 * other condition makes the receiver not visible, this method
926 * may still indicate that it is considered visible even though
927 * it may not actually be showing.
928 * </p>
929 *
930 * @return the receiver's header's visibility state
931 *
932 * @exception DWTException <ul>
933 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
934 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
935 * </ul>
936 */
937 public bool getHeaderVisible () {
938 checkWidget ();
939 return ((NSTableView)view).headerView() !is null;
940 }
941
942 int getInsetWidth () {
943 //TODO - wrong
944 return 20;
945 }
946
947 /**
948 * Returns the item at the given, zero-relative index in the
949 * receiver. Throws an exception if the index is out of range.
950 *
951 * @param index the index of the item to return
952 * @return the item at the given index
953 *
954 * @exception IllegalArgumentException <ul>
955 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
956 * </ul>
957 * @exception DWTException <ul>
958 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
959 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
960 * </ul>
961 */
962 public TableItem getItem (int index) {
963 checkWidget ();
964 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
965 return _getItem (index);
966 }
967
968 /**
969 * Returns the item at the given point in the receiver
970 * or null if no such item exists. The point is in the
971 * coordinate system of the receiver.
972 * <p>
973 * The item that is returned represents an item that could be selected by the user.
974 * For example, if selection only occurs in items in the first column, then null is
975 * returned if the point is outside of the item.
976 * Note that the DWT.FULL_SELECTION style hint, which specifies the selection policy,
977 * determines the extent of the selection.
978 * </p>
979 *
980 * @param point the point used to locate the item
981 * @return the item at the given point, or null if the point is not in a selectable item
982 *
983 * @exception IllegalArgumentException <ul>
984 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
985 * </ul>
986 * @exception DWTException <ul>
987 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
988 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
989 * </ul>
990 */
991 public TableItem getItem (Point point) {
992 checkWidget ();
993 // checkItems (true);
994 // if (point is null) error (DWT.ERROR_NULL_ARGUMENT);
995 // Rect rect = new Rect ();
996 // dwt.internal.carbon.Point pt = new dwt.internal.carbon.Point ();
997 // OS.SetPt (pt, (short) point.x, (short) point.y);
998 // if (0 < lastHittest && lastHittest <= itemCount && lastHittestColumn !is 0) {
999 // if (OS.GetDataBrowserItemPartBounds (handle, lastHittest, lastHittestColumn, OS.kDataBrowserPropertyEnclosingPart, rect) is OS.noErr) {
1000 // if (rect.top <= pt.v && pt.v <= rect.bottom) {
1001 // if ((style & DWT.FULL_SELECTION) !is 0) {
1002 // return _getItem (lastHittest - 1);
1003 // } else {
1004 // return OS.PtInRect (pt, rect) ? _getItem (lastHittest - 1) : null;
1005 // }
1006 // }
1007 // }
1008 //
1009 // }
1010 // int [] top = new int [1], left = new int [1];
1011 // OS.GetDataBrowserScrollPosition(handle, top, left);
1012 // short [] height = new short [1];
1013 // OS.GetDataBrowserTableViewRowHeight (handle, height);
1014 // short [] header = new short [1];
1015 // OS.GetDataBrowserListViewHeaderBtnHeight (handle, header);
1016 // int [] offsets = new int [] {0, 1, -1};
1017 // for (int i = 0; i < offsets.length; i++) {
1018 // int index = (top[0] - header [0] + point.y) / height [0] + offsets [i];
1019 // if (0 <= index && index < itemCount) {
1020 // if (columnCount is 0) {
1021 // if (OS.GetDataBrowserItemPartBounds (handle, index + 1, column_id, OS.kDataBrowserPropertyEnclosingPart, rect) is OS.noErr) {
1022 // if (rect.top <= pt.v && pt.v <= rect.bottom) {
1023 // if ((style & DWT.FULL_SELECTION) !is 0) {
1024 // return _getItem (index);
1025 // } else {
1026 // return OS.PtInRect (pt, rect) ? _getItem (index) : null;
1027 // }
1028 // }
1029 // }
1030 // } else {
1031 // for (int j = 0; j < columnCount; j++) {
1032 // if (OS.GetDataBrowserItemPartBounds (handle, index + 1, columns [j].id, OS.kDataBrowserPropertyEnclosingPart, rect) is OS.noErr) {
1033 // if (rect.top <= pt.v && pt.v <= rect.bottom) {
1034 // if ((style & DWT.FULL_SELECTION) !is 0) {
1035 // return _getItem (index);
1036 // } else {
1037 // return OS.PtInRect (pt, rect) ? _getItem (index) : null;
1038 // }
1039 // }
1040 // }
1041 // }
1042 // }
1043 // }
1044 // }
1045 // //TODO - optimize
1046 // for (int i=0; i<itemCount; i++) {
1047 // if (columnCount is 0) {
1048 // if (OS.GetDataBrowserItemPartBounds (handle, i + 1, column_id, OS.kDataBrowserPropertyEnclosingPart, rect) is OS.noErr) {
1049 // if (rect.top <= pt.v && pt.v <= rect.bottom) {
1050 // if ((style & DWT.FULL_SELECTION) !is 0) {
1051 // return _getItem (i);
1052 // } else {
1053 // return OS.PtInRect (pt, rect) ? _getItem (i) : null;
1054 // }
1055 // }
1056 // }
1057 // } else {
1058 // for (int j = 0; j < columnCount; j++) {
1059 // if (OS.GetDataBrowserItemPartBounds (handle, i + 1, columns [j].id, OS.kDataBrowserPropertyEnclosingPart, rect) is OS.noErr) {
1060 // if (rect.top <= pt.v && pt.v <= rect.bottom) {
1061 // if ((style & DWT.FULL_SELECTION) !is 0) {
1062 // return _getItem (i);
1063 // } else {
1064 // return OS.PtInRect (pt, rect) ? _getItem (i) : null;
1065 // }
1066 // }
1067 // }
1068 // }
1069 // }
1070 // }
1071 return null;
1072 }
1073
1074 /**
1075 * Returns the number of items contained in the receiver.
1076 *
1077 * @return the number of items
1078 *
1079 * @exception DWTException <ul>
1080 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1081 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1082 * </ul>
1083 */
1084 public int getItemCount () {
1085 checkWidget ();
1086 return itemCount;
1087 }
1088
1089 /**
1090 * Returns the height of the area which would be used to
1091 * display <em>one</em> of the items in the receiver's.
1092 *
1093 * @return the height of one item
1094 *
1095 * @exception DWTException <ul>
1096 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1097 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1098 * </ul>
1099 */
1100 public int getItemHeight () {
1101 checkWidget ();
1102 return (int)((NSTableView)view).rowHeight();
1103 }
1104
1105 /**
1106 * Returns a (possibly empty) array of <code>TableItem</code>s which
1107 * are the items in the receiver.
1108 * <p>
1109 * Note: This is not the actual structure used by the receiver
1110 * to maintain its list of items, so modifying the array will
1111 * not affect the receiver.
1112 * </p>
1113 *
1114 * @return the items in the receiver
1115 *
1116 * @exception DWTException <ul>
1117 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1118 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1119 * </ul>
1120 */
1121 public TableItem [] getItems () {
1122 checkWidget ();
1123 TableItem [] result = new TableItem [itemCount];
1124 if ((style & DWT.VIRTUAL) !is 0) {
1125 for (int i=0; i<itemCount; i++) {
1126 result [i] = _getItem (i);
1127 }
1128 } else {
1129 System.arraycopy (items, 0, result, 0, itemCount);
1130 }
1131 return result;
1132 }
1133
1134 /**
1135 * Returns <code>true</code> if the receiver's lines are visible,
1136 * and <code>false</code> otherwise.
1137 * <p>
1138 * If one of the receiver's ancestors is not visible or some
1139 * other condition makes the receiver not visible, this method
1140 * may still indicate that it is considered visible even though
1141 * it may not actually be showing.
1142 * </p>
1143 *
1144 * @return the visibility state of the lines
1145 *
1146 * @exception DWTException <ul>
1147 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1148 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1149 * </ul>
1150 */
1151 public bool getLinesVisible () {
1152 checkWidget ();
1153 // if (OS.VERSION >= 0x1040) {
1154 // int [] attrib = new int [1];
1155 // OS.DataBrowserGetAttributes (handle, attrib);
1156 // return (attrib [0] & (OS.kDataBrowserAttributeListViewAlternatingRowColors | OS.kDataBrowserAttributeListViewDrawColumnDividers)) !is 0;
1157 // }
1158 return false;
1159 }
1160
1161 /**
1162 * Returns an array of <code>TableItem</code>s that are currently
1163 * selected in the receiver. The order of the items is unspecified.
1164 * An empty array indicates that no items are selected.
1165 * <p>
1166 * Note: This is not the actual structure used by the receiver
1167 * to maintain its selection, so modifying the array will
1168 * not affect the receiver.
1169 * </p>
1170 * @return an array representing the selection
1171 *
1172 * @exception DWTException <ul>
1173 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1174 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1175 * </ul>
1176 */
1177 public TableItem [] getSelection () {
1178 checkWidget ();
1179 NSTableView widget = (NSTableView)view;
1180 if (widget.numberOfSelectedRows() is 0) {
1181 return new TableItem [0];
1182 }
1183 NSIndexSet selection = widget.selectedRowIndexes();
1184 int count = selection.count();
1185 int [] indexBuffer = new int [count];
1186 selection.getIndexes(indexBuffer, count, 0);
1187 TableItem [] result = new TableItem [count];
1188 for (int i=0; i<count; i++) {
1189 result [i] = _getItem (indexBuffer [i]);
1190 }
1191 return result;
1192 }
1193
1194 /**
1195 * Returns the number of selected items contained in the receiver.
1196 *
1197 * @return the number of selected items
1198 *
1199 * @exception DWTException <ul>
1200 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1201 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1202 * </ul>
1203 */
1204 public int getSelectionCount () {
1205 checkWidget ();
1206 return ((NSTableView)view).numberOfSelectedRows();
1207 }
1208
1209 /**
1210 * Returns the zero-relative index of the item which is currently
1211 * selected in the receiver, or -1 if no item is selected.
1212 *
1213 * @return the index of the selected item
1214 *
1215 * @exception DWTException <ul>
1216 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1217 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1218 * </ul>
1219 */
1220 public int getSelectionIndex () {
1221 checkWidget();
1222 //TODO - check empty selection case
1223 return ((NSTableView)view).selectedRow();
1224 }
1225
1226 /**
1227 * Returns the zero-relative indices of the items which are currently
1228 * selected in the receiver. The order of the indices is unspecified.
1229 * The array is empty if no items are selected.
1230 * <p>
1231 * Note: This is not the actual structure used by the receiver
1232 * to maintain its selection, so modifying the array will
1233 * not affect the receiver.
1234 * </p>
1235 * @return the array of indices of the selected items
1236 *
1237 * @exception DWTException <ul>
1238 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1239 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1240 * </ul>
1241 */
1242 public int [] getSelectionIndices () {
1243 checkWidget ();
1244 NSTableView widget = (NSTableView)view;
1245 if (widget.numberOfSelectedRows() is 0) {
1246 return new int [0];
1247 }
1248 NSIndexSet selection = widget.selectedRowIndexes();
1249 int count = selection.count();
1250 int [] result = new int [count];
1251 selection.getIndexes(result, count, 0);
1252 return result;
1253 }
1254
1255 /**
1256 * Returns the column which shows the sort indicator for
1257 * the receiver. The value may be null if no column shows
1258 * the sort indicator.
1259 *
1260 * @return the sort indicator
1261 *
1262 * @exception DWTException <ul>
1263 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1264 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1265 * </ul>
1266 *
1267 * @see #setSortColumn(TableColumn)
1268 *
1269 * @since 3.2
1270 */
1271 public TableColumn getSortColumn () {
1272 checkWidget ();
1273 return sortColumn;
1274 }
1275
1276 /**
1277 * Returns the direction of the sort indicator for the receiver.
1278 * The value will be one of <code>UP</code>, <code>DOWN</code>
1279 * or <code>NONE</code>.
1280 *
1281 * @return the sort direction
1282 *
1283 * @exception DWTException <ul>
1284 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1285 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1286 * </ul>
1287 *
1288 * @see #setSortDirection(int)
1289 *
1290 * @since 3.2
1291 */
1292 public int getSortDirection () {
1293 checkWidget ();
1294 return sortDirection;
1295 }
1296
1297 /**
1298 * Returns the zero-relative index of the item which is currently
1299 * at the top of the receiver. This index can change when items are
1300 * scrolled or new items are added or removed.
1301 *
1302 * @return the index of the top item
1303 *
1304 * @exception DWTException <ul>
1305 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1306 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1307 * </ul>
1308 */
1309 public int getTopIndex () {
1310 checkWidget();
1311 //TODO - partial item at the top
1312 NSRect rect = scrollView.documentVisibleRect();
1313 NSPoint point = new NSPoint();
1314 point.x = rect.x;
1315 point.y = rect.y;
1316 return ((NSTableView)view).rowAtPoint(point);
1317 }
1318
1319
1320 /**
1321 * Searches the receiver's list starting at the first column
1322 * (index 0) until a column is found that is equal to the
1323 * argument, and returns the index of that column. If no column
1324 * is found, returns -1.
1325 *
1326 * @param column the search column
1327 * @return the index of the column
1328 *
1329 * @exception IllegalArgumentException <ul>
1330 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
1331 * </ul>
1332 * @exception DWTException <ul>
1333 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1334 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1335 * </ul>
1336 */
1337 public int indexOf (TableColumn column) {
1338 checkWidget ();
1339 if (column is null) error (DWT.ERROR_NULL_ARGUMENT);
1340 for (int i=0; i<columnCount; i++) {
1341 if (columns [i] is column) return i;
1342 }
1343 return -1;
1344 }
1345
1346 /**
1347 * Searches the receiver's list starting at the first item
1348 * (index 0) until an item is found that is equal to the
1349 * argument, and returns the index of that item. If no item
1350 * is found, returns -1.
1351 *
1352 * @param item the search item
1353 * @return the index of the item
1354 *
1355 * @exception IllegalArgumentException <ul>
1356 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
1357 * </ul>
1358 * @exception DWTException <ul>
1359 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1360 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1361 * </ul>
1362 */
1363 public int indexOf (TableItem item) {
1364 checkWidget ();
1365 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
1366 if (1 <= lastIndexOf && lastIndexOf < itemCount - 1) {
1367 if (items [lastIndexOf] is item) return lastIndexOf;
1368 if (items [lastIndexOf + 1] is item) return ++lastIndexOf;
1369 if (items [lastIndexOf - 1] is item) return --lastIndexOf;
1370 }
1371 if (lastIndexOf < itemCount / 2) {
1372 for (int i=0; i<itemCount; i++) {
1373 if (items [i] is item) return lastIndexOf = i;
1374 }
1375 } else {
1376 for (int i=itemCount - 1; i>=0; --i) {
1377 if (items [i] is item) return lastIndexOf = i;
1378 }
1379 }
1380 return -1;
1381 }
1382
1383 /**
1384 * Returns <code>true</code> if the item is selected,
1385 * and <code>false</code> otherwise. Indices out of
1386 * range are ignored.
1387 *
1388 * @param index the index of the item
1389 * @return the selection state of the item at the index
1390 *
1391 * @exception DWTException <ul>
1392 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1393 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1394 * </ul>
1395 */
1396 public bool isSelected (int index) {
1397 checkWidget();
1398 //TODO - range check
1399 return ((NSTableView)view).isRowSelected(index);
1400 }
1401
1402 int numberOfRowsInTableView(int aTableView) {
1403 return itemCount;
1404 }
1405
1406 void releaseChildren (bool destroy) {
1407 if (items !is null) {
1408 for (int i=0; i<itemCount; i++) {
1409 TableItem item = items [i];
1410 if (item !is null && !item.isDisposed ()) {
1411 item.release (false);
1412 }
1413 }
1414 items = null;
1415 }
1416 if (columns !is null) {
1417 for (int i=0; i<columnCount; i++) {
1418 TableColumn column = columns [i];
1419 if (column !is null && !column.isDisposed ()) {
1420 column.release (false);
1421 }
1422 }
1423 columns = null;
1424 }
1425 super.releaseChildren (destroy);
1426 }
1427
1428 void releaseHandle () {
1429 super.releaseHandle ();
1430 if (headerView !is null) headerView.release();
1431 headerView = null;
1432 if (firstColumn !is null) firstColumn.release();
1433 firstColumn = null;
1434 if (checkColumn !is null) checkColumn.release();
1435 checkColumn = null;
1436 }
1437
1438 void releaseWidget () {
1439 super.releaseWidget ();
1440 currentItem = null;
1441 sortColumn = null;
1442 }
1443
1444 /**
1445 * Removes the item from the receiver at the given
1446 * zero-relative index.
1447 *
1448 * @param index the index for the item
1449 *
1450 * @exception IllegalArgumentException <ul>
1451 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1452 * </ul>
1453 * @exception DWTException <ul>
1454 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1455 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1456 * </ul>
1457 */
1458 public void remove (int index) {
1459 checkWidget();
1460 if (!(0 <= index && index < itemCount)) error (DWT.ERROR_INVALID_RANGE);
1461 TableItem item = items [index];
1462 if (item !is null) item.release (false);
1463 if (index !is itemCount - 1) fixSelection (index, false);
1464 System.arraycopy (items, index + 1, items, index, --itemCount - index);
1465 items [itemCount] = null;
1466 ((NSTableView)view).noteNumberOfRowsChanged();
1467 if (itemCount is 0) {
1468 setTableEmpty ();
1469 } else {
1470 // fixScrollBar ();
1471 }
1472 }
1473
1474 /**
1475 * Removes the items from the receiver which are
1476 * between the given zero-relative start and end
1477 * indices (inclusive).
1478 *
1479 * @param start the start of the range
1480 * @param end the end of the range
1481 *
1482 * @exception IllegalArgumentException <ul>
1483 * <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>
1484 * </ul>
1485 * @exception DWTException <ul>
1486 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1487 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1488 * </ul>
1489 */
1490 public void remove (int start, int end) {
1491 checkWidget();
1492 if (start > end) return;
1493 if (!(0 <= start && start <= end && end < itemCount)) {
1494 error (DWT.ERROR_INVALID_RANGE);
1495 }
1496 if (start is 0 && end is itemCount - 1) {
1497 removeAll ();
1498 } else {
1499 int length = end - start + 1;
1500 for (int i=0; i<length; i++) remove (start);
1501 }
1502 }
1503
1504 /**
1505 * Removes the items from the receiver's list at the given
1506 * zero-relative indices.
1507 *
1508 * @param indices the array of indices of the items
1509 *
1510 * @exception IllegalArgumentException <ul>
1511 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1512 * <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
1513 * </ul>
1514 * @exception DWTException <ul>
1515 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1516 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1517 * </ul>
1518 */
1519 public void remove (int [] indices) {
1520 checkWidget ();
1521 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
1522 if (indices.length is 0) return;
1523 int [] newIndices = new int [indices.length];
1524 System.arraycopy (indices, 0, newIndices, 0, indices.length);
1525 sort (newIndices);
1526 int start = newIndices [newIndices.length - 1], end = newIndices [0];
1527 if (!(0 <= start && start <= end && end < itemCount)) {
1528 error (DWT.ERROR_INVALID_RANGE);
1529 }
1530 int last = -1;
1531 for (int i=0; i<newIndices.length; i++) {
1532 int index = newIndices [i];
1533 if (index !is last) {
1534 remove (index);
1535 last = index;
1536 }
1537 }
1538 }
1539
1540 /**
1541 * Removes all of the items from the receiver.
1542 *
1543 * @exception DWTException <ul>
1544 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1545 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1546 * </ul>
1547 */
1548 public void removeAll () {
1549 checkWidget();
1550 for (int i=0; i<itemCount; i++) {
1551 TableItem item = items [i];
1552 if (item !is null && !item.isDisposed ()) item.release (false);
1553 }
1554 setTableEmpty ();
1555 ((NSTableView)view).noteNumberOfRowsChanged();
1556 }
1557
1558 /**
1559 * Removes the listener from the collection of listeners who will
1560 * be notified when the user changes the receiver's selection.
1561 *
1562 * @param listener the listener which should no longer be notified
1563 *
1564 * @exception IllegalArgumentException <ul>
1565 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1566 * </ul>
1567 * @exception DWTException <ul>
1568 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1569 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1570 * </ul>
1571 *
1572 * @see SelectionListener
1573 * @see #addSelectionListener(SelectionListener)
1574 */
1575 public void removeSelectionListener(SelectionListener listener) {
1576 checkWidget ();
1577 if (listener is null) error (DWT.ERROR_NULL_ARGUMENT);
1578 if (eventTable is null) return;
1579 eventTable.unhook (DWT.Selection, listener);
1580 eventTable.unhook (DWT.DefaultSelection,listener);
1581 }
1582
1583 /**
1584 * Selects the item at the given zero-relative index in the receiver.
1585 * If the item at the index was already selected, it remains
1586 * selected. Indices that are out of range are ignored.
1587 *
1588 * @param index the index of the item to select
1589 *
1590 * @exception DWTException <ul>
1591 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1592 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1593 * </ul>
1594 */
1595 public void select (int index) {
1596 checkWidget();
1597 if (0 <= index && index < itemCount) {
1598 NSIndexSet indexes = (NSIndexSet)new NSIndexSet().alloc();
1599 indexes.initWithIndex(index);
1600 NSTableView widget = (NSTableView)view;
1601 ignoreSelect = true;
1602 ((NSTableView)view).selectRowIndexes(indexes, true);
1603 ignoreSelect = false;
1604 }
1605 }
1606
1607 /**
1608 * Selects the items in the range specified by the given zero-relative
1609 * indices in the receiver. The range of indices is inclusive.
1610 * The current selection is not cleared before the new items are selected.
1611 * <p>
1612 * If an item in the given range is not selected, it is selected.
1613 * If an item in the given range was already selected, it remains selected.
1614 * Indices that are out of range are ignored and no items will be selected
1615 * if start is greater than end.
1616 * If the receiver is single-select and there is more than one item in the
1617 * given range, then all indices are ignored.
1618 * </p>
1619 *
1620 * @param start the start of the range
1621 * @param end the end of the range
1622 *
1623 * @exception DWTException <ul>
1624 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1625 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1626 * </ul>
1627 *
1628 * @see Table#setSelection(int,int)
1629 */
1630 public void select (int start, int end) {
1631 checkWidget ();
1632 if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return;
1633 if (itemCount is 0 || start >= itemCount) return;
1634 if (start is 0 && end is itemCount - 1) {
1635 selectAll ();
1636 } else {
1637 start = Math.max (0, start);
1638 end = Math.min (end, itemCount - 1);
1639 int length = end - start + 1;
1640 NSIndexSet indexes = (NSIndexSet)new NSIndexSet().alloc();
1641 NSRange range = new NSRange();
1642 range.location = start;
1643 range.length = length;
1644 indexes.initWithIndexesInRange(range);
1645 NSTableView widget = (NSTableView)view;
1646 ignoreSelect = true;
1647 widget.selectRowIndexes(indexes, true);
1648 ignoreSelect = false;
1649 }
1650 }
1651
1652 /**
1653 * Selects the items at the given zero-relative indices in the receiver.
1654 * The current selection is not cleared before the new items are selected.
1655 * <p>
1656 * If the item at a given index is not selected, it is selected.
1657 * If the item at a given index was already selected, it remains selected.
1658 * Indices that are out of range and duplicate indices are ignored.
1659 * If the receiver is single-select and multiple indices are specified,
1660 * then all indices are ignored.
1661 * </p>
1662 *
1663 * @param indices the array of indices for the items to select
1664 *
1665 * @exception IllegalArgumentException <ul>
1666 * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1667 * </ul>
1668 * @exception DWTException <ul>
1669 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1670 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1671 * </ul>
1672 *
1673 * @see Table#setSelection(int[])
1674 */
1675 public void select (int [] indices) {
1676 checkWidget ();
1677 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
1678 int length = indices.length;
1679 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
1680 int count = 0;
1681 NSMutableIndexSet indexes = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
1682 for (int i=0; i<length; i++) {
1683 int index = indices [length - i - 1];
1684 if (index >= 0 && index < itemCount) {
1685 indexes.addIndex (indices [i]);
1686 count++;
1687 }
1688 }
1689 if (count > 0) {
1690 NSTableView widget = (NSTableView)view;
1691 ignoreSelect = true;
1692 widget.selectRowIndexes(indexes, true);
1693 ignoreSelect = false;
1694 }
1695 }
1696
1697 void select (int [] ids, int count, bool clear) {
1698 NSMutableIndexSet indexes = (NSMutableIndexSet)new NSMutableIndexSet().alloc().init();
1699 for (int i=0; i<count; i++) indexes.addIndex (ids [i] - 1); //WRONG -1
1700 NSTableView widget = (NSTableView)view;
1701 ignoreSelect = true;
1702 widget.selectRowIndexes(indexes, !clear);
1703 ignoreSelect = false;
1704 }
1705
1706 /**
1707 * Selects all of the items in the receiver.
1708 * <p>
1709 * If the receiver is single-select, do nothing.
1710 * </p>
1711 *
1712 * @exception DWTException <ul>
1713 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1714 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1715 * </ul>
1716 */
1717 public void selectAll () {
1718 checkWidget ();
1719 if ((style & DWT.SINGLE) !is 0) return;
1720 NSTableView widget = (NSTableView)view;
1721 ignoreSelect = true;
1722 widget.selectAll(null);
1723 ignoreSelect = false;
1724 }
1725
1726 /**
1727 * Sets the order that the items in the receiver should
1728 * be displayed in to the given argument which is described
1729 * in terms of the zero-relative ordering of when the items
1730 * were added.
1731 *
1732 * @param order the new order to display the items
1733 *
1734 * @exception DWTException <ul>
1735 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1736 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1737 * </ul>
1738 * @exception IllegalArgumentException <ul>
1739 * <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
1740 * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
1741 * </ul>
1742 *
1743 * @see Table#getColumnOrder()
1744 * @see TableColumn#getMoveable()
1745 * @see TableColumn#setMoveable(bool)
1746 * @see DWT#Move
1747 *
1748 * @since 3.1
1749 */
1750 public void setColumnOrder (int [] order) {
1751 checkWidget ();
1752 if (order is null) error (DWT.ERROR_NULL_ARGUMENT);
1753 if (columnCount is 0) {
1754 if (order.length !is 0) error (DWT.ERROR_INVALID_ARGUMENT);
1755 return;
1756 }
1757 if (order.length !is columnCount) error (DWT.ERROR_INVALID_ARGUMENT);
1758 int [] oldOrder = getColumnOrder ();
1759 bool reorder = false;
1760 bool [] seen = new bool [columnCount];
1761 for (int i=0; i<order.length; i++) {
1762 int index = order [i];
1763 if (index < 0 || index >= columnCount) error (DWT.ERROR_INVALID_ARGUMENT);
1764 if (seen [index]) error (DWT.ERROR_INVALID_ARGUMENT);
1765 seen [index] = true;
1766 if (order [i] !is oldOrder [i]) reorder = true;
1767 }
1768 if (reorder) {
1769 int x = 0;
1770 short [] width = new short [1];
1771 int [] oldX = new int [oldOrder.length];
1772 for (int i=0; i<oldOrder.length; i++) {
1773 int index = oldOrder [i];
1774 TableColumn column = columns [index];
1775 oldX [index] = x;
1776 // OS.GetDataBrowserTableViewNamedColumnWidth(handle, column.id, width);
1777 x += width [0];
1778 }
1779 x = 0;
1780 int [] newX = new int [order.length];
1781 for (int i=0; i<order.length; i++) {
1782 int index = order [i];
1783 TableColumn column = columns [index];
1784 int position = (style & DWT.CHECK) !is 0 ? i + 1 : i;
1785 // OS.SetDataBrowserTableViewColumnPosition(handle, column.id, position);
1786 // column.lastPosition = position;
1787 newX [index] = x;
1788 // OS.GetDataBrowserTableViewNamedColumnWidth(handle, column.id, width);
1789 x += width [0];
1790 }
1791 TableColumn[] newColumns = new TableColumn [columnCount];
1792 System.arraycopy (columns, 0, newColumns, 0, columnCount);
1793 for (int i=0; i<columnCount; i++) {
1794 TableColumn column = newColumns [i];
1795 if (!column.isDisposed ()) {
1796 if (newX [i] !is oldX [i]) {
1797 column.sendEvent (DWT.Move);
1798 }
1799 }
1800 }
1801 }
1802 }
1803
1804 /**
1805 * Marks the receiver's header as visible if the argument is <code>true</code>,
1806 * and marks it invisible otherwise.
1807 * <p>
1808 * If one of the receiver's ancestors is not visible or some
1809 * other condition makes the receiver not visible, marking
1810 * it visible may not actually cause it to be displayed.
1811 * </p>
1812 *
1813 * @param show the new visibility state
1814 *
1815 * @exception DWTException <ul>
1816 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1817 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1818 * </ul>
1819 */
1820 public void setHeaderVisible (bool show) {
1821 checkWidget ();
1822 ((NSTableView)view).setHeaderView (show ? headerView : null);
1823 }
1824
1825 /**
1826 * Sets the number of items contained in the receiver.
1827 *
1828 * @param count the number of items
1829 *
1830 * @exception DWTException <ul>
1831 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1832 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1833 * </ul>
1834 *
1835 * @since 3.0
1836 */
1837 public void setItemCount (int count) {
1838 checkWidget ();
1839 // checkItems (true);
1840 // count = Math.max (0, count);
1841 // if (count is itemCount) return;
1842 // setRedraw (false);
1843 // int[] top = new int [1], left = new int [1];
1844 // OS.GetDataBrowserScrollPosition (handle, top, left);
1845 // DataBrowserCallbacks callbacks = new DataBrowserCallbacks ();
1846 // OS.GetDataBrowserCallbacks (handle, callbacks);
1847 // callbacks.v1_itemNotificationCallback = 0;
1848 // callbacks.v1_itemCompareCallback = 0;
1849 // OS.SetDataBrowserCallbacks (handle, callbacks);
1850 // if (count < itemCount) {
1851 // int index = count;
1852 // int[] id = new int [itemCount - count];
1853 // while (index < itemCount) {
1854 // TableItem item = items [index];
1855 // if (item !is null) item.release (false);
1856 // id [index-count] = index + 1;
1857 // index++;
1858 // }
1859 // OS.RemoveDataBrowserItems (handle, OS.kDataBrowserNoItem, id.length, id, 0);
1860 // int [] newItemCount = new int [1];
1861 // if (OS.GetDataBrowserItemCount (handle, OS.kDataBrowserNoItem, true, OS.kDataBrowserItemAnyState, newItemCount) !is OS.noErr) {
1862 // error (DWT.ERROR_CANNOT_GET_COUNT);
1863 // }
1864 // if (count !is newItemCount[0]) error (DWT.ERROR_ITEM_NOT_REMOVED);
1865 // }
1866 // int length = Math.max (4, (count + 3) / 4 * 4);
1867 // TableItem [] newItems = new TableItem [length];
1868 // System.arraycopy (items, 0, newItems, 0, Math.min (count, itemCount));
1869 // items = newItems;
1870 // if ((style & DWT.VIRTUAL) is 0) {
1871 // for (int i=itemCount; i<count; i++) {
1872 // items [i] = new TableItem (this, DWT.NONE, i, false);
1873 // }
1874 // }
1875 // itemCount = count;
1876 // OS.AddDataBrowserItems (handle, 0, itemCount, null, OS.kDataBrowserItemNoProperty);
1877 // callbacks.v1_itemNotificationCallback = display.itemNotificationProc;
1878 // callbacks.v1_itemCompareCallback = itemCompareProc ();
1879 // OS.SetDataBrowserCallbacks (handle, callbacks);
1880 // fixScrollBar ();
1881 // setRedraw (true);
1882 }
1883
1884 /*public*/ void setItemHeight (int itemHeight) {
1885 checkWidget ();
1886 if (itemHeight < -1) error (DWT.ERROR_INVALID_ARGUMENT);
1887 if (itemHeight is -1) {
1888 //TODO - reset item height, ensure other API's such as setFont don't do this
1889 } else {
1890 // OS.SetDataBrowserTableViewRowHeight (handle, (short) itemHeight);
1891 }
1892 }
1893
1894 /**
1895 * Marks the receiver's lines as visible if the argument is <code>true</code>,
1896 * and marks it invisible otherwise.
1897 * <p>
1898 * If one of the receiver's ancestors is not visible or some
1899 * other condition makes the receiver not visible, marking
1900 * it visible may not actually cause it to be displayed.
1901 * </p>
1902 *
1903 * @param show the new visibility state
1904 *
1905 * @exception DWTException <ul>
1906 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1907 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1908 * </ul>
1909 */
1910 public void setLinesVisible (bool show) {
1911 checkWidget ();
1912 ((NSTableView)view).setUsesAlternatingRowBackgroundColors(show);
1913 }
1914
1915 bool setScrollWidth (TableItem item) {
1916 if (columnCount !is 0) return false;
1917 if (currentItem !is null) {
1918 // if (currentItem !is item) fixScrollWidth = true;
1919 return false;
1920 }
1921 if (drawCount !is 0) return false;
1922 GC gc = new GC (this);
1923 int newWidth = item.calculateWidth (0, gc);
1924 gc.dispose ();
1925 newWidth += getInsetWidth ();
1926 // short [] width = new short [1];
1927 // OS.GetDataBrowserTableViewNamedColumnWidth (handle, column_id, width);
1928 // if (width [0] < newWidth) {
1929 // OS.SetDataBrowserTableViewNamedColumnWidth (handle, column_id, (short) newWidth);
1930 // return true;
1931 // }
1932 if (firstColumn.width() < newWidth) {
1933 firstColumn.setWidth (newWidth);
1934 }
1935 return false;
1936 }
1937
1938 bool setScrollWidth (TableItem [] items, bool set) {
1939 if (columnCount !is 0) return false;
1940 if (currentItem !is null) {
1941 // fixScrollWidth = true;
1942 return false;
1943 }
1944 if (drawCount !is 0) return false;
1945 GC gc = new GC (this);
1946 int newWidth = 0;
1947 for (int i = 0; i < items.length; i++) {
1948 TableItem item = items [i];
1949 if (item !is null) {
1950 newWidth = Math.max (newWidth, item.calculateWidth (0, gc));
1951 }
1952 }
1953 gc.dispose ();
1954 newWidth += getInsetWidth ();
1955 // if (!set) {
1956 // short [] width = new short [1];
1957 // OS.GetDataBrowserTableViewNamedColumnWidth (handle, column_id, width);
1958 // if (width [0] >= newWidth) return false;
1959 // }
1960 // OS.SetDataBrowserTableViewNamedColumnWidth (handle, column_id, (short) newWidth);
1961 if (!set) {
1962 if (firstColumn.width() > newWidth) return false;
1963 }
1964 firstColumn.setWidth (newWidth);
1965 return true;
1966 }
1967
1968 /**
1969 * Selects the item at the given zero-relative index in the receiver.
1970 * The current selection is first cleared, then the new item is selected.
1971 *
1972 * @param index the index of the item to select
1973 *
1974 * @exception DWTException <ul>
1975 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1976 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1977 * </ul>
1978 *
1979 * @see Table#deselectAll()
1980 * @see Table#select(int)
1981 */
1982 public void setSelection (int index) {
1983 checkWidget();
1984 //TODO - optimize to use expand flag
1985 deselectAll ();
1986 setSelection (index, false);
1987 }
1988
1989 void setSelection (int index, bool notify) {
1990 // checkWidget();
1991 if (0 <= index && index < itemCount) {
1992 select (index);
1993 showIndex (index);
1994 if (notify) {
1995 Event event = new Event ();
1996 event.item = _getItem (index);
1997 postEvent (DWT.Selection, event);
1998 }
1999 }
2000 }
2001
2002 /**
2003 * Selects the items in the range specified by the given zero-relative
2004 * indices in the receiver. The range of indices is inclusive.
2005 * The current selection is cleared before the new items are selected.
2006 * <p>
2007 * Indices that are out of range are ignored and no items will be selected
2008 * if start is greater than end.
2009 * If the receiver is single-select and there is more than one item in the
2010 * given range, then all indices are ignored.
2011 * </p>
2012 *
2013 * @param start the start index of the items to select
2014 * @param end the end index of the items to select
2015 *
2016 * @exception DWTException <ul>
2017 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2018 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2019 * </ul>
2020 *
2021 * @see Table#deselectAll()
2022 * @see Table#select(int,int)
2023 */
2024 public void setSelection (int start, int end) {
2025 checkWidget ();
2026 //TODO - optimize to use expand flag
2027 deselectAll ();
2028 if (end < 0 || start > end || ((style & DWT.SINGLE) !is 0 && start !is end)) return;
2029 if (itemCount is 0 || start >= itemCount) return;
2030 start = Math.max (0, start);
2031 end = Math.min (end, itemCount - 1);
2032 select (start, end);
2033 showIndex (start);
2034 }
2035
2036 /**
2037 * Selects the items at the given zero-relative indices in the receiver.
2038 * The current selection is cleared before the new items are selected.
2039 * <p>
2040 * Indices that are out of range and duplicate indices are ignored.
2041 * If the receiver is single-select and multiple indices are specified,
2042 * then all indices are ignored.
2043 * </p>
2044 *
2045 * @param indices the indices of the items to select
2046 *
2047 * @exception IllegalArgumentException <ul>
2048 * <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
2049 * </ul>
2050 * @exception DWTException <ul>
2051 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2052 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2053 * </ul>
2054 *
2055 * @see Table#deselectAll()
2056 * @see Table#select(int[])
2057 */
2058 public void setSelection (int [] indices) {
2059 checkWidget ();
2060 if (indices is null) error (DWT.ERROR_NULL_ARGUMENT);
2061 //TODO - optimize to use expand flag
2062 deselectAll ();
2063 int length = indices.length;
2064 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
2065 select (indices);
2066 showIndex (indices [0]);
2067 }
2068
2069 /**
2070 * Sets the receiver's selection to the given item.
2071 * The current selection is cleared before the new item is selected.
2072 * <p>
2073 * If the item is not in the receiver, then it is ignored.
2074 * </p>
2075 *
2076 * @param item the item to select
2077 *
2078 * @exception IllegalArgumentException <ul>
2079 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
2080 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
2081 * </ul>
2082 * @exception DWTException <ul>
2083 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2084 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2085 * </ul>
2086 *
2087 * @since 3.2
2088 */
2089 public void setSelection (TableItem item) {
2090 checkWidget ();
2091 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
2092 setSelection (new TableItem [] {item});
2093 }
2094
2095 /**
2096 * Sets the receiver's selection to be the given array of items.
2097 * The current selection is cleared before the new items are selected.
2098 * <p>
2099 * Items that are not in the receiver are ignored.
2100 * If the receiver is single-select and multiple items are specified,
2101 * then all items are ignored.
2102 * </p>
2103 *
2104 * @param items the array of items
2105 *
2106 * @exception IllegalArgumentException <ul>
2107 * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
2108 * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
2109 * </ul>
2110 * @exception DWTException <ul>
2111 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2112 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2113 * </ul>
2114 *
2115 * @see Table#deselectAll()
2116 * @see Table#select(int[])
2117 * @see Table#setSelection(int[])
2118 */
2119 public void setSelection (TableItem [] items) {
2120 checkWidget ();
2121 if (items is null) error (DWT.ERROR_NULL_ARGUMENT);
2122 //TODO - optimize to use expand flag
2123 deselectAll ();
2124 int length = items.length;
2125 if (length is 0 || ((style & DWT.SINGLE) !is 0 && length > 1)) return;
2126 int [] indices = new int [length];
2127 int count = 0;
2128 for (int i=0; i<length; i++) {
2129 int index = indexOf (items [length - i - 1]);
2130 if (index !is -1) {
2131 indices [count++] = index;
2132 }
2133 }
2134 if (count > 0) {
2135 select (indices);
2136 showIndex (indices [0] - 1);
2137 }
2138 }
2139
2140 /**
2141 * Sets the column used by the sort indicator for the receiver. A null
2142 * value will clear the sort indicator. The current sort column is cleared
2143 * before the new column is set.
2144 *
2145 * @param column the column used by the sort indicator or <code>null</code>
2146 *
2147 * @exception IllegalArgumentException <ul>
2148 * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
2149 * </ul>
2150 * @exception DWTException <ul>
2151 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2152 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2153 * </ul>
2154 *
2155 * @since 3.2
2156 */
2157 public void setSortColumn (TableColumn column) {
2158 checkWidget ();
2159 if (column !is null && column.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
2160 if (column is sortColumn) return;
2161 // DataBrowserCallbacks callbacks = new DataBrowserCallbacks ();
2162 // OS.GetDataBrowserCallbacks (handle, callbacks);
2163 // callbacks.v1_itemCompareCallback = display.itemCompareProc;
2164 // OS.SetDataBrowserCallbacks (handle, callbacks);
2165 // if (column is null) {
2166 // if (sortColumn !is null && !sortColumn.isDisposed () && sortDirection !is DWT.NONE) {
2167 // OS.SetDataBrowserSortOrder (handle, (short) OS.kDataBrowserOrderIncreasing);
2168 // sortColumn = null;
2169 // OS.SetDataBrowserSortProperty (handle, 0);
2170 // }
2171 // }
2172 // sortColumn = column;
2173 // if (sortColumn !is null && !sortColumn.isDisposed () && sortDirection !is DWT.NONE) {
2174 // OS.SetDataBrowserSortProperty (handle, sortColumn.id);
2175 // int order = sortDirection is DWT.DOWN ? OS.kDataBrowserOrderDecreasing : OS.kDataBrowserOrderIncreasing;
2176 // OS.SetDataBrowserSortOrder (handle, (short) order);
2177 // }
2178 // callbacks.v1_itemCompareCallback = itemCompareProc ();
2179 // OS.SetDataBrowserCallbacks (handle, callbacks);
2180 }
2181
2182 /**
2183 * Sets the direction of the sort indicator for the receiver. The value
2184 * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
2185 *
2186 * @param direction the direction of the sort indicator
2187 *
2188 * @exception DWTException <ul>
2189 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2190 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2191 * </ul>
2192 *
2193 * @since 3.2
2194 */
2195 public void setSortDirection (int direction) {
2196 checkWidget ();
2197 if (direction !is DWT.UP && direction !is DWT.DOWN && direction !is DWT.NONE) return;
2198 if (direction is sortDirection) return;
2199 sortDirection = direction;
2200 // DataBrowserCallbacks callbacks = new DataBrowserCallbacks ();
2201 // OS.GetDataBrowserCallbacks (handle, callbacks);
2202 // callbacks.v1_itemCompareCallback = display.itemCompareProc;
2203 // OS.SetDataBrowserCallbacks (handle, callbacks);
2204 // if (sortColumn !is null && !sortColumn.isDisposed ()) {
2205 // if (sortDirection is DWT.NONE) {
2206 // OS.SetDataBrowserSortOrder (handle, (short) OS.kDataBrowserOrderIncreasing);
2207 // TableColumn column = sortColumn;
2208 // sortColumn = null;
2209 // OS.SetDataBrowserSortProperty (handle, 0);
2210 // sortColumn = column;
2211 // } else {
2212 // OS.SetDataBrowserSortProperty (handle, 0);
2213 // OS.SetDataBrowserSortProperty (handle, sortColumn.id);
2214 // int order = sortDirection is DWT.DOWN ? OS.kDataBrowserOrderDecreasing : OS.kDataBrowserOrderIncreasing;
2215 // OS.SetDataBrowserSortOrder (handle, (short) order);
2216 // }
2217 // }
2218 // callbacks.v1_itemCompareCallback = itemCompareProc ();
2219 // OS.SetDataBrowserCallbacks (handle, callbacks);
2220 }
2221
2222 void setTableEmpty () {
2223 itemCount = 0;
2224 items = new TableItem [4];
2225 }
2226
2227 /**
2228 * Sets the zero-relative index of the item which is currently
2229 * at the top of the receiver. This index can change when items
2230 * are scrolled or new items are added and removed.
2231 *
2232 * @param index the index of the top item
2233 *
2234 * @exception DWTException <ul>
2235 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2236 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2237 * </ul>
2238 */
2239 public void setTopIndex (int index) {
2240 checkWidget();
2241 NSRect rect = ((NSTableView)view).rectOfRow(index);
2242 ((NSTableView)view).scrollRectToVisible(rect);
2243 }
2244
2245 /**
2246 * Shows the column. If the column is already showing in the receiver,
2247 * this method simply returns. Otherwise, the columns are scrolled until
2248 * the column is visible.
2249 *
2250 * @param column the column to be shown
2251 *
2252 * @exception IllegalArgumentException <ul>
2253 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
2254 * <li>ERROR_INVALID_ARGUMENT - if the column has been disposed</li>
2255 * </ul>
2256 * @exception DWTException <ul>
2257 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2258 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2259 * </ul>
2260 *
2261 * @since 3.0
2262 */
2263 public void showColumn (TableColumn column) {
2264 checkWidget ();
2265 if (column is null) error (DWT.ERROR_NULL_ARGUMENT);
2266 if (column.isDisposed()) error(DWT.ERROR_INVALID_ARGUMENT);
2267 if (column.parent !is this) return;
2268 int index = indexOf (column);
2269 if (columnCount <= 1 || !(0 <= index && index < columnCount)) return;
2270 ((NSTableView)view).scrollColumnToVisible(index + ((style & DWT.CHECK) !is 0 ? 1 : 0));
2271 }
2272
2273 void showIndex (int index) {
2274 if (0 <= index && index < itemCount) {
2275 ((NSTableView)view).scrollRowToVisible(index);
2276 }
2277 }
2278
2279 /**
2280 * Shows the item. If the item is already showing in the receiver,
2281 * this method simply returns. Otherwise, the items are scrolled until
2282 * the item is visible.
2283 *
2284 * @param item the item to be shown
2285 *
2286 * @exception IllegalArgumentException <ul>
2287 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
2288 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
2289 * </ul>
2290 * @exception DWTException <ul>
2291 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2292 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2293 * </ul>
2294 *
2295 * @see Table#showSelection()
2296 */
2297 public void showItem (TableItem item) {
2298 checkWidget ();
2299 if (item is null) error (DWT.ERROR_NULL_ARGUMENT);
2300 if (item.isDisposed()) error(DWT.ERROR_INVALID_ARGUMENT);
2301 int index = indexOf (item);
2302 if (index !is -1) showIndex (index);
2303 }
2304
2305 /**
2306 * Shows the selection. If the selection is already showing in the receiver,
2307 * this method simply returns. Otherwise, the items are scrolled until
2308 * the selection is visible.
2309 *
2310 * @exception DWTException <ul>
2311 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2312 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2313 * </ul>
2314 *
2315 * @see Table#showItem(TableItem)
2316 */
2317 public void showSelection () {
2318 checkWidget();
2319 int index = getSelectionIndex ();
2320 if (index >= 0) showIndex (index);
2321 }
2322
2323 void sendDoubleSelection() {
2324 postEvent (DWT.DefaultSelection);
2325 }
2326
2327 void tableViewSelectionDidChange (int aNotification) {
2328 if (ignoreSelect) return;
2329 NSTableView widget = (NSTableView)view;
2330 int row = widget.selectedRow();
2331 if(row is -1)
2332 postEvent(DWT.Selection);
2333 else {
2334 TableItem item = _getItem(row);
2335 Event event = new Event();
2336 event.item = item;
2337 event.index = row;
2338 postEvent(DWT.Selection, event);
2339 }
2340 }
2341
2342 int tableView_objectValueForTableColumn_row(int aTableView, int aTableColumn, int rowIndex) {
2343 TableItem item = items [rowIndex];
2344 if (checkColumn !is null && aTableColumn is checkColumn.id) {
2345 NSNumber value;
2346 if (item.checked && item.grayed) {
2347 value = NSNumber.numberWithInt(OS.NSMixedState);
2348 } else {
2349 value = NSNumber.numberWithInt(item.checked ? OS.NSOnState : OS.NSOffState);
2350 }
2351 return value.id;
2352 }
2353 for (int i=0; i<columnCount; i++) {
2354 if (columns [i].nsColumn.id is aTableColumn) {
2355 return item.createString(i).id;
2356 }
2357 }
2358 return item.createString(0).id;
2359 }
2360
2361 void tableView_setObjectValue_forTableColumn_row(int aTableView, int anObject, int aTableColumn, int rowIndex) {
2362 TableItem item = items [rowIndex];
2363 if (checkColumn !is null && aTableColumn is checkColumn.id) {
2364 item.checked = !item.checked;
2365 Event event = new Event();
2366 event.detail = DWT.CHECK;
2367 event.item = item;
2368 event.index = rowIndex;
2369 postEvent(DWT.Selection, event);
2370 }
2371 }
2372
2373 bool tableView_shouldEditTableColumn_row(int aTableView, int aTableColumn, int rowIndex) {
2374 return false;
2375 }
2376
2377 void tableView_willDisplayCell_forTableColumn_row(int aTableView, int aCell, int aTableColumn, int rowIndex) {
2378 if (checkColumn !is null && aTableColumn is checkColumn.id) return;
2379 TableItem item = items [rowIndex];
2380 Image image = item.image;
2381 for (int i=0; i<columnCount; i++) {
2382 if (columns [i].nsColumn.id is aTableColumn) {
2383 image = item.getImage(i);
2384 }
2385 }
2386 NSBrowserCell cell = new NSBrowserCell(aCell);
2387 cell.setImage(image !is null ? image.handle : null);
2388 cell.setLeaf(true);
2389 }
2390 }