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