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}