Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/swt/widgets/Tree.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.swt.widgets;
12  
13  
14  import org.eclipse.swt.*;
15  import org.eclipse.swt.internal.gtk.*;
16  import org.eclipse.swt.graphics.*;
17  import org.eclipse.swt.events.*;
18  
19  /**
20   * Instances of this class provide a selectable user interface object
21   * that displays a hierarchy of items and issue notificiation when an
22   * item in the hierarchy is selected.
23   * <p>
24   * The item children that may be added to instances of this class
25   * must be of type <code>TreeItem</code>.
26   * </p><p>
27   * Note that although this class is a subclass of <code>Composite</code>,
28   * it does not make sense to add <code>Control</code> children to it,
29   * or set a layout on it.
30   * </p><p>
31   * <dl>
32   * <dt><b>Styles:</b></dt>
33   * <dd>SINGLE, MULTI, CHECK</dd>
34   * <dt><b>Events:</b></dt>
35   * <dd>Selection, DefaultSelection, Collapse, Expand</dd>
36   * </dl>
37   * <p>
38   * Note: Only one of the styles SINGLE and MULTI may be specified.
39   * </p><p>
40   * IMPORTANT: This class is <em>not</em> intended to be subclassed.
41   * </p>
42   */
43  public class Tree extends Composite {
44    long /*int*/ modelHandle, columnHandle, checkRenderer, pixbufRenderer, textRenderer;
45    TreeItem[] items;
46    ImageList imageList;
47    
48    static final int TEXT_COLUMN = 0;
49    static final int PIXBUF_COLUMN = 1;
50    static final int FOREGROUND_COLUMN = 2;
51    static final int BACKGROUND_COLUMN = 3;
52    static final int FONT_COLUMN = 4;
53    static final int ID_COLUMN = 5;
54    static final int CHECKED_COLUMN = 6;
55    static final int GRAYED_COLUMN = 7;
56    
57  /**
58   * Constructs a new instance of this class given its parent
59   * and a style value describing its behavior and appearance.
60   * <p>
61   * The style value is either one of the style constants defined in
62   * class <code>SWT</code> which is applicable to instances of this
63   * class, or must be built by <em>bitwise OR</em>'ing together 
64   * (that is, using the <code>int</code> "|" operator) two or more
65   * of those <code>SWT</code> style constants. The class description
66   * lists the style constants that are applicable to the class.
67   * Style bits are also inherited from superclasses.
68   * </p>
69   *
70   * @param parent a composite control which will be the parent of the new instance (cannot be null)
71   * @param style the style of control to construct
72   *
73   * @exception IllegalArgumentException <ul>
74   *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
75   * </ul>
76   * @exception SWTException <ul>
77   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
78   *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
79   * </ul>
80   *
81   * @see SWT#SINGLE
82   * @see SWT#MULTI
83   * @see SWT#CHECK
84   * @see Widget#checkSubclass
85   * @see Widget#getStyle
86   */
87  public Tree (Composite parent, int style) {
88    super (parent, checkStyle (style));
89  }
90  
91  static int checkStyle (int style) {
92    style |= SWT.H_SCROLL | SWT.V_SCROLL;
93    return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
94  }
95  
96  /**
97   * Adds the listener to the collection of listeners who will
98   * be notified when the receiver's selection changes, by sending
99   * it one of the messages defined in the <code>SelectionListener</code>
100  * interface.
101  * <p>
102  * When <code>widgetSelected</code> is called, the item field of the event object is valid.
103  * If the reciever has <code>SWT.CHECK</code> style set and the check selection changes,
104  * the event object detail field contains the value <code>SWT.CHECK</code>.
105  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
106  * The item field of the event object is valid for default selection, but the detail field is not used.
107  * </p>
108  *
109  * @param listener the listener which should be notified
110  *
111  * @exception IllegalArgumentException <ul>
112  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
113  * </ul>
114  * @exception SWTException <ul>
115  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
116  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
117  * </ul>
118  *
119  * @see SelectionListener
120  * @see #removeSelectionListener
121  * @see SelectionEvent
122  */
123 public void addSelectionListener(SelectionListener listener) {
124   checkWidget ();
125   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
126   TypedListener typedListener = new TypedListener (listener);
127   addListener (SWT.Selection, typedListener);
128   addListener (SWT.DefaultSelection, typedListener);
129 }
130 
131 /**
132  * Adds the listener to the collection of listeners who will
133  * be notified when an item in the receiver is expanded or collapsed
134  * by sending it one of the messages defined in the <code>TreeListener</code>
135  * interface.
136  *
137  * @param listener the listener which should be notified
138  *
139  * @exception IllegalArgumentException <ul>
140  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
141  * </ul>
142  * @exception SWTException <ul>
143  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
144  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
145  * </ul>
146  *
147  * @see TreeListener
148  * @see #removeTreeListener
149  */
150 public void addTreeListener(TreeListener listener) {
151   checkWidget ();
152   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
153   TypedListener typedListener = new TypedListener (listener);
154   addListener (SWT.Expand, typedListener);
155   addListener (SWT.Collapse, typedListener);
156 }  
157 
158 public Point computeSize (int wHint, int hHint, boolean changed) {
159   checkWidget ();
160   if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
161   if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
162   Point size = computeNativeSize (handle, wHint, hHint, changed);
163   Rectangle trim = computeTrim (0, 0, size.x, size.y);
164   size.x = trim.width;
165   size.y = trim.height;
166   return size;
167 }
168 
169 void createHandle (int index) {
170   state |= HANDLE;
171   fixedHandle = OS.gtk_fixed_new ();
172   if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES);
173   OS.gtk_fixed_set_has_window (fixedHandle, true);
174   scrolledHandle = OS.gtk_scrolled_window_new (0, 0);
175   if (scrolledHandle == 0) error (SWT.ERROR_NO_HANDLES);
176   /*
177   * Columns:
178   * 0 - text
179   * 1 - pixmap
180   * 2 - foreground
181   * 3 - background
182   * 4 - font
183   * 5 - id
184   * 6 - checked (if needed)
185   * 7 - grayed (if needed)
186   */
187   long /*int*/ [] types = new long /*int*/ [(style & SWT.CHECK) !=0 ? 8 : 6];
188   types [TEXT_COLUMN] = OS.G_TYPE_STRING ();
189   types [PIXBUF_COLUMN] = OS.GDK_TYPE_PIXBUF ();
190   types [FOREGROUND_COLUMN] = OS.GDK_TYPE_COLOR ();
191   types [BACKGROUND_COLUMN] = OS.GDK_TYPE_COLOR ();
192   types [FONT_COLUMN] = OS.PANGO_TYPE_FONT_DESCRIPTION ();
193   types [ID_COLUMN] = OS.G_TYPE_INT ();
194   if ((style & SWT.CHECK) != 0) {
195     types [CHECKED_COLUMN] = OS.G_TYPE_BOOLEAN (); 
196     types [GRAYED_COLUMN] = OS.G_TYPE_BOOLEAN ();
197   } 
198   modelHandle = OS.gtk_tree_store_newv (types.length, types);
199   if (modelHandle == 0) error (SWT.ERROR_NO_HANDLES);
200   handle = OS.gtk_tree_view_new_with_model (modelHandle);
201   if (handle == 0) error (SWT.ERROR_NO_HANDLES);
202   
203   /*
204   * Bug in ATK. For some reason, ATK segments fault if 
205   * the GtkTreeView has a column and does not have items.
206   * The fix is to insert the column only when an item is 
207   * created.
208   */
209   columnHandle = OS.gtk_tree_view_column_new ();
210   if (columnHandle == 0) error (SWT.ERROR_NO_HANDLES);
211   OS.g_object_ref (columnHandle);
212   
213   if ((style & SWT.CHECK) != 0) {
214     checkRenderer = OS.gtk_cell_renderer_toggle_new ();
215     if (checkRenderer == 0) error (SWT.ERROR_NO_HANDLES);
216     OS.gtk_tree_view_column_pack_start (columnHandle, checkRenderer, false);
217     OS.gtk_tree_view_column_add_attribute (columnHandle, checkRenderer, "active", CHECKED_COLUMN);
218 
219     /*
220     * Feature in GTK. The inconsistent property only exists in GTK 2.2.x.
221     */
222     if (OS.gtk_major_version () > 2 || (OS.gtk_major_version () == 2 && OS.gtk_minor_version () >= 2)) {
223       OS.gtk_tree_view_column_add_attribute (columnHandle, checkRenderer, "inconsistent", GRAYED_COLUMN);
224     }
225   }
226   pixbufRenderer = OS.gtk_cell_renderer_pixbuf_new ();
227   if (pixbufRenderer == 0) error (SWT.ERROR_NO_HANDLES);
228   OS.gtk_tree_view_column_pack_start (columnHandle, pixbufRenderer, false);
229   OS.gtk_tree_view_column_add_attribute (columnHandle, pixbufRenderer, "pixbuf", PIXBUF_COLUMN);
230   /*
231   * Feature on GTK.  When a tree view column contains only one activatable
232   * cell renderer such as a toggle renderer, mouse clicks anywhere in a cell
233   * activate that renderer. The workaround is to set a second  cell renderer
234   * to be activatable.
235   */
236   if ((style & SWT.CHECK) != 0) {
237     OS.g_object_set (pixbufRenderer, OS.mode, OS.GTK_CELL_RENDERER_MODE_ACTIVATABLE, 0);
238   }
239   textRenderer = OS.gtk_cell_renderer_text_new ();
240   if (textRenderer == 0) error (SWT.ERROR_NO_HANDLES);
241   OS.gtk_tree_view_column_pack_start (columnHandle, textRenderer, true);
242   OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, "text", TEXT_COLUMN);
243   OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, "foreground-gdk", FOREGROUND_COLUMN);
244   OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, "background-gdk", BACKGROUND_COLUMN);
245   OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, "font-desc", FONT_COLUMN);
246   long /*int*/ parentHandle = parent.parentingHandle ();
247   OS.gtk_container_add (parentHandle, fixedHandle);
248   OS.gtk_container_add (fixedHandle, scrolledHandle);
249   OS.gtk_container_add (scrolledHandle, handle);
250   OS.gtk_widget_show (fixedHandle);
251   OS.gtk_widget_show (scrolledHandle);
252   OS.gtk_widget_show (handle);
253 
254   int mode = (style & SWT.MULTI) != 0 ? OS.GTK_SELECTION_MULTIPLE : OS.GTK_SELECTION_BROWSE;
255   long /*int*/ selectionHandle = OS.gtk_tree_view_get_selection (handle);
256   OS.gtk_tree_selection_set_mode (selectionHandle, mode);
257   OS.gtk_tree_view_set_headers_visible (handle, false);  
258   int hsp = (style & SWT.H_SCROLL) != 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
259   int vsp = (style & SWT.V_SCROLL) != 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
260   OS.gtk_scrolled_window_set_policy (scrolledHandle, hsp, vsp);
261   if ((style & SWT.BORDER) != 0) OS.gtk_scrolled_window_set_shadow_type (scrolledHandle, OS.GTK_SHADOW_ETCHED_IN);
262 }
263 
264 void createItem (TreeItem item, long /*int*/ iter, int index) {
265   long /*int*/ column = OS.gtk_tree_view_get_column (handle, 0);
266   if (column == 0) OS.gtk_tree_view_insert_column (handle, columnHandle, 0);
267   int count = OS.gtk_tree_model_iter_n_children (modelHandle, iter);
268   if (index == -1) index = count;
269   if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
270   int id = 0;
271   while (id < items.length && items [id] != null) id++;
272   if (id == items.length) {
273     TreeItem [] newItems = new TreeItem [items.length + 4];
274     System.arraycopy (items, 0, newItems, 0, items.length);
275     items = newItems;
276   }
277   item.handle = OS.g_malloc (OS.GtkTreeIter_sizeof ());
278   if (item.handle == 0) error(SWT.ERROR_NO_HANDLES);
279   if (index == count) {
280     OS.gtk_tree_store_append (modelHandle, item.handle, iter);
281   } else {
282     OS.gtk_tree_store_insert (modelHandle, item.handle, iter, index);
283   }
284   OS.gtk_tree_store_set (modelHandle, item.handle, ID_COLUMN, id, -1);
285   items [id] = item;
286 }
287 
288 void createWidget (int index) {
289   super.createWidget (index);
290   items = new TreeItem [4];
291 }
292 
293 GdkColor defaultBackground () {
294   return display.COLOR_LIST_BACKGROUND;
295 }
296 
297 GdkColor defaultForeground () {
298   return display.COLOR_LIST_FOREGROUND;
299 }
300 
301 void deregister () {
302   super.deregister ();
303   display.removeWidget (OS.gtk_tree_view_get_selection (handle));
304   if (checkRenderer != 0) display.removeWidget (checkRenderer);
305 }
306 
307 /**
308  * Deselects all selected items in the receiver.
309  *
310  * @exception SWTException <ul>
311  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313  * </ul>
314  */
315 public void deselectAll() {
316   checkWidget();
317   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
318   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
319   OS.gtk_tree_selection_unselect_all (selection);
320   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
321 }
322 
323 void destroyItem (TreeItem item) {
324   /*
325   * Bug in GTK.  GTK segment faults when a root tree item
326   * is destroyed when the tree is expanded and the last leaf of
327   * the root is selected.  This only happens in versions earlier
328   * than 2.0.6.  The fix is to collapse the tree item being destroyed
329   * when it is a root, before it is destroyed.
330   */
331   if (OS.gtk_major_version () == 2 && OS.gtk_minor_version () == 0 && OS.gtk_micro_version () < 6) {
332     TreeItem [] roots = getItems (0);
333     for (int i = 0; i < roots.length; i++) {
334       if (item == roots [i]) {
335         item.setExpanded (false);
336         break;
337       }
338     }
339   }
340   int [] index = new int [1];
341   releaseItems (item.getItems (), index);
342   releaseItem (item, index);
343   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
344   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
345   OS.gtk_tree_store_remove (modelHandle, item.handle);
346   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
347   int childCount = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
348   if (childCount == 0) removeColumn ();
349 }
350 
351 void destroyWidget () {
352   /*
353   * Bug in GTK. Sometimes GTK causes a segment fault when a tree widget is
354   * destroyed and it has outstanding events or idle handlers.  This only happens
355   * on versions earlier than 2.0.5.  The fix is to flush all outstanding events before
356   * destroying the widget.
357   */
358   if (OS.gtk_major_version () == 2 && OS.gtk_minor_version () == 0 && OS.gtk_micro_version () < 5) {
359     while (OS.gtk_events_pending () != 0) OS.gtk_main_iteration ();
360   }
361   super.destroyWidget ();
362 }
363 
364 GdkColor getBackgroundColor () {
365   return getBaseColor ();
366 }
367 
368 TreeItem getFocusItem () {
369   long /*int*/ [] path = new long /*int*/ [1];
370   OS.gtk_tree_view_get_cursor (handle, path, null);
371   if (path [0] == 0) return null;
372   TreeItem item = null;
373   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
374   if (OS.gtk_tree_model_get_iter (modelHandle, iter, path [0])) {
375     int [] index = new int [1];
376     OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
377     item = items [index [0]];
378   }
379   OS.g_free (iter);
380   OS.gtk_tree_path_free (path [0]);
381   return item;  
382 } 
383 
384 GdkColor getForegroundColor () {
385   return getTextColor ();
386 }
387 
388 /**
389  * Returns the item at the given point in the receiver
390  * or null if no such item exists. The point is in the
391  * coordinate system of the receiver.
392  *
393  * @param point the point used to locate the item
394  * @return the item at the given point
395  *
396  * @exception IllegalArgumentException <ul>
397  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
398  * </ul>
399  * @exception SWTException <ul>
400  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
401  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
402  * </ul>
403  */
404 public TreeItem getItem (Point point) {
405   checkWidget ();
406   long /*int*/ [] path = new long /*int*/ [1];  
407   OS.gtk_widget_realize (handle);
408   if (!OS.gtk_tree_view_get_path_at_pos (handle, point.x, point.y, path, null, null, null)) return null;
409   if (path [0] == 0) return null;
410   TreeItem item = null;
411   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
412   if (OS.gtk_tree_model_get_iter (modelHandle, iter, path [0])) {
413     boolean overExpander = false;
414     if (OS.gtk_tree_model_iter_n_children (modelHandle, iter) > 0) {
415       int[] buffer = new int [1];
416       GdkRectangle rect = new GdkRectangle ();
417       OS.gtk_tree_view_get_cell_area (handle, path [0], columnHandle, rect);
418       OS.gtk_widget_style_get (handle, OS.expander_size, buffer, 0);
419       int expanderSize = buffer [0] + TreeItem.EXPANDER_EXTRA_PADDING;
420       overExpander = rect.x - 1 <= point.x && point.x < rect.x + expanderSize;
421     }
422     if (!overExpander) {
423       int [] index = new int [1];
424       OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
425       item = items [index [0]];
426     }
427   }
428   OS.g_free (iter);
429   OS.gtk_tree_path_free (path [0]);
430   return item;
431 }
432 
433 /**
434  * Returns the number of items contained in the receiver
435  * that are direct item children of the receiver.  The
436  * number that is returned is the number of roots in the
437  * tree.
438  *
439  * @return the number of items
440  *
441  * @exception SWTException <ul>
442  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
443  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
444  * </ul>
445  */
446 public int getItemCount () {
447   checkWidget ();
448   return OS.gtk_tree_model_iter_n_children (modelHandle, 0);
449 }
450 
451 /**
452  * Returns the height of the area which would be used to
453  * display <em>one</em> of the items in the tree.
454  *
455  * @return the height of one item
456  *
457  * @exception SWTException <ul>
458  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
459  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
460  * </ul>
461  */
462 public int getItemHeight () {
463   checkWidget ();
464   int itemCount = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
465   if (itemCount == 0) {
466     int [] w = new int [1], h = new int [1];
467     OS.gtk_tree_view_insert_column (handle, columnHandle, 0);
468     OS.gtk_tree_view_column_cell_get_size (columnHandle, null, null, null, w, h);
469     OS.gtk_tree_view_remove_column (handle, columnHandle);
470     return h [0];
471   } else {
472     long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
473     OS.gtk_tree_model_get_iter_first (modelHandle, iter);
474     long /*int*/ column = OS.gtk_tree_view_get_column (handle, 0);
475     OS.gtk_tree_view_column_cell_set_cell_data (column, modelHandle, iter, false, false);
476     int [] w = new int [1], h = new int [1];
477     OS.gtk_tree_view_column_cell_get_size (column, null, null, null, w, h);
478     OS.g_free (iter);
479     return h [0];
480   }
481 }
482 
483 /**
484  * Returns the items contained in the receiver
485  * that are direct item children of the receiver.  These
486  * are the roots of the tree.
487  * <p>
488  * Note: This is not the actual structure used by the receiver
489  * to maintain its list of items, so modifying the array will
490  * not affect the receiver. 
491  * </p>
492  *
493  * @return the items
494  *
495  * @exception SWTException <ul>
496  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
497  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
498  * </ul>
499  */
500 public TreeItem [] getItems () {
501   checkWidget();
502   return getItems (0);
503 }
504 
505 TreeItem [] getItems (long /*int*/ parent) {
506   int length = OS.gtk_tree_model_iter_n_children (modelHandle, parent);
507   TreeItem[] result = new TreeItem [length];
508   if (length == 0) return result;
509   int i = 0;
510   int[] index = new int [1];
511   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
512   boolean valid = OS.gtk_tree_model_iter_children (modelHandle, iter, parent);
513   while (valid) {
514     OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
515     result [i++] = items [index [0]];
516     valid = OS.gtk_tree_model_iter_next (modelHandle, iter);
517   }
518   OS.g_free (iter);
519   return result;
520 }
521 
522 /**
523  * Returns the receiver's parent item, which must be a
524  * <code>TreeItem</code> or null when the receiver is a
525  * root.
526  *
527  * @return the receiver's parent item
528  *
529  * @exception SWTException <ul>
530  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
531  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
532  * </ul>
533  */
534 public TreeItem getParentItem () {
535   checkWidget ();
536   return null;
537 }
538 
539 /**
540  * Returns an array of <code>TreeItem</code>s that are currently
541  * selected in the receiver. An empty array indicates that no
542  * items are selected.
543  * <p>
544  * Note: This is not the actual structure used by the receiver
545  * to maintain its selection, so modifying the array will
546  * not affect the receiver. 
547  * </p>
548  * @return an array representing the selection
549  *
550  * @exception SWTException <ul>
551  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
552  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
553  * </ul>
554  */
555 public TreeItem[] getSelection () {
556   checkWidget();
557   if ((style & SWT.MULTI) != 0) {
558     display.treeSelectionLength  = 0;
559     display.treeSelection = new int [items.length];
560     long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
561     OS.gtk_tree_selection_selected_foreach (selection, display.treeSelectionProc, handle);
562     TreeItem [] result = new TreeItem [display.treeSelectionLength];
563     for (int i=0; i<result.length; i++) result [i] = items [display.treeSelection [i]];
564     return result;
565   } else {
566     long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
567     long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
568     boolean hasSelection = OS.gtk_tree_selection_get_selected (selection, null, iter);
569     TreeItem [] result;
570     if (hasSelection) {
571       int [] index = new int [1];
572       OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
573       result = new TreeItem []{items [index [0]]};
574     } else {
575       result = new TreeItem [0];
576     }
577     OS.g_free (iter);
578     return result;
579   }
580 }
581   
582 /**
583  * Returns the number of selected items contained in the receiver.
584  *
585  * @return the number of selected items
586  *
587  * @exception SWTException <ul>
588  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
589  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
590  * </ul>
591  */
592 public int getSelectionCount () {
593   checkWidget();
594   display.treeSelectionLength = 0;
595   display.treeSelection = null;
596   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
597   OS.gtk_tree_selection_selected_foreach (selection, display.treeSelectionProc, handle);
598   return display.treeSelectionLength;
599 }
600 
601 /**
602  * Returns the item which is currently at the top of the receiver.
603  * This item can change when items are expanded, collapsed, scrolled
604  * or new items are added or removed.
605  *
606  * @return the item at the top of the receiver 
607  * 
608  * @exception SWTException <ul>
609  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
610  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
611  * </ul>
612  * 
613  * @since 2.1
614  */
615 public TreeItem getTopItem () {
616   checkWidget ();
617   long /*int*/ [] path = new long /*int*/ [1];
618   OS.gtk_widget_realize (handle);
619   if (!OS.gtk_tree_view_get_path_at_pos (handle, 1, 1, path, null, null, null)) return null;
620   if (path [0] == 0) return null;
621   TreeItem item = null;
622   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof());
623   if (OS.gtk_tree_model_get_iter (modelHandle, iter, path [0])) {
624     int [] index = new int [1];
625     OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
626     item = items [index [0]];
627   }
628   OS.g_free (iter);
629   OS.gtk_tree_path_free (path [0]);
630   return item;
631 }
632 
633 long /*int*/ gtk_changed (long /*int*/ widget) {
634   TreeItem item = getFocusItem ();
635   if (item != null) {
636     Event event = new Event ();
637     event.item = item; 
638     postEvent (SWT.Selection, event);
639   }
640   return 0;
641 }
642 
643 long /*int*/ gtk_key_press_event (long /*int*/ widget, long /*int*/ eventPtr) {
644   long /*int*/ result = super.gtk_key_press_event (widget, eventPtr);
645   if (result != 0) return result;
646 
647   /*
648   * Feature in GTK.  When an item is default selected using
649   * the return key, GTK does not issue notification. The fix is
650   * to issue this notification when the return key is pressed.
651   */
652   GdkEventKey keyEvent = new GdkEventKey ();
653   OS.memmove (keyEvent, eventPtr, GdkEventKey.sizeof);
654   int key = keyEvent.keyval;
655   switch (key) {
656     case OS.GDK_Return:
657     case OS.GDK_KP_Enter: {
658       Event event = new Event ();
659       event.item = getFocusItem (); 
660       postEvent (SWT.DefaultSelection, event);
661       break;
662     }
663   }
664   return result;
665 }
666 
667 long /*int*/ gtk_row_activated (long /*int*/ tree, long /*int*/ path, long /*int*/ column) {
668   if (path == 0) return 0;
669   TreeItem item = null;
670   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
671   if (OS.gtk_tree_model_get_iter (modelHandle, iter, path)) {
672     int [] index = new int [1];
673     OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
674     item = items [index [0]];
675   }
676   OS.g_free (iter);
677   Event event = new Event ();
678   event.item = item;
679   postEvent (SWT.DefaultSelection, event);
680   return 0;
681 }
682 
683 long /*int*/ gtk_test_collapse_row (long /*int*/ tree, long /*int*/ iter, long /*int*/ path) {
684   int [] index = new int [1];
685   OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
686   Event event = new Event ();
687   event.item = items [index [0]];
688   sendEvent (SWT.Collapse, event);
689   if (isDisposed ()) return 0;
690   OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_COLLAPSE_ROW);
691   OS.gtk_tree_view_collapse_row (handle, path);
692   OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_COLLAPSE_ROW);
693   return 1;
694 }
695 
696 long /*int*/ gtk_test_expand_row (long /*int*/ tree, long /*int*/ iter, long /*int*/ path) {
697   int [] index = new int [1];
698   OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
699   Event event = new Event ();
700   event.item = items [index [0]];
701   sendEvent (SWT.Expand, event);
702   if (isDisposed ()) return 0;
703   OS.g_signal_handlers_block_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_EXPAND_ROW);
704   OS.gtk_tree_view_expand_row (handle, path, false);
705   OS.g_signal_handlers_unblock_matched (handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_EXPAND_ROW);
706   return 1;
707 }
708 
709 long /*int*/ gtk_toggled (long /*int*/ renderer, long /*int*/ pathStr) {
710   long /*int*/ path = OS.gtk_tree_path_new_from_string (pathStr);
711   if (path == 0) return 0;
712   TreeItem item = null;
713   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof());
714   if (OS.gtk_tree_model_get_iter (modelHandle, iter, path)) {
715     int [] index = new int [1];
716     OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
717     item = items [index [0]];
718   }
719   OS.g_free (iter);
720   OS.gtk_tree_path_free (path);
721   item.setChecked (!item.getChecked ());
722   Event event = new Event ();
723   event.detail = SWT.CHECK;
724   event.item = item;
725   postEvent (SWT.Selection, event);
726   return 0;
727 }
728 
729 long /*int*/ gtk_button_press_event (long /*int*/ widget, long /*int*/ event) {
730   long /*int*/ result = super.gtk_button_press_event (widget, event);
731   if (result != 0) return result;
732   /*
733   * Bug in GTK. GTK segments fault, if the GtkTreeView widget is
734   * not in focus and all items in the widget are disposed before
735   * it finishes processing a button press.  The fix is to give
736   * focus to the widget before it starts processing the event.
737   */
738   if (!OS.GTK_WIDGET_HAS_FOCUS (handle)) {
739     OS.gtk_widget_grab_focus (handle);
740     // widget may be disposed at this point
741     if (isDisposed ()) return 0;
742   }
743   /*
744   * Feature in GTK.  In a multi-select tree view, when multiple items are already
745   * selected, the selection state of the item is toggled and the previous selection 
746   * is cleared. This is not the desired behaviour when bringing up a popup menu.
747   * Also, when an item is reselected with the right button, the tree view issues
748   * an unwanted selection event. The workaround is to detect that case and not
749   * run the default handler when the item is already part of the current selection.
750   */
751   GdkEventButton gdkEvent = new GdkEventButton ();
752   OS.memmove (gdkEvent, event, GdkEventButton.sizeof);
753   int button = gdkEvent.button;
754   if (button == 3 && gdkEvent.type == OS.GDK_BUTTON_PRESS) {
755     long /*int*/ [] path = new long /*int*/ [1];
756     if (OS.gtk_tree_view_get_path_at_pos (handle, (int)gdkEvent.x, (int)gdkEvent.y, path, null, null, null)) {
757       if (path [0] != 0) {
758         long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
759         if (OS.gtk_tree_selection_path_is_selected (selection, path [0])) result = 1;
760         OS.gtk_tree_path_free (path [0]);
761       }
762     }
763   }
764   
765   /*
766   * Feature in GTK.  When the user clicks in a single selection GtkTreeView
767   * and there are no selected items, the first item is selected automatically
768   * before the click is processed, causing two selection events.  The is fix
769   * is the set the cursor item to be same as the clicked item to stop the
770   * widget from automatically selecting the first item.
771   */
772   if ((style & SWT.SINGLE) != 0 && getSelectionCount () == 0) {
773     long /*int*/ [] path = new long /*int*/ [1];
774     if (OS.gtk_tree_view_get_path_at_pos (handle, (int)gdkEvent.x, (int)gdkEvent.y, path, null, null, null)) {
775       if (path [0] != 0) {
776         long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
777         OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
778         OS.gtk_tree_view_set_cursor (handle, path [0], 0, false);
779         OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
780         OS.gtk_tree_path_free (path [0]);
781       }
782     }
783   }
784   
785   return result;
786 }
787   
788 void hookEvents () {
789   super.hookEvents ();
790   long /*int*/ selection = OS.gtk_tree_view_get_selection(handle);
791   OS.g_signal_connect_after (selection, OS.changed, display.windowProc2, CHANGED);
792   OS.g_signal_connect (handle, OS.row_activated, display.windowProc4, ROW_ACTIVATED);
793   OS.g_signal_connect (handle, OS.test_expand_row, display.windowProc4, TEST_EXPAND_ROW);
794   OS.g_signal_connect (handle, OS.test_collapse_row, display.windowProc4, TEST_COLLAPSE_ROW);
795   if (checkRenderer != 0) {
796     OS.g_signal_connect (checkRenderer, OS.toggled, display.windowProc3, TOGGLED);
797   }
798 }
799 
800 long /*int*/ paintWindow () {
801   OS.gtk_widget_realize (handle);
802   return OS.gtk_tree_view_get_bin_window (handle);
803 }
804 
805 void register () {
806   super.register ();
807   display.addWidget (OS.gtk_tree_view_get_selection (handle), this);
808   if (checkRenderer != 0) display.addWidget (checkRenderer, this);
809 }
810 
811 boolean releaseItem (TreeItem item, int [] index) {
812   if (item.isDisposed ()) return false;
813   OS.gtk_tree_model_get (modelHandle, item.handle, ID_COLUMN, index, -1);
814   items [index [0]] = null;
815   return true;
816 }
817 
818 void releaseItems (TreeItem [] nodes, int [] index) {
819   for (int i=0; i<nodes.length; i++) {
820     TreeItem item = nodes [i];
821     TreeItem [] sons = item.getItems ();
822     if (sons.length != 0) {
823       releaseItems (sons, index);
824     }
825     if (releaseItem (item, index)) {
826       item.releaseResources ();
827     }
828   }
829 }
830 
831 void releaseWidget () {
832   for (int i=0; i<items.length; i++) {
833     TreeItem item = items [i];
834     if (item != null && !item.isDisposed ()) item.releaseResources();
835   }
836   items = null;
837   super.releaseWidget();
838   if (modelHandle != 0) OS.g_object_unref (modelHandle);
839   modelHandle = 0;
840   if (columnHandle != 0) OS.g_object_unref (columnHandle);
841   columnHandle = 0;
842   if (imageList != null) {
843     imageList.dispose ();
844     imageList = null;
845   }
846 }
847 
848 /**
849  * Removes all of the items from the receiver.
850  * <p>
851  * @exception SWTException <ul>
852  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
853  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
854  * </ul>
855  */
856 public void removeAll () {
857   checkWidget ();
858   for (int i=0; i<items.length; i++) {
859     TreeItem item = items [i];
860     if (item != null && !item.isDisposed ()) item.releaseResources ();
861   }
862   items = new TreeItem[4];
863   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
864   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
865   OS.gtk_tree_store_clear (modelHandle);
866   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
867   removeColumn ();
868 }
869 
870 void removeColumn () {
871   long /*int*/ column = OS.gtk_tree_view_get_column (handle, 0);
872   if (column == 0) return;
873   OS.gtk_tree_view_remove_column (handle, column);
874 }
875 
876 /**
877  * Removes the listener from the collection of listeners who will
878  * be notified when the receiver's selection changes.
879  *
880  * @param listener the listener which should no longer be notified
881  *
882  * @exception IllegalArgumentException <ul>
883  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
884  * </ul>
885  * @exception SWTException <ul>
886  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
887  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
888  * </ul>
889  *
890  * @see SelectionListener
891  * @see #addSelectionListener
892  */
893 public void removeSelectionListener (SelectionListener listener) {
894   checkWidget ();
895   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
896   eventTable.unhook (SWT.Selection, listener);
897   eventTable.unhook (SWT.DefaultSelection, listener);  
898 }
899 
900 /**
901  * Removes the listener from the collection of listeners who will
902  * be notified when items in the receiver are expanded or collapsed..
903  *
904  * @param listener the listener which should no longer be notified
905  *
906  * @exception IllegalArgumentException <ul>
907  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
908  * </ul>
909  * @exception SWTException <ul>
910  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
911  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
912  * </ul>
913  *
914  * @see TreeListener
915  * @see #addTreeListener
916  */
917 public void removeTreeListener(TreeListener listener) {
918   checkWidget ();
919   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
920   if (eventTable == null) return;
921   eventTable.unhook (SWT.Expand, listener);
922   eventTable.unhook (SWT.Collapse, listener);
923 }
924 
925 /**
926  * Display a mark indicating the point at which an item will be inserted.
927  * The drop insert item has a visual hint to show where a dragged item 
928  * will be inserted when dropped on the tree.
929  * 
930  * @param item the insert item.  Null will clear the insertion mark.
931  * @param before true places the insert mark above 'item'. false places 
932  *  the insert mark below 'item'.
933  *
934  * @exception IllegalArgumentException <ul>
935  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
936  * </ul>
937  * @exception SWTException <ul>
938  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
939  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
940  * </ul>
941  */
942 public void setInsertMark (TreeItem item, boolean before) {
943   checkWidget ();
944   if (item == null) {
945     OS.gtk_tree_view_unset_rows_drag_dest(handle);
946     return;
947   }
948   if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
949   if (item.parent != this) return;
950   Rectangle rect = item.getBounds();
951   long /*int*/ [] path = new long /*int*/ [1];
952   OS.gtk_widget_realize (handle);
953   if (!OS.gtk_tree_view_get_path_at_pos(handle, rect.x, rect.y, path, null, null, null)) return;
954   if (path [0] == 0) return;
955   int position = before ? OS.GTK_TREE_VIEW_DROP_BEFORE : OS.GTK_TREE_VIEW_DROP_AFTER;
956   OS.gtk_tree_view_set_drag_dest_row(handle, path[0], position);
957   OS.gtk_tree_path_free (path [0]);
958 }
959 
960 /**
961  * Selects all of the items in the receiver.
962  * <p>
963  * If the receiver is single-select, do nothing.
964  *
965  * @exception SWTException <ul>
966  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
967  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
968  * </ul>
969  */
970 public void selectAll () {
971   checkWidget();
972   if ((style & SWT.SINGLE) != 0) return;
973   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
974   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
975   OS.gtk_tree_selection_select_all (OS.gtk_tree_view_get_selection (handle));
976   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
977 }
978 
979 void setBackgroundColor (GdkColor color) {
980   super.setBackgroundColor (color);
981   OS.gtk_widget_modify_base (handle, 0, color);
982 }
983 
984 boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
985   boolean result = super.setBounds (x, y, width, height, move, resize);
986   /*
987   * Bug on GTK.  The tree view sometimes does not get a paint
988   * event or resizes to a one pixel square when resized in a new
989   * shell that is not visible after any event loop has been run.  The
990   * problem is intermittent. It doesn't seem to happen the first time
991   * a new shell is created. The fix is to ensure the tree view is realized
992   * after it has been resized.
993   */
994   OS.gtk_widget_realize (handle);
995   return result;
996 }
997 
998 void setForegroundColor (GdkColor color) {
999   super.setForegroundColor (color);
1000  OS.gtk_widget_modify_text (handle, 0, color);
1001}
1002
1003/**
1004 * Sets the receiver's selection to be the given array of items.
1005 * The current selection is cleared before the new items are selected.
1006 * <p>
1007 * Items that are not in the receiver are ignored.
1008 * If the receiver is single-select and multiple items are specified,
1009 * then all items are ignored.
1010 *
1011 * @param items the array of items
1012 *
1013 * @exception IllegalArgumentException <ul>
1014 *    <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
1015 *    <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
1016 * </ul>
1017 * @exception SWTException <ul>
1018 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1019 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1020 * </ul>
1021 *
1022 * @see Tree#deselectAll()
1023 */
1024public void setSelection (TreeItem [] items) {
1025  checkWidget ();
1026  if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1027  int length = items.length;
1028  if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) {
1029    deselectAll ();
1030    return;
1031  }
1032  long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
1033  OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1034  OS.gtk_tree_selection_unselect_all (selection);
1035  boolean first = true;
1036  for (int i = 0; i < length; i++) {
1037    TreeItem item = items [i];
1038    if (item == null) continue;
1039    if (item.isDisposed ()) break;
1040    if (item.parent != this) continue;
1041    long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
1042    showItem (path, first);
1043    OS.gtk_tree_selection_select_iter (selection, item.handle);
1044    if ((style & SWT.SINGLE) != 0) {
1045      OS.gtk_tree_view_set_cursor (handle, path, 0, false);
1046    }
1047    OS.gtk_tree_path_free (path);
1048    first = false;
1049  }
1050  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1051}
1052
1053/**
1054 * Sets the item which is currently at the top of the receiver.
1055 * This item can change when items are expanded, collapsed, scrolled
1056 * or new items are added or removed.
1057 *
1058 * @param item the item to be shown
1059 *
1060 * @exception IllegalArgumentException <ul>
1061 *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
1062 *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
1063 * </ul>
1064 * @exception SWTException <ul>
1065 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1066 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1067 * </ul>
1068 *
1069 * @see Tree#getTopItem()
1070 * 
1071 * @since 2.1
1072 */
1073public void setTopItem (TreeItem item) {
1074  if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
1075  if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
1076  if (item.parent != this) return;
1077  long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
1078  showItem (path, false);
1079  OS.gtk_tree_view_scroll_to_cell (handle, path, 0, true, 0, 0);
1080  OS.gtk_tree_path_free (path);
1081}
1082
1083/**
1084 * Shows the selection.  If the selection is already showing in the receiver,
1085 * this method simply returns.  Otherwise, the items are scrolled until
1086 * the selection is visible.
1087 *
1088 * @exception SWTException <ul>
1089 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1090 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1091 * </ul>
1092 *
1093 * @see Tree#showItem(TreeItem)
1094 */
1095public void showSelection () {
1096  checkWidget();
1097  TreeItem [] items = getSelection ();
1098  if (items.length != 0 && items [0] != null) showItem (items [0]);
1099}
1100
1101void showItem (long /*int*/ path, boolean scroll) {
1102  int depth = OS.gtk_tree_path_get_depth (path);
1103  if (depth > 1) {
1104    int [] indices = new int [depth - 1];
1105    long /*int*/ indicesPtr = OS.gtk_tree_path_get_indices (path);
1106    OS.memmove (indices, indicesPtr, indices.length * 4);
1107    long /*int*/ tempPath = OS.gtk_tree_path_new ();
1108    for (int i=0; i<indices.length; i++) {
1109      OS.gtk_tree_path_append_index (tempPath, indices [i]);
1110      OS.gtk_tree_view_expand_row (handle, tempPath, false);
1111    }
1112    OS.gtk_tree_path_free (tempPath);    
1113  }
1114  if (scroll) {
1115    GdkRectangle rect = new GdkRectangle ();
1116    OS.gtk_widget_realize (handle);
1117    OS.gtk_tree_view_get_cell_area (handle, path, 0, rect);
1118    boolean isHidden = rect.y == 0 && rect.height == 0;
1119    if (!isHidden) {
1120      int [] tx = new int [1], ty = new int [1];
1121      OS.gtk_tree_view_widget_to_tree_coords (handle, rect.x, rect.y, tx, ty);
1122      rect.y = ty[0];
1123      GdkRectangle visRect = new GdkRectangle ();
1124      OS.gtk_tree_view_get_visible_rect (handle, visRect);
1125      if (rect.y < visRect.y || rect.y + rect.height > visRect.y + visRect.height) {
1126        isHidden = true;
1127      } 
1128    }
1129    if (isHidden) OS.gtk_tree_view_scroll_to_cell (handle, path, 0, depth != 1, 0.5f, 0.0f);  
1130  }
1131}
1132
1133/**
1134 * Shows the item.  If the item is already showing in the receiver,
1135 * this method simply returns.  Otherwise, the items are scrolled
1136 * and expanded until the item is visible.
1137 *
1138 * @param item the item to be shown
1139 *
1140 * @exception IllegalArgumentException <ul>
1141 *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
1142 *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
1143 * </ul>
1144 * @exception SWTException <ul>
1145 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1146 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1147 * </ul>
1148 *
1149 * @see Tree#showSelection()
1150 */
1151public void showItem (TreeItem item) {
1152  checkWidget ();
1153  if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
1154  if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
1155  if (item.parent != this) return;
1156  long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
1157  showItem (path, true);
1158  OS.gtk_tree_path_free (path);
1159}
1160
1161long /*int*/ treeSelectionProc (long /*int*/ model, long /*int*/ path, long /*int*/ iter, int[] selection, int length) {
1162  if (selection != null) {
1163    int [] index = new int [1];
1164    OS.gtk_tree_model_get (modelHandle, iter, ID_COLUMN, index, -1);
1165    selection [(int)/*64*/length] = index [0];
1166  }
1167  return 0;
1168}
1169
1170}