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