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

Quick Search    Search Deep

Source code: org/eclipse/swt/widgets/List.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.*;
16  import org.eclipse.swt.internal.gtk.*;
17  import org.eclipse.swt.graphics.*;
18  import org.eclipse.swt.events.*;
19  
20  /** 
21   * Instances of this class represent a selectable user interface
22   * object that displays a list of strings and issues notificiation
23   * when a string selected.  A list may be single or multi select.
24   * <p>
25   * <dl>
26   * <dt><b>Styles:</b></dt>
27   * <dd>SINGLE, MULTI</dd>
28   * <dt><b>Events:</b></dt>
29   * <dd>Selection, DefaultSelection</dd>
30   * </dl>
31   * <p>
32   * Note: Only one of SINGLE and MULTI may be specified.
33   * </p><p>
34   * IMPORTANT: This class is <em>not</em> intended to be subclassed.
35   * </p>
36   */
37  public class List extends Scrollable {
38    long /*int*/ modelHandle;
39  
40    static final int TEXT_COLUMN = 0;
41  
42  /**
43   * Constructs a new instance of this class given its parent
44   * and a style value describing its behavior and appearance.
45   * <p>
46   * The style value is either one of the style constants defined in
47   * class <code>SWT</code> which is applicable to instances of this
48   * class, or must be built by <em>bitwise OR</em>'ing together 
49   * (that is, using the <code>int</code> "|" operator) two or more
50   * of those <code>SWT</code> style constants. The class description
51   * lists the style constants that are applicable to the class.
52   * Style bits are also inherited from superclasses.
53   * </p>
54   *
55   * @param parent a composite control which will be the parent of the new instance (cannot be null)
56   * @param style the style of control to construct
57   *
58   * @exception IllegalArgumentException <ul>
59   *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
60   * </ul>
61   * @exception SWTException <ul>
62   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
63   *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
64   * </ul>
65   *
66   * @see SWT#SINGLE
67   * @see SWT#MULTI
68   * @see Widget#checkSubclass
69   * @see Widget#getStyle
70   */
71  public List (Composite parent, int style) {
72    super (parent, checkStyle (style));
73  }
74  
75  /**
76   * Adds the argument to the end of the receiver's list.
77   *
78   * @param string the new item
79   *
80   * @exception IllegalArgumentException <ul>
81   *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
82   * </ul>
83   * @exception SWTException <ul>
84   *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
85   *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
86   * </ul>
87   * @exception SWTError <ul>
88   *    <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
89   * </ul>
90   *
91   * @see #add(String,int)
92   */
93  public void add (String string) {
94    checkWidget();
95    if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
96    byte [] buffer = Converter.wcsToMbcs (null, string, true);
97    long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
98    if (iter == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
99    OS.gtk_list_store_append (modelHandle, iter);
100   OS.gtk_list_store_set (modelHandle, iter, TEXT_COLUMN, buffer, -1);
101   OS.g_free (iter);
102 }
103 
104 /**
105  * Adds the argument to the receiver's list at the given
106  * zero-relative index.
107  * <p>
108  * Note: To add an item at the end of the list, use the
109  * result of calling <code>getItemCount()</code> as the
110  * index or use <code>add(String)</code>.
111  * </p>
112  *
113  * @param string the new item
114  * @param index the index for the item
115  *
116  * @exception IllegalArgumentException <ul>
117  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
118  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list (inclusive)</li>
119  * </ul>
120  * @exception SWTException <ul>
121  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
122  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
123  * </ul>
124  * @exception SWTError <ul>
125  *    <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
126  * </ul>
127  *
128  * @see #add(String)
129  */
130 public void add (String string, int index) {
131   checkWidget();
132   if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
133   int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
134   if (!(0 <= index && index <= count)) {
135     error (SWT.ERROR_INVALID_RANGE);
136   }
137   byte [] buffer = Converter.wcsToMbcs (null, string, true);
138   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
139   if (iter == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
140   if (index == count) {
141     OS.gtk_list_store_append (modelHandle, iter);
142   } else {
143     OS.gtk_list_store_insert (modelHandle, iter, index);
144   }
145   OS.gtk_list_store_set (modelHandle, iter, TEXT_COLUMN, buffer, -1);
146   OS.g_free (iter);
147 }
148 
149 /**
150  * Adds the listener to the collection of listeners who will
151  * be notified when the receiver's selection changes, by sending
152  * it one of the messages defined in the <code>SelectionListener</code>
153  * interface.
154  * <p>
155  * <code>widgetSelected</code> is called when the selection changes.
156  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
157  * </p>
158  *
159  * @param listener the listener which should be notified
160  *
161  * @exception IllegalArgumentException <ul>
162  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
163  * </ul>
164  * @exception SWTException <ul>
165  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
166  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
167  * </ul>
168  *
169  * @see SelectionListener
170  * @see #removeSelectionListener
171  * @see SelectionEvent
172  */
173 public void addSelectionListener(SelectionListener listener) {
174   checkWidget();
175   if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
176   TypedListener typedListener = new TypedListener (listener);
177   addListener (SWT.Selection,typedListener);
178   addListener (SWT.DefaultSelection,typedListener);
179 }
180 
181 static int checkStyle (int style) {
182   return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
183 }
184 
185 void createHandle (int index) {
186   state |= HANDLE;
187   fixedHandle = OS.gtk_fixed_new ();
188   if (fixedHandle == 0) error (SWT.ERROR_NO_HANDLES);
189   OS.gtk_fixed_set_has_window (fixedHandle, true);
190   scrolledHandle = OS.gtk_scrolled_window_new (0, 0);
191   if (scrolledHandle == 0) error (SWT.ERROR_NO_HANDLES);
192   /*
193   * Columns:
194   * 0 - text
195   */
196   long /*int*/ [] types = new long /*int*/ [] {OS.G_TYPE_STRING ()};
197   modelHandle = OS.gtk_list_store_newv (types.length, types);
198   if (modelHandle == 0) error (SWT.ERROR_NO_HANDLES);
199   handle = OS.gtk_tree_view_new_with_model (modelHandle);
200   if (handle == 0) error (SWT.ERROR_NO_HANDLES);
201   long /*int*/ textRenderer = OS.gtk_cell_renderer_text_new ();
202   if (textRenderer == 0) error (SWT.ERROR_NO_HANDLES);
203   long /*int*/ columnHandle = OS.gtk_tree_view_column_new ();
204   if (columnHandle == 0) error (SWT.ERROR_NO_HANDLES);
205   OS.gtk_tree_view_column_pack_start (columnHandle, textRenderer, true);
206   OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, "text", TEXT_COLUMN);
207   OS.gtk_tree_view_insert_column (handle, columnHandle, index);
208   long /*int*/ parentHandle = parent.parentingHandle ();
209   OS.gtk_container_add (parentHandle, fixedHandle);
210   OS.gtk_container_add (fixedHandle, scrolledHandle);
211   OS.gtk_container_add (scrolledHandle, handle);
212   OS.gtk_widget_show (fixedHandle);
213   OS.gtk_widget_show (scrolledHandle);
214   OS.gtk_widget_show (handle);
215   
216   int mode = (style & SWT.MULTI) != 0 ? OS.GTK_SELECTION_MULTIPLE : OS.GTK_SELECTION_BROWSE;
217   long /*int*/ selectionHandle = OS.gtk_tree_view_get_selection (handle);
218   OS.gtk_tree_selection_set_mode (selectionHandle, mode);
219   OS.gtk_tree_view_set_headers_visible (handle, false);  
220   int hsp = (style & SWT.H_SCROLL) != 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
221   int vsp = (style & SWT.V_SCROLL) != 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
222   OS.gtk_scrolled_window_set_policy (scrolledHandle, hsp, vsp);
223   if ((style & SWT.BORDER) != 0) OS.gtk_scrolled_window_set_shadow_type (scrolledHandle, OS.GTK_SHADOW_ETCHED_IN);
224 }
225 
226 public Point computeSize (int wHint, int hHint, boolean changed) {
227   checkWidget ();
228   if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
229   if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
230   Point size = computeNativeSize (handle, wHint, hHint, changed);
231   Rectangle trim = computeTrim (0, 0, size.x, size.y);
232   size.x = trim.width;
233   size.y = trim.height;
234   return size;
235 }
236 
237 void deregister() {
238   super.deregister ();
239   display.removeWidget (OS.gtk_tree_view_get_selection (handle));
240 }
241 
242 /**
243  * Deselects the item at the given zero-relative index in the receiver.
244  * If the item at the index was already deselected, it remains
245  * deselected. Indices that are out of range are ignored.
246  *
247  * @param index the index of the item to deselect
248  *
249  * @exception SWTException <ul>
250  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
251  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
252  * </ul>
253  */
254 public void deselect (int index) {
255   checkWidget();
256   if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0)))  return;
257   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
258   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
259   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
260   OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index); 
261   OS.gtk_tree_selection_unselect_iter (selection, iter);
262   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
263   OS.g_free (iter);
264 }
265 
266 /**
267  * Deselects the items at the given zero-relative indices in the receiver.
268  * If the item at the given zero-relative index in the receiver 
269  * is selected, it is deselected.  If the item at the index
270  * was not selected, it remains deselected.  The range of the
271  * indices is inclusive. Indices that are out of range are ignored.
272  *
273  * @param start the start index of the items to deselect
274  * @param end the end index of the items to deselect
275  *
276  * @exception SWTException <ul>
277  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
278  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
279  * </ul>
280  */
281 public void deselect (int start, int end) {
282   checkWidget();
283   if (start < 0 && end < 0) return;
284   int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
285   if (start >= count && end >= count) return;
286   start = Math.min (count - 1, Math.max (0, start));
287   end = Math.min (count - 1, Math.max (0, end));
288   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
289   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
290   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
291   for (int index=start; index<=end; index++) {
292     OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index); 
293     OS.gtk_tree_selection_unselect_iter (selection, iter);
294   }
295   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
296   OS.g_free (iter);
297 }
298 
299 /**
300  * Deselects the items at the given zero-relative indices in the receiver.
301  * If the item at the given zero-relative index in the receiver 
302  * is selected, it is deselected.  If the item at the index
303  * was not selected, it remains deselected. Indices that are out
304  * of range and duplicate indices are ignored.
305  *
306  * @param indices the array of indices for the items to deselect
307  *
308  * @exception IllegalArgumentException <ul>
309  *    <li>ERROR_NULL_ARGUMENT - if the set of indices is null</li>
310  * </ul>
311  * @exception SWTException <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 public void deselect (int [] indices) {
317   checkWidget();
318   if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
319   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
320   int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
321   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
322   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
323   for (int i=0; i<indices.length; i++) {
324     int index = indices [i];
325     if (index < 0 || index > count - 1) continue;
326     OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index); 
327     OS.gtk_tree_selection_unselect_iter (selection, iter);
328   }
329   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
330   OS.g_free (iter);
331 }
332 
333 /**
334  * Deselects all selected items in the receiver.
335  *
336  * @exception SWTException <ul>
337  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
338  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
339  * </ul>
340  */
341 public void deselectAll () {
342   checkWidget();
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_selection_unselect_all (selection);
346   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
347 }
348 
349 GdkColor getBackgroundColor () {
350   return getBaseColor ();
351 }
352 
353 /**
354  * Returns the zero-relative index of the item which currently
355  * has the focus in the receiver, or -1 if no item has focus.
356  *
357  * @return the index of the selected item
358  *
359  * @exception SWTException <ul>
360  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
361  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
362  * </ul>
363  */
364 public int getFocusIndex () {
365   checkWidget();
366   long /*int*/ [] path = new long /*int*/ [1];
367   OS.gtk_tree_view_get_cursor (handle, path, null);
368   if (path [0] == 0) return -1;
369   long /*int*/ indices = OS.gtk_tree_path_get_indices (path [0]);
370   int [] index = new int []{-1};
371   if (indices != 0) OS.memmove (index, indices, 4);
372   OS.gtk_tree_path_free (path [0]);
373   return index [0];
374 }
375 
376 GdkColor getForegroundColor () {
377   return getTextColor ();
378 }
379 
380 /**
381  * Returns the item at the given, zero-relative index in the
382  * receiver. Throws an exception if the index is out of range.
383  *
384  * @param index the index of the item to return
385  * @return the item at the given index
386  *
387  * @exception IllegalArgumentException <ul>
388  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
389  * </ul>
390  * @exception SWTException <ul>
391  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
392  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
393  * </ul>
394  * @exception SWTError <ul>
395  *    <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure</li>
396  * </ul>
397  */
398 public String getItem (int index) {
399   checkWidget();
400   if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0)))  {
401     error (SWT.ERROR_INVALID_RANGE);
402   }
403   long /*int*/ [] ptr = new long /*int*/ [1];
404   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
405   OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
406   OS.gtk_tree_model_get (modelHandle, iter, 0, ptr, -1);
407   OS.g_free (iter);
408   if (ptr [0] == 0) return null;
409   int length = OS.strlen (ptr [0]);
410   byte[] buffer2 = new byte [length];
411   OS.memmove (buffer2, ptr [0], length);
412   OS.g_free (ptr [0]);
413   return new String (Converter.mbcsToWcs (null, buffer2));
414 }
415 
416 /**
417  * Returns the number of items contained in the receiver.
418  *
419  * @return the number of items
420  *
421  * @exception SWTException <ul>
422  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
423  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
424  * </ul>
425  * @exception SWTError <ul>
426  *    <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
427  * </ul>
428  */
429 public int getItemCount () {
430   checkWidget();
431   return OS.gtk_tree_model_iter_n_children (modelHandle, 0);
432 }
433 
434 /**
435  * Returns the height of the area which would be used to
436  * display <em>one</em> of the items in the tree.
437  *
438  * @return the height of one item
439  *
440  * @exception SWTException <ul>
441  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
442  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
443  * </ul>
444  * @exception SWTError <ul>
445  *    <li>ERROR_CANNOT_GET_ITEM_HEIGHT - if the operation fails because of an operating system failure</li>
446  * </ul>
447  */
448 public int getItemHeight () {
449   checkWidget();
450   int itemCount = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
451   long /*int*/ column = OS.gtk_tree_view_get_column (handle, 0);
452   if (itemCount == 0) {
453     int [] w = new int [1], h = new int [1];
454     OS.gtk_tree_view_column_cell_get_size (column, null, null, null, w, h);
455     return h [0];
456   } else {
457     long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
458     OS.gtk_tree_model_get_iter_first (modelHandle, iter);
459     OS.gtk_tree_view_column_cell_set_cell_data (column, modelHandle, iter, false, false);
460     int [] w = new int [1], h = new int [1];
461     OS.gtk_tree_view_column_cell_get_size (column, null, null, null, w, h);
462     OS.g_free (iter);
463     return h [0];
464   }
465 }
466 
467 /**
468  * Returns an array of <code>String</code>s which are the items
469  * in the receiver. 
470  * <p>
471  * Note: This is not the actual structure used by the receiver
472  * to maintain its list of items, so modifying the array will
473  * not affect the receiver. 
474  * </p>
475  *
476  * @return the items in the receiver's list
477  *
478  * @exception SWTException <ul>
479  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
480  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
481  * </ul>
482  * @exception SWTError <ul>
483  *    <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
484  *    <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</li>
485  * </ul>
486  */
487 public String [] getItems () {
488   checkWidget();
489   int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
490   long /*int*/ [] ptr = new long /*int*/ [1];
491   String [] result = new String [count];
492   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
493   for (int index=0; index<count; index++) {
494     OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
495     OS.gtk_tree_model_get (modelHandle, iter, 0, ptr, -1);
496     if (ptr [0] != 0) {
497       int length = OS.strlen (ptr [0]);
498       byte[] buffer = new byte [length];
499       OS.memmove (buffer, ptr [0], length);
500       OS.g_free (ptr [0]);
501       result [index] = new String (Converter.mbcsToWcs (null, buffer));
502     }
503   }
504   OS.g_free (iter);
505   return result;
506 }
507 
508 /**
509  * Returns an array of <code>String</code>s that are currently
510  * selected in the receiver. An empty array indicates that no
511  * items are selected.
512  * <p>
513  * Note: This is not the actual structure used by the receiver
514  * to maintain its selection, so modifying the array will
515  * not affect the receiver. 
516  * </p>
517  * @return an array representing the selection
518  *
519  * @exception SWTException <ul>
520  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
521  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
522  * </ul>
523  * @exception SWTError <ul>
524  *    <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure while getting the selection</li>
525  *    <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
526  * </ul>
527  */
528 public String [] getSelection () {
529   checkWidget();
530   int [] indices = getSelectionIndices ();
531   String [] result = new String [indices.length];
532   for (int i=0; i<indices.length; i++) {
533     result [i] = getItem (indices [i]);
534   }
535   return result;
536 }
537 
538 /**
539  * Returns the number of selected items contained in the receiver.
540  *
541  * @return the number of selected items
542  *
543  * @exception SWTException <ul>
544  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
545  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
546  * </ul>
547  * @exception SWTError <ul>
548  *    <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure</li>
549  * </ul>
550  */
551 public int getSelectionCount () {
552   checkWidget();
553   display.treeSelectionLength = 0;
554   display.treeSelection = null;
555   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
556   OS.gtk_tree_selection_selected_foreach (selection, display.treeSelectionProc, handle);
557   return display.treeSelectionLength;
558 }
559 
560 /**
561  * Returns the zero-relative index of the item which is currently
562  * selected in the receiver, or -1 if no item is selected.
563  *
564  * @return the index of the selected item
565  *
566  * @exception SWTException <ul>
567  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
568  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
569  * </ul>
570  * @exception SWTError <ul>
571  *    <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li>
572  * </ul>
573  */
574 public int getSelectionIndex () {
575   checkWidget();
576   int itemCount = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
577   display.treeSelectionLength  = 0;
578   display.treeSelection = new int [itemCount];
579   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
580   OS.gtk_tree_selection_selected_foreach (selection, display.treeSelectionProc, handle);
581   if (display.treeSelectionLength == 0) return -1;
582   return display.treeSelection [0];
583 }
584 
585 /**
586  * Returns the zero-relative indices of the items which are currently
587  * selected in the receiver.  The array is empty if no items are selected.
588  * <p>
589  * Note: This is not the actual structure used by the receiver
590  * to maintain its selection, so modifying the array will
591  * not affect the receiver. 
592  * </p>
593  * @return the array of indices of the selected items
594  *
595  * @exception SWTException <ul>
596  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
597  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
598  * </ul>
599  * @exception SWTError <ul>
600  *    <li>ERROR_CANNOT_GET_SELECTION - if the operation fails because of an operating system failure</li>
601  * </ul>
602  */
603 public int [] getSelectionIndices () {
604   checkWidget();
605   int itemCount = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
606   display.treeSelectionLength  = 0;
607   display.treeSelection = new int [itemCount];
608   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
609   OS.gtk_tree_selection_selected_foreach (selection, display.treeSelectionProc, handle);
610   if (display.treeSelectionLength == display.treeSelection.length) return display.treeSelection;
611   int [] result = new int [display.treeSelectionLength];
612   System.arraycopy (display.treeSelection, 0, result, 0, display.treeSelectionLength);
613   return result;
614 }
615 
616 /**
617  * Returns the zero-relative index of the item which is currently
618  * at the top of the receiver. This index can change when items are
619  * scrolled or new items are added or removed.
620  *
621  * @return the index of the top item
622  *
623  * @exception SWTException <ul>
624  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
625  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
626  * </ul>
627  */
628 public int getTopIndex () {
629   checkWidget();
630   long /*int*/ [] path = new long /*int*/ [1];
631   OS.gtk_widget_realize (handle);
632   if (!OS.gtk_tree_view_get_path_at_pos (handle, 1, 1, path, null, null, null)) return 0;
633   if (path [0] == 0) return 0;
634   long /*int*/ indices = OS.gtk_tree_path_get_indices (path[0]);
635   int[] index = new int [1];
636   if (indices != 0) OS.memmove (index, indices, 4);
637   OS.gtk_tree_path_free (path [0]);
638   return index [0];
639 }
640 
641 long /*int*/ gtk_changed (long /*int*/ widget) {
642   postEvent (SWT.Selection);
643   return 0;
644 }
645 
646 long /*int*/ gtk_button_press_event (long /*int*/ widget, long /*int*/ event) {
647   long /*int*/ result = super.gtk_button_press_event (widget, event);
648   if (result != 0) return result;
649   /*
650   * Bug in GTK. GTK segments fault, if the GtkTreeView widget is
651   * not in focus and all items in the widget are disposed before
652   * it finishes processing a button press.  The fix is to give
653   * focus to the widget before it starts processing the event.
654   */
655   if (!OS.GTK_WIDGET_HAS_FOCUS (handle)) {
656     OS.gtk_widget_grab_focus (handle);
657     // widget may be disposed at this point
658     if (isDisposed ()) return 0;
659   }
660   /*
661   * Feature in GTK.  In a multi-select list view, when multiple items are already
662   * selected, the selection state of the item is toggled and the previous selection 
663   * is cleared. This is not the desired behaviour when bringing up a popup menu.
664   * Also, when an item is reselected with the right button, the tree view issues
665   * an unwanted selection event. The workaround is to detect that case and not
666   * run the default handler when the item is already part of the current selection.
667   */
668   GdkEventButton gdkEvent = new GdkEventButton ();
669   OS.memmove (gdkEvent, event, GdkEventButton.sizeof);
670   int button = gdkEvent.button;
671   if (button == 3 && gdkEvent.type == OS.GDK_BUTTON_PRESS) {
672     long /*int*/ [] path = new long /*int*/ [1];
673     if (OS.gtk_tree_view_get_path_at_pos (handle, (int)gdkEvent.x, (int)gdkEvent.y, path, null, null, null)) {
674       if (path [0] != 0) {
675         long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
676         if (OS.gtk_tree_selection_path_is_selected (selection, path [0])) result = 1;
677         OS.gtk_tree_path_free (path [0]);
678       }
679     }
680   }
681   
682   /*
683   * Feature in GTK.  When the user clicks in a single selection GtkTreeView
684   * and there are no selected items, the first item is selected automatically
685   * before the click is processed, causing two selection events.  The is fix
686   * is the set the cursor item to be same as the clicked item to stop the
687   * widget from automatically selecting the first item.
688   */
689   if ((style & SWT.SINGLE) != 0 && getSelectionCount () == 0) {
690     long /*int*/ [] path = new long /*int*/ [1];
691     if (OS.gtk_tree_view_get_path_at_pos (handle, (int)gdkEvent.x, (int)gdkEvent.y, path, null, null, null)) {
692       if (path [0] != 0) {
693         long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
694         OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
695         OS.gtk_tree_view_set_cursor (handle, path [0], 0, false);
696         OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
697         OS.gtk_tree_path_free (path [0]);
698       }
699     }
700   }
701   return result;
702 }
703 
704 long /*int*/ gtk_key_press_event (long /*int*/ widget, long /*int*/ event) {
705   long /*int*/ result = super.gtk_key_press_event (widget, event);
706   if (result != 0) return result;
707 
708   /*
709   * Feature in GTK.  When an item is default selected using
710   * the return key, GTK does not issue notification. The fix is
711   * to issue this notification when the return key is pressed.
712   */
713   GdkEventKey keyEvent = new GdkEventKey ();
714   OS.memmove (keyEvent, event, GdkEventKey.sizeof);
715   int key = keyEvent.keyval;
716   switch (key) {
717     case OS.GDK_Return:
718     case OS.GDK_KP_Enter: {
719       postEvent (SWT.DefaultSelection);
720       break;
721     }
722   }
723   
724   return result;
725 }
726 
727 long /*int*/ gtk_row_activated (long /*int*/ tree, long /*int*/ path, long /*int*/ column) {
728   postEvent (SWT.DefaultSelection);
729   return 0;
730 }
731 
732 void hookEvents () {
733   super.hookEvents();
734   long /*int*/ selection = OS.gtk_tree_view_get_selection(handle);
735   OS.g_signal_connect (selection, OS.changed, display.windowProc2, CHANGED);
736   OS.g_signal_connect (handle, OS.row_activated, display.windowProc4, ROW_ACTIVATED);
737 }
738 
739 /**
740  * Gets the index of an item.
741  * <p>
742  * The list is searched starting at 0 until an
743  * item is found that is equal to the search item.
744  * If no item is found, -1 is returned.  Indexing
745  * is zero based.
746  *
747  * @param string the search item
748  * @return the index of the item
749  *
750  * @exception IllegalArgumentException <ul>
751  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
752  * </ul>
753  * @exception SWTException <ul>
754  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
755  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
756  * </ul>
757  */
758 public int indexOf (String string) {
759   checkWidget();
760   return indexOf (string, 0);
761 }
762 
763 /**
764  * Searches the receiver's list starting at the given, 
765  * zero-relative index until an item is found that is equal
766  * to the argument, and returns the index of that item. If
767  * no item is found or the starting index is out of range,
768  * returns -1.
769  *
770  * @param string the search item
771  * @param start the zero-relative index at which to start the search
772  * @return the index of the item
773  *
774  * @exception IllegalArgumentException <ul>
775  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
776  * </ul>
777  * @exception SWTException <ul>
778  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
779  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
780  * </ul>
781  * @exception SWTError <ul>
782  *    <li>ERROR_CANNOT_GET_COUNT - if the operation fails because of an operating system failure while getting the item count</li>
783  *    <li>ERROR_CANNOT_GET_ITEM - if the operation fails because of an operating system failure while getting an item</li>
784  * </ul>
785  */
786 public int indexOf (String string, int start) {
787   checkWidget();
788   if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
789   String [] items = getItems ();
790   for (int i=start; i<items.length; i++) {
791     if (items [i].equals (string)) return i;
792   }
793   return -1;
794 }
795 
796 /**
797  * Returns <code>true</code> if the item is selected,
798  * and <code>false</code> otherwise.  Indices out of
799  * range are ignored.
800  *
801  * @param index the index of the item
802  * @return the visibility state of the item at the index
803  *
804  * @exception SWTException <ul>
805  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
806  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
807  * </ul>
808  */
809 public boolean isSelected (int index) {
810   checkWidget();
811   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
812   byte [] buffer = Converter.wcsToMbcs (null, Integer.toString (index), true);
813   long /*int*/ path = OS.gtk_tree_path_new_from_string (buffer);
814   boolean answer = OS.gtk_tree_selection_path_is_selected (selection, path);
815   OS.gtk_tree_path_free (path);
816   return answer;
817 }
818 
819 long /*int*/ paintWindow () {
820   OS.gtk_widget_realize (handle);
821   return OS.gtk_tree_view_get_bin_window (handle);
822 }
823 
824 void register () {
825   super.register ();
826   display.addWidget (OS.gtk_tree_view_get_selection (handle), this);
827 }
828 
829 void releaseWidget () {
830   super.releaseWidget ();
831   if (modelHandle != 0) OS.g_object_unref (modelHandle);
832   modelHandle = 0;
833 }
834 
835 /**
836  * Removes the item from the receiver at the given
837  * zero-relative index.
838  *
839  * @param index the index for the item
840  *
841  * @exception IllegalArgumentException <ul>
842  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
843  * </ul>
844  * @exception SWTException <ul>
845  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
846  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
847  * </ul>
848  * @exception SWTError <ul>
849  *    <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
850  * </ul>
851  */
852 public void remove (int index) {
853   checkWidget();
854   if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0)))  {
855     error (SWT.ERROR_INVALID_RANGE);
856   }
857   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
858   OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
859   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
860   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
861   OS.gtk_list_store_remove (modelHandle, iter);
862   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
863   OS.g_free (iter);
864 }
865 
866 /**
867  * Removes the items from the receiver which are
868  * between the given zero-relative start and end 
869  * indices (inclusive).
870  *
871  * @param start the start of the range
872  * @param end the end of the range
873  *
874  * @exception IllegalArgumentException <ul>
875  *    <li>ERROR_INVALID_RANGE - if either the start or end are not between 0 and the number of elements in the list minus 1 (inclusive)</li>
876  * </ul>
877  * @exception SWTException <ul>
878  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
879  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
880  * </ul>
881  * @exception SWTError <ul>
882  *    <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
883  * </ul>
884  */
885 public void remove (int start, int end) {
886   checkWidget();
887   if (start > end) return;
888   int count =  OS.gtk_tree_model_iter_n_children (modelHandle, 0);
889   if (!(0 <= start && start <= end && end < count)) {
890     error (SWT.ERROR_INVALID_RANGE);
891   }
892   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
893   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
894   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
895   for (int index=end; index>=start; index--) {
896     OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
897     OS.gtk_list_store_remove (modelHandle, iter);
898   }
899   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
900   OS.g_free (iter);
901 }
902 
903 /**
904  * Searches the receiver's list starting at the first item
905  * until an item is found that is equal to the argument, 
906  * and removes that item from the list.
907  *
908  * @param string the item to remove
909  *
910  * @exception IllegalArgumentException <ul>
911  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
912  *    <li>ERROR_INVALID_ARGUMENT - if the string is not found in the list</li>
913  * </ul>
914  * @exception SWTException <ul>
915  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
916  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
917  * </ul>
918  * @exception SWTError <ul>
919  *    <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
920  * </ul>
921  */
922 public void remove (String string) {
923   checkWidget();
924   int index = indexOf (string, 0);
925   if (index == -1) error (SWT.ERROR_INVALID_ARGUMENT);
926   remove (index);
927 }
928 
929 /**
930  * Removes the items from the receiver at the given
931  * zero-relative indices.
932  *
933  * @param indices the array of indices of the items
934  *
935  * @exception IllegalArgumentException <ul>
936  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
937  *    <li>ERROR_NULL_ARGUMENT - if the indices array is null</li>
938  * </ul>
939  * @exception SWTException <ul>
940  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
941  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
942  * </ul>
943  * @exception SWTError <ul>
944  *    <li>ERROR_ITEM_NOT_REMOVED - if the operation fails because of an operating system failure</li>
945  * </ul>
946  */
947 public void remove (int [] indices) {
948   checkWidget();
949   if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
950   if (indices.length == 0) return;
951   int [] newIndices = new int [indices.length];
952   System.arraycopy (indices, 0, newIndices, 0, indices.length);
953   sort (newIndices);
954   int start = newIndices [newIndices.length - 1], end = newIndices [0];
955   int count = getItemCount();
956   if (!(0 <= start && start <= end && end < count)) {
957     error (SWT.ERROR_INVALID_RANGE);
958   }
959   long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
960   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
961   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
962   int last = -1;
963   for (int i=0; i<newIndices.length; i++) {
964     int index = newIndices [i];
965     if (index != last) {
966       OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
967       OS.gtk_list_store_remove (modelHandle, iter);
968       last = index;
969     }
970   }
971   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
972   OS.g_free (iter);
973 }
974 
975 /**
976  * Removes all of the items from the receiver.
977  * <p>
978  * @exception SWTException <ul>
979  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
980  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
981  * </ul>
982  */
983 public void removeAll () {
984   checkWidget();
985   long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
986   OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
987   OS.gtk_list_store_clear (modelHandle);
988   OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
989 }
990 
991 /**
992  * Removes the listener from the collection of listeners who will
993  * be notified when the receiver's selection changes.
994  *
995  * @param listener the listener which should no longer be notified
996  *
997  * @exception IllegalArgumentException <ul>
998  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
999  * </ul>
1000 * @exception SWTException <ul>
1001 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1002 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1003 * </ul>
1004 *
1005 * @see SelectionListener
1006 * @see #addSelectionListener
1007 */
1008public void removeSelectionListener(SelectionListener listener) {
1009  checkWidget();
1010  if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
1011  if (eventTable == null) return;
1012  eventTable.unhook (SWT.Selection, listener);
1013  eventTable.unhook (SWT.DefaultSelection,listener);  
1014}
1015
1016/**
1017 * Selects the item at the given zero-relative index in the receiver's 
1018 * list.  If the item at the index was already selected, it remains
1019 * selected. Indices that are out of range are ignored.
1020 *
1021 * @param index the index of the item to select
1022 *
1023 * @exception SWTException <ul>
1024 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1025 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1026 * </ul>
1027 */
1028public void select (int index) {
1029  checkWidget();
1030  if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0)))  return;
1031  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
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_model_iter_nth_child (modelHandle, iter, 0, index);
1035  OS.gtk_tree_selection_select_iter (selection, iter); 
1036  if ((style & SWT.SINGLE) != 0) {
1037    long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1038    OS.gtk_tree_view_set_cursor (handle, path, 0, false);
1039    OS.gtk_tree_path_free (path);
1040  }
1041  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1042  OS.g_free (iter);
1043}
1044
1045/**
1046 * Selects the items in the range specified by the given zero-relative
1047 * indices in the receiver. The range of indices is inclusive.
1048 * The current selection is not cleared before the new items are selected.
1049 * <p>
1050 * If an item in the given range is not selected, it is selected.
1051 * If an item in the given range was already selected, it remains selected.
1052 * Indices that are out of range are ignored and no items will be selected
1053 * if start is greater than end.
1054 * If the receiver is single-select and there is more than one item in the
1055 * given range, then all indices are ignored.
1056 *
1057 * @param start the start of the range
1058 * @param end the end of the range
1059 *
1060 * @exception SWTException <ul>
1061 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1062 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1063 * </ul>
1064 * 
1065 * @see List#setSelection(int,int)
1066 */
1067public void select (int start, int end) {
1068  checkWidget ();
1069  if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) return;
1070  int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
1071  if (count == 0 || start >= count) return;
1072  start = Math.max (0, start);
1073  end = Math.min (end, count - 1);
1074  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1075  long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
1076  OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1077  for (int index=start; index<=end; index++) {
1078    OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1079    OS.gtk_tree_selection_select_iter (selection, iter);
1080    if ((style & SWT.SINGLE) != 0) {
1081      long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1082      OS.gtk_tree_view_set_cursor (handle, path, 0, false);
1083      OS.gtk_tree_path_free (path);
1084    }
1085  }
1086  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1087  OS.g_free (iter);
1088}
1089
1090/**
1091 * Selects the items at the given zero-relative indices in the receiver.
1092 * The current selection is not cleared before the new items are selected.
1093 * <p>
1094 * If the item at a given index is not selected, it is selected.
1095 * If the item at a given index was already selected, it remains selected.
1096 * Indices that are out of range and duplicate indices are ignored.
1097 * If the receiver is single-select and multiple indices are specified,
1098 * then all indices are ignored.
1099 *
1100 * @param indices the array of indices for the items to select
1101 *
1102 * @exception IllegalArgumentException <ul>
1103 *    <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1104 * </ul>
1105 * @exception SWTException <ul>
1106 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1107 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1108 * </ul>
1109 * 
1110 * @see List#setSelection(int[])
1111 */
1112public void select (int [] indices) {
1113  checkWidget ();
1114  if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
1115  int length = indices.length;
1116  if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1117  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1118  int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
1119  long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
1120  OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1121  for (int i=0; i<length; i++) {
1122    int index = indices [i];
1123    if (index < 0 || index > count - 1) continue;
1124    OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1125    OS.gtk_tree_selection_select_iter (selection, iter); 
1126    if ((style & SWT.SINGLE) != 0) {
1127      long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1128      OS.gtk_tree_view_set_cursor (handle, path, 0, false);
1129      OS.gtk_tree_path_free (path);
1130      break;
1131    }
1132  }
1133  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1134  OS.g_free (iter);
1135}
1136
1137/**
1138 * Selects all of the items in the receiver.
1139 * <p>
1140 * If the receiver is single-select, do nothing.
1141 *
1142 * @exception SWTException <ul>
1143 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1144 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1145 * </ul>
1146 */
1147public void selectAll () {
1148  checkWidget();
1149  if ((style & SWT.SINGLE) != 0) return;
1150  long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
1151  OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1152  OS.gtk_tree_selection_select_all (selection);
1153  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1154}
1155
1156void selectFocusIndex (int index) {
1157  /*
1158   * Note that this method both selects and sets the focus to the
1159   * specified index, so any previous selection in the list will be lost.
1160   * gtk does not provide a way to just set focus to a specified list item.
1161   */
1162  int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
1163  if (!(0 <= index && index < count))  return;
1164  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1165  OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1166  long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1167  OS.gtk_tree_view_set_cursor (handle, path, 0, false);
1168  OS.gtk_tree_path_free (path);
1169  OS.g_free (iter);
1170}
1171
1172void setBackgroundColor (GdkColor color) {
1173  super.setBackgroundColor (color);
1174  OS.gtk_widget_modify_base (handle, 0, color);
1175}
1176
1177boolean setBounds (int x, int y, int width, int height, boolean move, boolean resize) {
1178  boolean result = super.setBounds (x, y, width, height, move, resize);
1179  /*
1180  * Bug on GTK.  The tree view sometimes does not get a paint
1181  * event or resizes to a one pixel square when resized in a new
1182  * shell that is not visible after any event loop has been run.  The
1183  * problem is intermittent. It doesn't seem to happen the first time
1184  * a new shell is created. The fix is to ensure the tree view is realized
1185  * after it has been resized.
1186  */
1187  OS.gtk_widget_realize (handle);
1188  return result;
1189}
1190
1191void setForegroundColor (GdkColor color) {
1192  super.setForegroundColor (color);
1193  OS.gtk_widget_modify_text (handle, 0, color);
1194}
1195
1196/**
1197 * Sets the text of the item in the receiver's list at the given
1198 * zero-relative index to the string argument. This is equivalent
1199 * to <code>remove</code>'ing the old item at the index, and then
1200 * <code>add</code>'ing the new item at that index.
1201 *
1202 * @param index the index for the item
1203 * @param string the new text for the item
1204 *
1205 * @exception IllegalArgumentException <ul>
1206 *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1207 *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
1208 * </ul>
1209 * @exception SWTException <ul>
1210 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1211 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1212 * </ul>
1213 * @exception SWTError <ul>
1214 *    <li>ERROR_ITEM_NOT_REMOVED - if the remove operation fails because of an operating system failure</li>
1215 *    <li>ERROR_ITEM_NOT_ADDED - if the add operation fails because of an operating system failure</li>
1216 * </ul>
1217 */
1218public void setItem (int index, String string) {
1219  checkWidget();
1220  if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1221  if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0)))  {
1222    error (SWT.ERROR_INVALID_RANGE);
1223  }
1224  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1225  OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1226  byte [] buffer = Converter.wcsToMbcs (null, string, true);
1227  OS.gtk_list_store_set (modelHandle, iter, TEXT_COLUMN, buffer, -1);
1228  OS.g_free (iter);
1229}
1230
1231/**
1232 * Sets the receiver's items to be the given array of items.
1233 *
1234 * @param items the array of items
1235 *
1236 * @exception IllegalArgumentException <ul>
1237 *    <li>ERROR_NULL_ARGUMENT - if the items array is null</li>
1238 * </ul>
1239 * @exception SWTException <ul>
1240 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1241 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1242 * </ul>
1243 * @exception SWTError <ul>
1244 *    <li>ERROR_ITEM_NOT_ADDED - if the operation fails because of an operating system failure</li>
1245 * </ul>
1246 */
1247public void setItems (String [] items) {
1248  checkWidget();
1249  if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1250  long /*int*/ selection = OS.gtk_tree_view_get_selection (handle);
1251  OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1252  OS.gtk_list_store_clear (modelHandle);
1253  OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1254  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1255  if (iter == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
1256  for (int i=0; i<items.length; i++) {
1257    String string = items [i];
1258    if (string == null) {
1259      OS.g_free (iter);
1260      error (SWT.ERROR_ITEM_NOT_ADDED);
1261    }
1262    byte [] buffer = Converter.wcsToMbcs (null, string, true);
1263    OS.gtk_list_store_append (modelHandle, iter);
1264    OS.gtk_list_store_set (modelHandle, iter, TEXT_COLUMN, buffer, -1);
1265  }
1266  OS.g_free (iter);
1267}
1268
1269/**
1270 * Selects the item at the given zero-relative index in the receiver. 
1271 * If the item at the index was already selected, it remains selected.
1272 * The current selected is first cleared, then the new items are selected.
1273 * Indices that are out of range are ignored.
1274 *
1275 * @param index the index of the item to select
1276 *
1277 * @exception SWTException <ul>
1278 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1279 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1280 * </ul>
1281 * @see List#deselectAll()
1282 * @see List#select(int)
1283 */
1284public void setSelection (int index) {
1285  checkWidget();
1286  if ((style & SWT.MULTI) != 0) {
1287    deselectAll ();
1288    if (index >= 0) selectFocusIndex (index);
1289  } else {
1290    select (index);
1291  }
1292  showSelection ();
1293}
1294
1295/**
1296 * Selects the items in the range specified by the given zero-relative
1297 * indices in the receiver. The range of indices is inclusive.
1298 * The current selection is cleared before the new items are selected.
1299 * <p>
1300 * Indices that are out of range are ignored and no items will be selected
1301 * if start is greater than end.
1302 * If the receiver is single-select and there is more than one item in the
1303 * given range, then all indices are ignored.
1304 *
1305 * @param start the start index of the items to select
1306 * @param end the end index of the items to select
1307 *
1308 * @exception SWTException <ul>
1309 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1310 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1311 * </ul>
1312 *
1313 * @see List#deselectAll()
1314 * @see List#select(int,int)
1315 */
1316public void setSelection (int start, int end) {
1317  checkWidget ();
1318  if (end < 0 || start > end || ((style & SWT.SINGLE) != 0 && start != end)) {
1319    deselectAll ();
1320    return;
1321  }
1322  int count = OS.gtk_tree_model_iter_n_children (modelHandle, 0);
1323  if (count == 0 || start >= count) {
1324    deselectAll ();
1325    return;
1326  }
1327  start = Math.max (0, start);
1328  end = Math.min (end, count - 1);
1329  if ((style & SWT.MULTI) != 0) {
1330    deselectAll ();
1331    selectFocusIndex (start);
1332    start++;
1333  }
1334  select (start, end);
1335  showSelection ();
1336}
1337
1338/**
1339 * Selects the items at the given zero-relative indices in the receiver.
1340 * The current selection is cleared before the new items are selected.
1341 * <p>
1342 * Indices that are out of range and duplicate indices are ignored.
1343 * If the receiver is single-select and multiple indices are specified,
1344 * then all indices are ignored.
1345 *
1346 * @param indices the indices of the items to select
1347 *
1348 * @exception IllegalArgumentException <ul>
1349 *    <li>ERROR_NULL_ARGUMENT - if the array of indices is null</li>
1350 * </ul>
1351 * @exception SWTException <ul>
1352 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1353 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1354 * </ul>
1355 *
1356 * @see List#deselectAll()
1357 * @see List#select(int[])
1358 */
1359public void setSelection(int[] indices) {
1360  checkWidget ();
1361  if (indices == null) error (SWT.ERROR_NULL_ARGUMENT);
1362  deselectAll ();
1363  int length = indices.length;
1364  if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) return;
1365  if ((style & SWT.MULTI) != 0) {
1366    int focusIndex = indices [0];
1367    if (focusIndex >= 0) {
1368      selectFocusIndex (focusIndex);
1369      int [] temp = indices;
1370      indices = new int [length - 1];
1371      System.arraycopy (temp, 1, indices, 0, length - 1);
1372    }
1373  }
1374  select (indices);
1375  showSelection ();
1376}
1377
1378/**
1379 * Sets the receiver's selection to be the given array of items.
1380 * The current selection is cleared before the new items are selected.
1381 * <p>
1382 * Items that are not in the receiver are ignored.
1383 * If the receiver is single-select and multiple items are specified,
1384 * then all items are ignored.
1385 *
1386 * @param items the array of items
1387 *
1388 * @exception IllegalArgumentException <ul>
1389 *    <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
1390 * </ul>
1391 * @exception SWTException <ul>
1392 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1393 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1394 * </ul>
1395 *
1396 * @see List#deselectAll()
1397 * @see List#select(int[])
1398 * @see List#setSelection(int[])
1399 */
1400public void setSelection (String [] items) {
1401  checkWidget ();
1402  if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
1403  int length = items.length;
1404  if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) {
1405    deselectAll ();
1406    return;
1407  }
1408  if ((style & SWT.MULTI) != 0) deselectAll ();
1409  boolean firstSelect = true;
1410  int singleSelectIndex = -1;
1411  for (int i = 0; i < length; i++) {
1412    int index = 0;
1413    String string = items [i];
1414    if (string != null) {
1415      while ((index = indexOf (string, index)) != -1) {
1416        if ((style & SWT.MULTI) != 0) {
1417          if (firstSelect) {
1418            firstSelect = false;
1419            selectFocusIndex (index);
1420          } else {
1421            select (index);
1422          }
1423        } else {  /* SINGLE */
1424          singleSelectIndex = index;
1425          break;
1426        }
1427        index++;
1428      }
1429    }
1430  }
1431  if ((style & SWT.SINGLE) != 0) {
1432    if (singleSelectIndex == -1) {
1433      deselectAll ();
1434    } else {
1435      select (singleSelectIndex);
1436    }
1437  }
1438  showSelection ();
1439}
1440
1441/**
1442 * Sets the zero-relative index of the item which is currently
1443 * at the top of the receiver. This index can change when items
1444 * are scrolled or new items are added and removed.
1445 *
1446 * @param index the index of the top item
1447 *
1448 * @exception SWTException <ul>
1449 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1450 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1451 * </ul>
1452 */
1453public void setTopIndex (int index) {
1454  checkWidget();
1455  if (!(0 <= index && index < OS.gtk_tree_model_iter_n_children (modelHandle, 0))) return;
1456  // FIXME - For some reason, sometimes the tree scrolls to the wrong place
1457  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1458  OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1459  long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1460  OS.gtk_tree_view_scroll_to_cell (handle, path, 0, true, 0, 0);
1461  OS.gtk_tree_path_free (path);
1462  OS.g_free (iter);
1463}
1464
1465/**
1466 * Shows the selection.  If the selection is already showing in the receiver,
1467 * this method simply returns.  Otherwise, the items are scrolled until
1468 * the selection is visible.
1469 *
1470 * @exception SWTException <ul>
1471 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1472 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1473 * </ul>
1474 */
1475public void showSelection () {
1476  checkWidget();
1477  int index = getSelectionIndex ();
1478  if (index == -1) return;
1479  long /*int*/ iter = OS.g_malloc (OS.GtkTreeIter_sizeof ());
1480  OS.gtk_tree_model_iter_nth_child (modelHandle, iter, 0, index);
1481  long /*int*/ path = OS.gtk_tree_model_get_path (modelHandle, iter);
1482  OS.gtk_tree_view_scroll_to_cell (handle, path, 0, true, 0, 0);
1483  OS.gtk_tree_path_free (path);
1484  OS.g_free (iter);
1485}
1486
1487long /*int*/ treeSelectionProc (long /*int*/ model, long /*int*/ path, long /*int*/ iter, int[] selection, int length) {
1488  if (selection != null) { 
1489    long /*int*/ indices = OS.gtk_tree_path_get_indices (path);
1490    if (indices != 0) {
1491      int [] index = new int [1];
1492      OS.memmove (index, indices, 4);
1493      selection [length] = index [0];
1494    }
1495  }
1496  return 0;
1497}
1498
1499}