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.Table;
|
|
14
|
|
15
|
|
16
|
|
17 import org.eclipse.swt.SWT;
|
|
18 import org.eclipse.swt.SWTException;
|
|
19 import org.eclipse.swt.events.SelectionEvent;
|
|
20 import org.eclipse.swt.events.SelectionListener;
|
|
21 import org.eclipse.swt.graphics.Color;
|
|
22 import org.eclipse.swt.graphics.Font;
|
|
23 import org.eclipse.swt.graphics.GC;
|
|
24 import org.eclipse.swt.graphics.Image;
|
|
25 import org.eclipse.swt.graphics.Point;
|
|
26 import org.eclipse.swt.graphics.Rectangle;
|
|
27 import org.eclipse.swt.internal.gtk.OS;
|
|
28 import org.eclipse.swt.widgets.Composite;
|
|
29 import org.eclipse.swt.widgets.TableItem;
|
|
30 import org.eclipse.swt.widgets.TableColumn;
|
|
31 import org.eclipse.swt.widgets.Listener;
|
|
32 import org.eclipse.swt.widgets.ImageList;
|
|
33 import org.eclipse.swt.widgets.Shell;
|
|
34 import org.eclipse.swt.widgets.Decorations;
|
|
35 import org.eclipse.swt.widgets.Menu;
|
|
36 import org.eclipse.swt.widgets.Display;
|
|
37 import org.eclipse.swt.widgets.ScrollBar;
|
|
38 import org.eclipse.swt.widgets.Event;
|
|
39 import org.eclipse.swt.widgets.Control;
|
|
40 import org.eclipse.swt.widgets.TypedListener;
|
|
41 import java.lang.all;
|
|
42
|
48
|
43 version(Tango){
|
25
|
44 import tango.util.Convert;
|
48
|
45 } else { // Phobos
|
|
46 }
|
25
|
47
|
|
48 /**
|
|
49 * Instances of this class implement a selectable user interface
|
|
50 * object that displays a list of images and strings and issues
|
|
51 * notification when selected.
|
|
52 * <p>
|
|
53 * The item children that may be added to instances of this class
|
|
54 * must be of type <code>TableItem</code>.
|
|
55 * </p><p>
|
|
56 * Style <code>VIRTUAL</code> is used to create a <code>Table</code> whose
|
|
57 * <code>TableItem</code>s are to be populated by the client on an on-demand basis
|
|
58 * instead of up-front. This can provide significant performance improvements for
|
|
59 * tables that are very large or for which <code>TableItem</code> population is
|
|
60 * expensive (for example, retrieving values from an external source).
|
|
61 * </p><p>
|
|
62 * Here is an example of using a <code>Table</code> with style <code>VIRTUAL</code>:
|
|
63 * <code><pre>
|
|
64 * final Table table = new Table (parent, SWT.VIRTUAL | SWT.BORDER);
|
|
65 * table.setItemCount (1000000);
|
|
66 * table.addListener (SWT.SetData, new Listener () {
|
|
67 * public void handleEvent (Event event) {
|
|
68 * TableItem item = (TableItem) event.item;
|
|
69 * int index = table.indexOf (item);
|
|
70 * item.setText ("Item " + index);
|
|
71 * System.out.println (item.getText ());
|
|
72 * }
|
|
73 * });
|
|
74 * </pre></code>
|
|
75 * </p><p>
|
|
76 * Note that although this class is a subclass of <code>Composite</code>,
|
|
77 * it does not normally make sense to add <code>Control</code> children to
|
|
78 * it, or set a layout on it, unless implementing something like a cell
|
|
79 * editor.
|
|
80 * </p><p>
|
|
81 * <dl>
|
|
82 * <dt><b>Styles:</b></dt>
|
|
83 * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, HIDE_SELECTION, VIRTUAL, NO_SCROLL</dd>
|
|
84 * <dt><b>Events:</b></dt>
|
|
85 * <dd>Selection, DefaultSelection, SetData, MeasureItem, EraseItem, PaintItem</dd>
|
|
86 * </dl>
|
|
87 * </p><p>
|
|
88 * Note: Only one of the styles SINGLE, and MULTI may be specified.
|
|
89 * </p><p>
|
|
90 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
|
|
91 * </p>
|
|
92 *
|
|
93 * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
|
|
94 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
|
|
95 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
|
|
96 */
|
|
97 public class Table : Composite {
|
|
98
|
|
99 alias Composite.computeSize computeSize;
|
|
100 alias Composite.createHandle createHandle;
|
|
101 alias Composite.dragDetect dragDetect;
|
|
102 alias Composite.mnemonicHit mnemonicHit;
|
|
103 alias Composite.mnemonicMatch mnemonicMatch;
|
|
104 alias Composite.setBackgroundColor setBackgroundColor;
|
|
105 alias Composite.setBounds setBounds;
|
|
106
|
|
107 CallbackData treeSelectionCallbackData;
|
|
108 GtkWidget* modelHandle, checkRenderer;
|
|
109 int itemCount, columnCount, lastIndexOf, sortDirection;
|
|
110 GtkWidget* ignoreCell;
|
|
111 TableItem [] items;
|
|
112 TableColumn [] columns;
|
|
113 TableItem currentItem;
|
|
114 TableColumn sortColumn;
|
|
115 ImageList imageList, headerImageList;
|
|
116 bool firstCustomDraw;
|
|
117 int drawState, drawFlags;
|
|
118 GdkColor* drawForeground;
|
|
119 bool ownerDraw, ignoreSize;
|
|
120
|
|
121 static const int CHECKED_COLUMN = 0;
|
|
122 static const int GRAYED_COLUMN = 1;
|
|
123 static const int FOREGROUND_COLUMN = 2;
|
|
124 static const int BACKGROUND_COLUMN = 3;
|
|
125 static const int FONT_COLUMN = 4;
|
|
126 static const int FIRST_COLUMN = FONT_COLUMN + 1;
|
|
127 static const int CELL_PIXBUF = 0;
|
|
128 static const int CELL_TEXT = 1;
|
|
129 static const int CELL_FOREGROUND = 2;
|
|
130 static const int CELL_BACKGROUND = 3;
|
|
131 static const int CELL_FONT = 4;
|
|
132 static const int CELL_TYPES = CELL_FONT + 1;
|
|
133
|
|
134 /**
|
|
135 * Constructs a new instance of this class given its parent
|
|
136 * and a style value describing its behavior and appearance.
|
|
137 * <p>
|
|
138 * The style value is either one of the style constants defined in
|
|
139 * class <code>SWT</code> which is applicable to instances of this
|
|
140 * class, or must be built by <em>bitwise OR</em>'ing together
|
|
141 * (that is, using the <code>int</code> "|" operator) two or more
|
|
142 * of those <code>SWT</code> style constants. The class description
|
|
143 * lists the style constants that are applicable to the class.
|
|
144 * Style bits are also inherited from superclasses.
|
|
145 * </p>
|
|
146 *
|
|
147 * @param parent a composite control which will be the parent of the new instance (cannot be null)
|
|
148 * @param style the style of control to construct
|
|
149 *
|
|
150 * @exception IllegalArgumentException <ul>
|
|
151 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
|
|
152 * </ul>
|
|
153 * @exception SWTException <ul>
|
|
154 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
|
|
155 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
|
|
156 * </ul>
|
|
157 *
|
|
158 * @see SWT#SINGLE
|
|
159 * @see SWT#MULTI
|
|
160 * @see SWT#CHECK
|
|
161 * @see SWT#FULL_SELECTION
|
|
162 * @see SWT#HIDE_SELECTION
|
|
163 * @see SWT#VIRTUAL
|
|
164 * @see SWT#NO_SCROLL
|
|
165 * @see Widget#checkSubclass
|
|
166 * @see Widget#getStyle
|
|
167 */
|
|
168 public this (Composite parent, int style) {
|
|
169 super (parent, checkStyle (style));
|
|
170 }
|
|
171
|
|
172 override void _addListener (int eventType, Listener listener) {
|
|
173 super._addListener (eventType, listener);
|
|
174 if (!ownerDraw) {
|
|
175 switch (eventType) {
|
|
176 case SWT.MeasureItem:
|
|
177 case SWT.EraseItem:
|
|
178 case SWT.PaintItem:
|
|
179 ownerDraw = true;
|
|
180 recreateRenderers ();
|
|
181 break;
|
|
182 default:
|
|
183 }
|
|
184 }
|
|
185 }
|
|
186
|
|
187 TableItem _getItem (int index) {
|
|
188 if ((style & SWT.VIRTUAL) is 0) return items [index];
|
|
189 if (items [index] !is null) return items [index];
|
|
190 return items [index] = new TableItem (this, SWT.NONE, index, false);
|
|
191 }
|
|
192
|
|
193 static int checkStyle (int style) {
|
|
194 /*
|
|
195 * Feature in Windows. Even when WS_HSCROLL or
|
|
196 * WS_VSCROLL is not specified, Windows creates
|
|
197 * trees and tables with scroll bars. The fix
|
|
198 * is to set H_SCROLL and V_SCROLL.
|
|
199 *
|
|
200 * NOTE: This code appears on all platforms so that
|
|
201 * applications have consistent scroll bar behavior.
|
|
202 */
|
|
203 if ((style & SWT.NO_SCROLL) is 0) {
|
|
204 style |= SWT.H_SCROLL | SWT.V_SCROLL;
|
|
205 }
|
|
206 /* GTK is always FULL_SELECTION */
|
|
207 style |= SWT.FULL_SELECTION;
|
|
208 return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
|
|
209 }
|
|
210
|
|
211 override void cellDataProc (
|
|
212 GtkTreeViewColumn *tree_column,
|
|
213 GtkCellRenderer *cell,
|
|
214 GtkTreeModel *tree_model,
|
|
215 GtkTreeIter *iter,
|
|
216 void* data)
|
|
217 {
|
|
218 if (cell is cast(GtkCellRenderer*)ignoreCell) return;
|
|
219 auto path = OS.gtk_tree_model_get_path (tree_model, iter);
|
|
220 auto index = OS.gtk_tree_path_get_indices (path);
|
|
221 TableItem item = _getItem (index[0]);
|
|
222 OS.gtk_tree_path_free (path);
|
|
223 if (item !is null) OS.g_object_set_qdata (cast(GObject*)cell, Display.SWT_OBJECT_INDEX2, item.handle);
|
|
224 bool isPixbuf = OS.GTK_IS_CELL_RENDERER_PIXBUF (cast(GTypeInstance*)cell);
|
|
225 if (!(isPixbuf || OS.GTK_IS_CELL_RENDERER_TEXT (cast(GTypeInstance*)cell))) return;
|
|
226 int modelIndex = -1;
|
|
227 bool customDraw = false;
|
|
228 if (columnCount is 0) {
|
|
229 modelIndex = Table.FIRST_COLUMN;
|
|
230 customDraw = firstCustomDraw;
|
|
231 } else {
|
|
232 TableColumn column = cast(TableColumn) display.getWidget (cast(GtkWidget*)tree_column);
|
|
233 if (column !is null) {
|
|
234 modelIndex = column.modelIndex;
|
|
235 customDraw = column.customDraw;
|
|
236 }
|
|
237 }
|
|
238 if (modelIndex is -1) return 0;
|
|
239 bool setData = false;
|
|
240 if ((style & SWT.VIRTUAL) !is 0) {
|
|
241 /*
|
|
242 * Feature in GTK. On GTK before 2.4, fixed_height_mode is not
|
|
243 * supported, and the tree asks for the data of all items. The
|
|
244 * fix is to only provide the data if the row is visible.
|
|
245 */
|
|
246 if (OS.GTK_VERSION < OS.buildVERSION (2, 3, 2)) {
|
|
247 OS.gtk_widget_realize (handle);
|
|
248 GdkRectangle visible;
|
|
249 OS.gtk_tree_view_get_visible_rect (handle, &visible);
|
|
250 GdkRectangle area;
|
|
251 path = OS.gtk_tree_model_get_path (tree_model, iter);
|
|
252 OS.gtk_tree_view_get_cell_area (handle, path, tree_column, &area);
|
|
253 OS.gtk_tree_path_free (path);
|
|
254 if (area.y + area.height < 0 || area.y + visible.y > visible.y + visible.height) {
|
|
255 /* Give an image from the image list to make sure the row has
|
|
256 * the correct height.
|
|
257 */
|
|
258 if (imageList !is null && imageList.pixbufs.length > 0) {
|
|
259 if (isPixbuf) OS.g_object_set1 (cell, OS.pixbuf.ptr, cast(int)imageList.pixbufs [0] );
|
|
260 }
|
|
261 return 0;
|
|
262 }
|
|
263 }
|
|
264 if (!item.cached) {
|
|
265 lastIndexOf = index[0];
|
|
266 setData = checkData (item);
|
|
267 }
|
|
268 }
|
|
269 void* ptr;
|
|
270 if (setData) {
|
|
271 if (isPixbuf) {
|
|
272 OS.gtk_tree_model_get1 (tree_model, iter, modelIndex + CELL_PIXBUF, &ptr);
|
|
273 OS.g_object_set1 (cell, OS.pixbuf.ptr, cast(int)ptr);
|
|
274 } else {
|
|
275 OS.gtk_tree_model_get1 (tree_model, iter, modelIndex + CELL_TEXT, &ptr);
|
|
276 if (ptr !is null) {
|
|
277 OS.g_object_set1 (cell, OS.text.ptr, cast(int)ptr);
|
|
278 OS.g_free (ptr);
|
|
279 }
|
|
280 }
|
|
281 }
|
|
282 if (customDraw) {
|
|
283 /*
|
|
284 * Bug on GTK. Gtk renders the background on top of the checkbox and pixbuf.
|
|
285 * This only happens in version 2.2.1 and earlier. The fix is not to set the background.
|
|
286 */
|
|
287 if (OS.GTK_VERSION > OS.buildVERSION (2, 2, 1)) {
|
|
288 if (!ownerDraw) {
|
|
289 ptr = null;
|
|
290 OS.gtk_tree_model_get1 (tree_model, iter, modelIndex + CELL_BACKGROUND, &ptr);
|
|
291 if (ptr !is null) {
|
|
292 OS.g_object_set1 (cell, OS.cell_background_gdk.ptr, cast(int)ptr);
|
|
293 }
|
|
294 }
|
|
295 }
|
|
296 if (!isPixbuf) {
|
|
297 ptr = null;
|
|
298 OS.gtk_tree_model_get1 (tree_model, iter, modelIndex + CELL_FOREGROUND, &ptr);
|
|
299 if (ptr !is null) {
|
|
300 OS.g_object_set1 (cell, OS.foreground_gdk.ptr, cast(int)ptr);
|
|
301 }
|
|
302 ptr = null;
|
|
303 OS.gtk_tree_model_get1 (tree_model, iter, modelIndex + CELL_FONT, &ptr);
|
|
304 if (ptr !is null) {
|
|
305 OS.g_object_set1 (cell, OS.font_desc.ptr, cast(int)ptr);
|
|
306 }
|
|
307 }
|
|
308 }
|
|
309 if (setData) {
|
|
310 ignoreCell = cast(GtkWidget*)cell;
|
|
311 setScrollWidth (tree_column, item);
|
|
312 ignoreCell = null;
|
|
313 }
|
|
314 return;
|
|
315 }
|
|
316
|
|
317 bool checkData (TableItem item) {
|
|
318 if (item.cached) return true;
|
|
319 if ((style & SWT.VIRTUAL) !is 0) {
|
|
320 item.cached = true;
|
|
321 Event event = new Event ();
|
|
322 event.item = item;
|
|
323 event.index = indexOf (item);
|
|
324 int mask = OS.G_SIGNAL_MATCH_DATA | OS.G_SIGNAL_MATCH_ID;
|
|
325 int signal_id = OS.g_signal_lookup (OS.row_changed.ptr, OS.gtk_tree_model_get_type ());
|
|
326 OS.g_signal_handlers_block_matched (modelHandle, mask, signal_id, 0, null, null, handle);
|
|
327 currentItem = item;
|
|
328 sendEvent (SWT.SetData, event);
|
|
329 //widget could be disposed at this point
|
|
330 currentItem = null;
|
|
331 if (isDisposed ()) return false;
|
|
332 OS.g_signal_handlers_unblock_matched (modelHandle, mask, signal_id, 0, null, null, handle);
|
|
333 if (item.isDisposed ()) return false;
|
|
334 }
|
|
335 return true;
|
|
336 }
|
|
337
|
|
338 protected override void checkSubclass () {
|
|
339 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
|
|
340 }
|
|
341
|
|
342 /**
|
|
343 * Adds the listener to the collection of listeners who will
|
|
344 * be notified when the user changes the receiver's selection, by sending
|
|
345 * it one of the messages defined in the <code>SelectionListener</code>
|
|
346 * interface.
|
|
347 * <p>
|
|
348 * When <code>widgetSelected</code> is called, the item field of the event object is valid.
|
|
349 * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
|
|
350 * the event object detail field contains the value <code>SWT.CHECK</code>.
|
|
351 * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
|
|
352 * The item field of the event object is valid for default selection, but the detail field is not used.
|
|
353 * </p>
|
|
354 *
|
|
355 * @param listener the listener which should be notified when the user changes the receiver's selection
|
|
356 *
|
|
357 * @exception IllegalArgumentException <ul>
|
|
358 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
359 * </ul>
|
|
360 * @exception SWTException <ul>
|
|
361 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
362 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
363 * </ul>
|
|
364 *
|
|
365 * @see SelectionListener
|
|
366 * @see #removeSelectionListener
|
|
367 * @see SelectionEvent
|
|
368 */
|
|
369 public void addSelectionListener (SelectionListener listener) {
|
|
370 checkWidget ();
|
|
371 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
372 TypedListener typedListener = new TypedListener (listener);
|
|
373 addListener (SWT.Selection, typedListener);
|
|
374 addListener (SWT.DefaultSelection, typedListener);
|
|
375 }
|
|
376
|
|
377 int calculateWidth (GtkTreeViewColumn* column, GtkTreeIter* iter) {
|
|
378 OS.gtk_tree_view_column_cell_set_cell_data (column, modelHandle, iter, false, false);
|
|
379 /*
|
|
380 * Bug in GTK. The width calculated by gtk_tree_view_column_cell_get_size()
|
|
381 * always grows in size regardless of the text or images in the table.
|
|
382 * The fix is to determine the column width from the cell renderers.
|
|
383 */
|
|
384 // Code intentionally commented
|
|
385 //int [] width = new int [1];
|
|
386 //OS.gtk_tree_view_column_cell_get_size (column, null, null, null, width, null);
|
|
387 //return width [0];
|
|
388
|
|
389 int width = 0;
|
|
390 int w;
|
|
391 OS.gtk_widget_style_get1(handle, OS.focus_line_width.ptr, &w );
|
|
392 width += 2 * w;
|
|
393 auto list = OS.gtk_tree_view_column_get_cell_renderers (column);
|
|
394 if (list is null) return 0;
|
|
395 auto temp = list;
|
|
396 while (temp !is null) {
|
|
397 auto renderer = OS.g_list_data (temp);
|
|
398 if (renderer !is null) {
|
|
399 OS.gtk_cell_renderer_get_size (renderer, handle, null, null, null, &w, null);
|
|
400 width += w;
|
|
401 }
|
|
402 temp = OS.g_list_next (temp);
|
|
403 }
|
|
404 OS.g_list_free (list);
|
|
405 return width;
|
|
406 }
|
|
407
|
|
408 /**
|
|
409 * Clears the item at the given zero-relative index in the receiver.
|
|
410 * The text, icon and other attributes of the item are set to the default
|
|
411 * value. If the table was created with the <code>SWT.VIRTUAL</code> style,
|
|
412 * these attributes are requested again as needed.
|
|
413 *
|
|
414 * @param index the index of the item to clear
|
|
415 *
|
|
416 * @exception IllegalArgumentException <ul>
|
|
417 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
418 * </ul>
|
|
419 * @exception SWTException <ul>
|
|
420 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
421 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
422 * </ul>
|
|
423 *
|
|
424 * @see SWT#VIRTUAL
|
|
425 * @see SWT#SetData
|
|
426 *
|
|
427 * @since 3.0
|
|
428 */
|
|
429 public void clear (int index) {
|
|
430 checkWidget ();
|
|
431 if (!(0 <= index && index < itemCount)) {
|
|
432 error(SWT.ERROR_INVALID_RANGE);
|
|
433 }
|
|
434 TableItem item = items [index];
|
|
435 if (item !is null) item.clear ();
|
|
436 }
|
|
437
|
|
438 /**
|
|
439 * Removes the items from the receiver which are between the given
|
|
440 * zero-relative start and end indices (inclusive). The text, icon
|
|
441 * and other attributes of the items are set to their default values.
|
|
442 * If the table was created with the <code>SWT.VIRTUAL</code> style,
|
|
443 * these attributes are requested again as needed.
|
|
444 *
|
|
445 * @param start the start index of the item to clear
|
|
446 * @param end the end index of the item to clear
|
|
447 *
|
|
448 * @exception IllegalArgumentException <ul>
|
|
449 * <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>
|
|
450 * </ul>
|
|
451 * @exception SWTException <ul>
|
|
452 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
453 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
454 * </ul>
|
|
455 *
|
|
456 * @see SWT#VIRTUAL
|
|
457 * @see SWT#SetData
|
|
458 *
|
|
459 * @since 3.0
|
|
460 */
|
|
461 public void clear (int start, int end) {
|
|
462 checkWidget ();
|
|
463 if (start > end) return;
|
|
464 if (!(0 <= start && start <= end && end < itemCount)) {
|
|
465 error (SWT.ERROR_INVALID_RANGE);
|
|
466 }
|
|
467 if (start is 0 && end is itemCount - 1) {
|
|
468 clearAll();
|
|
469 } else {
|
|
470 for (int i=start; i<=end; i++) {
|
|
471 TableItem item = items [i];
|
|
472 if (item !is null) item.clear();
|
|
473 }
|
|
474 }
|
|
475 }
|
|
476
|
|
477 /**
|
|
478 * Clears the items at the given zero-relative indices in the receiver.
|
|
479 * The text, icon and other attributes of the items are set to their default
|
|
480 * values. If the table was created with the <code>SWT.VIRTUAL</code> style,
|
|
481 * these attributes are requested again as needed.
|
|
482 *
|
|
483 * @param indices the array of indices of the items
|
|
484 *
|
|
485 * @exception IllegalArgumentException <ul>
|
|
486 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
487 * </ul>
|
|
488 * @exception SWTException <ul>
|
|
489 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
490 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
491 * </ul>
|
|
492 *
|
|
493 * @see SWT#VIRTUAL
|
|
494 * @see SWT#SetData
|
|
495 *
|
|
496 * @since 3.0
|
|
497 */
|
|
498 public void clear (int [] indices) {
|
|
499 checkWidget ();
|
|
500 // SWT extension: allow null for zero length string
|
|
501 //if (indices is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
502 if (indices.length is 0) return;
|
|
503 for (int i=0; i<indices.length; i++) {
|
|
504 if (!(0 <= indices [i] && indices [i] < itemCount)) {
|
|
505 error (SWT.ERROR_INVALID_RANGE);
|
|
506 }
|
|
507 }
|
|
508 for (int i=0; i<indices.length; i++) {
|
|
509 TableItem item = items [indices [i]];
|
|
510 if (item !is null) item.clear();
|
|
511 }
|
|
512 }
|
|
513
|
|
514 /**
|
|
515 * Clears all the items in the receiver. The text, icon and other
|
|
516 * attributes of the items are set to their default values. If the
|
|
517 * table was created with the <code>SWT.VIRTUAL</code> style, these
|
|
518 * attributes are requested again as needed.
|
|
519 *
|
|
520 * @exception SWTException <ul>
|
|
521 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
522 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
523 * </ul>
|
|
524 *
|
|
525 * @see SWT#VIRTUAL
|
|
526 * @see SWT#SetData
|
|
527 *
|
|
528 * @since 3.0
|
|
529 */
|
|
530 public void clearAll () {
|
|
531 checkWidget ();
|
|
532 for (int i=0; i<itemCount; i++) {
|
|
533 TableItem item = items [i];
|
|
534 if (item !is null) item.clear();
|
|
535 }
|
|
536 }
|
|
537
|
|
538 public override Point computeSize (int wHint, int hHint, bool changed) {
|
|
539 checkWidget ();
|
|
540 if (wHint !is SWT.DEFAULT && wHint < 0) wHint = 0;
|
|
541 if (hHint !is SWT.DEFAULT && hHint < 0) hHint = 0;
|
|
542 Point size = computeNativeSize (handle, wHint, hHint, changed);
|
|
543 Rectangle trim = computeTrim (0, 0, size.x, size.y);
|
|
544 size.x = trim.width;
|
|
545 size.y = trim.height;
|
|
546 return size;
|
|
547 }
|
|
548
|
|
549 void createColumn (TableColumn column, int index) {
|
|
550 int modelIndex = FIRST_COLUMN;
|
|
551 if (columnCount !is 0) {
|
|
552 int modelLength = OS.gtk_tree_model_get_n_columns (modelHandle);
|
|
553 bool [] usedColumns = new bool [modelLength];
|
|
554 for (int i=0; i<columnCount; i++) {
|
|
555 int columnIndex = columns [i].modelIndex;
|
|
556 for (int j = 0; j < CELL_TYPES; j++) {
|
|
557 usedColumns [columnIndex + j] = true;
|
|
558 }
|
|
559 }
|
|
560 while (modelIndex < modelLength) {
|
|
561 if (!usedColumns [modelIndex]) break;
|
|
562 modelIndex++;
|
|
563 }
|
|
564 if (modelIndex is modelLength) {
|
|
565 auto oldModel = modelHandle;
|
|
566 auto types = getColumnTypes (columnCount + 4); // grow by 4 rows at a time
|
|
567 auto newModel = OS.gtk_list_store_newv (types.length, types.ptr);
|
|
568 if (newModel is null) error (SWT.ERROR_NO_HANDLES);
|
|
569 void* ptr;
|
|
570 for (int i=0; i<itemCount; i++) {
|
|
571 GtkTreeIter* newItem = cast(GtkTreeIter*)OS.g_malloc( GtkTreeIter.sizeof );
|
|
572 if (newItem is null) error (SWT.ERROR_NO_HANDLES);
|
|
573 OS.gtk_list_store_append (newModel, newItem);
|
|
574 TableItem item = items [i];
|
|
575 if (item !is null) {
|
|
576 auto oldItem = item.handle;
|
|
577 for (int j=0; j<modelLength; j++) {
|
|
578 OS.gtk_tree_model_get1 (oldModel, oldItem, j, &ptr);
|
|
579 OS.gtk_list_store_set1 (newModel, newItem, j, ptr);
|
|
580 if (types [j] is OS.G_TYPE_STRING ()) OS.g_free ((ptr));
|
|
581 }
|
|
582 OS.gtk_list_store_remove (oldModel, oldItem);
|
|
583 OS.g_free (oldItem);
|
|
584 item.handle = cast(GtkWidget*)newItem;
|
|
585 } else {
|
|
586 OS.g_free (newItem);
|
|
587 }
|
|
588 }
|
|
589 OS.gtk_tree_view_set_model (handle, newModel);
|
|
590 OS.g_object_unref (oldModel);
|
|
591 modelHandle = cast(GtkWidget*)newModel;
|
|
592 }
|
|
593 }
|
|
594 auto columnHandle = OS.gtk_tree_view_column_new ();
|
|
595 if (columnHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
596 if (index is 0 && columnCount > 0) {
|
|
597 TableColumn checkColumn = columns [0];
|
|
598 createRenderers (cast(GtkTreeViewColumn*)checkColumn.handle, checkColumn.modelIndex, false, checkColumn.style);
|
|
599 }
|
|
600 createRenderers ( columnHandle, modelIndex, index is 0, column is null ? 0 : column.style);
|
|
601 /*
|
|
602 * Use GTK_TREE_VIEW_COLUMN_GROW_ONLY on GTK versions < 2.3.2
|
|
603 * because fixed_height_mode is not supported.
|
|
604 */
|
|
605 bool useVirtual = (style & SWT.VIRTUAL) !is 0 && OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2);
|
|
606 if (!useVirtual && columnCount is 0) {
|
|
607 OS.gtk_tree_view_column_set_sizing (columnHandle, OS.GTK_TREE_VIEW_COLUMN_GROW_ONLY);
|
|
608 } else {
|
|
609 OS.gtk_tree_view_column_set_sizing (columnHandle, OS.GTK_TREE_VIEW_COLUMN_FIXED);
|
|
610 if (columnCount !is 0) OS.gtk_tree_view_column_set_visible (columnHandle, false);
|
|
611 }
|
|
612 OS.gtk_tree_view_column_set_resizable (columnHandle, true);
|
|
613 OS.gtk_tree_view_column_set_clickable (columnHandle, true);
|
|
614 OS.gtk_tree_view_column_set_min_width (columnHandle, 0);
|
|
615 OS.gtk_tree_view_insert_column (handle, columnHandle, index);
|
|
616 if (column !is null) {
|
|
617 column.handle = cast(GtkWidget*)columnHandle;
|
|
618 column.modelIndex = modelIndex;
|
|
619 }
|
|
620 /* Disable searching when using VIRTUAL */
|
|
621 if ((style & SWT.VIRTUAL) !is 0) {
|
|
622 /*
|
|
623 * Bug in GTK. Until GTK 2.6.5, calling gtk_tree_view_set_enable_search(FALSE)
|
|
624 * would prevent the user from being able to type in text to search the tree.
|
|
625 * After 2.6.5, GTK introduced Ctrl+F as being the key binding for interactive
|
|
626 * search. This meant that even if FALSE was passed to enable_search, the user
|
|
627 * can still bring up the search pop up using the keybinding. GTK also introduced
|
|
628 * the notion of passing a -1 to gtk_set_search_column to disable searching
|
|
629 * (including the search key binding). The fix is to use the right calls
|
|
630 * for the right version.
|
|
631 */
|
|
632 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 5)) {
|
|
633 OS.gtk_tree_view_set_search_column (handle, -1);
|
|
634 } else {
|
|
635 OS.gtk_tree_view_set_enable_search (handle, false);
|
|
636 }
|
|
637 } else {
|
|
638 /* Set the search column whenever the model changes */
|
|
639 int firstColumn = columnCount is 0 ? FIRST_COLUMN : columns [0].modelIndex;
|
|
640 OS.gtk_tree_view_set_search_column (handle, firstColumn + CELL_TEXT);
|
|
641 }
|
|
642 }
|
|
643
|
|
644 override void createHandle (int index) {
|
|
645 state |= HANDLE;
|
|
646 fixedHandle = cast(GtkWidget*)OS.g_object_new (display.gtk_fixed_get_type (), null);
|
|
647 if (fixedHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
648 OS.gtk_fixed_set_has_window (fixedHandle, true);
|
|
649 scrolledHandle = cast(GtkWidget*)OS.gtk_scrolled_window_new (null, null);
|
|
650 if (scrolledHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
651 auto types = getColumnTypes (1);
|
|
652 modelHandle = cast(GtkWidget*)OS.gtk_list_store_newv (types.length, types.ptr);
|
|
653 if (modelHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
654 handle = cast(GtkWidget*)OS.gtk_tree_view_new_with_model (modelHandle);
|
|
655 if (handle is null) error (SWT.ERROR_NO_HANDLES);
|
|
656 if ((style & SWT.CHECK) !is 0) {
|
|
657 checkRenderer = cast(GtkWidget*)OS.gtk_cell_renderer_toggle_new ();
|
|
658 if (checkRenderer is null) error (SWT.ERROR_NO_HANDLES);
|
|
659 OS.g_object_ref (checkRenderer);
|
|
660 }
|
|
661 createColumn (null, 0);
|
|
662 OS.gtk_container_add (fixedHandle, scrolledHandle);
|
|
663 OS.gtk_container_add (scrolledHandle, handle);
|
|
664
|
|
665 int mode = (style & SWT.MULTI) !is 0 ? OS.GTK_SELECTION_MULTIPLE : OS.GTK_SELECTION_BROWSE;
|
|
666 auto selectionHandle = OS.gtk_tree_view_get_selection (handle);
|
|
667 OS.gtk_tree_selection_set_mode (selectionHandle, mode);
|
|
668 OS.gtk_tree_view_set_headers_visible (handle, false);
|
|
669 int hsp = (style & SWT.H_SCROLL) !is 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
|
|
670 int vsp = (style & SWT.V_SCROLL) !is 0 ? OS.GTK_POLICY_AUTOMATIC : OS.GTK_POLICY_NEVER;
|
|
671 OS.gtk_scrolled_window_set_policy (scrolledHandle, hsp, vsp);
|
|
672 if ((style & SWT.BORDER) !is 0) OS.gtk_scrolled_window_set_shadow_type (scrolledHandle, OS.GTK_SHADOW_ETCHED_IN);
|
|
673 /* Disable searching when using VIRTUAL */
|
|
674 if ((style & SWT.VIRTUAL) !is 0) {
|
|
675 /* The fixed_height_mode property only exists in GTK 2.3.2 and greater */
|
|
676 if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2)) {
|
|
677 OS.g_object_set1 (handle, OS.fixed_height_mode.ptr, true);
|
|
678 }
|
|
679 /*
|
|
680 * Bug in GTK. Until GTK 2.6.5, calling gtk_tree_view_set_enable_search(FALSE)
|
|
681 * would prevent the user from being able to type in text to search the tree.
|
|
682 * After 2.6.5, GTK introduced Ctrl+F as being the key binding for interactive
|
|
683 * search. This meant that even if FALSE was passed to enable_search, the user
|
|
684 * can still bring up the search pop up using the keybinding. GTK also introduced
|
|
685 * the notion of passing a -1 to gtk_set_search_column to disable searching
|
|
686 * (including the search key binding). The fix is to use the right calls
|
|
687 * for the right version.
|
|
688 */
|
|
689 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 5)) {
|
|
690 OS.gtk_tree_view_set_search_column (handle, -1);
|
|
691 } else {
|
|
692 OS.gtk_tree_view_set_enable_search (handle, false);
|
|
693 }
|
|
694 }
|
|
695 }
|
|
696
|
|
697 void createItem (TableColumn column, int index) {
|
|
698 if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
|
|
699 if (columnCount is 0) {
|
|
700 column.handle = cast(GtkWidget*)OS.gtk_tree_view_get_column (handle, 0);
|
|
701 OS.gtk_tree_view_column_set_sizing (column.handle, OS.GTK_TREE_VIEW_COLUMN_FIXED);
|
|
702 OS.gtk_tree_view_column_set_visible (column.handle, false);
|
|
703 column.modelIndex = FIRST_COLUMN;
|
|
704 createRenderers (cast(GtkTreeViewColumn*)column.handle, column.modelIndex, true, column.style);
|
|
705 column.customDraw = firstCustomDraw;
|
|
706 firstCustomDraw = false;
|
|
707 } else {
|
|
708 createColumn (column, index);
|
|
709 }
|
|
710 auto boxHandle = OS.gtk_hbox_new (false, 3);
|
|
711 if (boxHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
712 auto labelHandle = OS.gtk_label_new_with_mnemonic (null);
|
|
713 if (labelHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
714 auto imageHandle = OS.gtk_image_new ();
|
|
715 if (imageHandle is null) error (SWT.ERROR_NO_HANDLES);
|
|
716 OS.gtk_container_add (boxHandle, imageHandle);
|
|
717 OS.gtk_container_add (boxHandle, labelHandle);
|
|
718 OS.gtk_widget_show (boxHandle);
|
|
719 OS.gtk_widget_show (labelHandle);
|
|
720 column.labelHandle = labelHandle;
|
|
721 column.imageHandle = imageHandle;
|
|
722 OS.gtk_tree_view_column_set_widget (column.handle, boxHandle);
|
|
723 auto widget = OS.gtk_widget_get_parent (boxHandle);
|
|
724 while (widget !is handle) {
|
|
725 if (OS.GTK_IS_BUTTON (cast(GTypeInstance*)widget)) {
|
|
726 column.buttonHandle = widget;
|
|
727 break;
|
|
728 }
|
|
729 widget = OS.gtk_widget_get_parent (widget);
|
|
730 }
|
|
731 if (columnCount is columns.length) {
|
|
732 TableColumn [] newColumns = new TableColumn [columns.length + 4];
|
|
733 System.arraycopy (columns, 0, newColumns, 0, columns.length);
|
|
734 columns = newColumns;
|
|
735 }
|
|
736 System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
|
|
737 columns [index] = column;
|
|
738 if ((state & FONT) !is 0) {
|
|
739 column.setFontDescription (getFontDescription ());
|
|
740 }
|
|
741 if (columnCount >= 1) {
|
|
742 for (int i=0; i<itemCount; i++) {
|
|
743 TableItem item = items [i];
|
|
744 if (item !is null) {
|
|
745 Font [] cellFont = item.cellFont;
|
|
746 if (cellFont !is null) {
|
|
747 Font [] temp = new Font [columnCount];
|
|
748 System.arraycopy (cellFont, 0, temp, 0, index);
|
|
749 System.arraycopy (cellFont, index, temp, index+1, columnCount-index-1);
|
|
750 item.cellFont = temp;
|
|
751 }
|
|
752 }
|
|
753 }
|
|
754 }
|
|
755 }
|
|
756
|
|
757 void createItem (TableItem item, int index) {
|
|
758 if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
|
|
759 if (itemCount is items.length) {
|
|
760 int length = drawCount is 0 ? items.length + 4 : Math.max (4, items.length * 3 / 2);
|
|
761 TableItem [] newItems = new TableItem [length];
|
|
762 System.arraycopy (items, 0, newItems, 0, items.length);
|
|
763 items = newItems;
|
|
764 }
|
|
765 item.handle = cast(GtkWidget*) OS.g_malloc( GtkTreeIter.sizeof );
|
|
766 if (item.handle is null) error (SWT.ERROR_NO_HANDLES);
|
|
767 /*
|
|
768 * Feature in GTK. It is much faster to append to a list store
|
|
769 * than to insert at the end using gtk_list_store_insert().
|
|
770 */
|
|
771 if (index is itemCount) {
|
|
772 OS.gtk_list_store_append (modelHandle, item.handle);
|
|
773 } else {
|
|
774 OS.gtk_list_store_insert (modelHandle, item.handle, index);
|
|
775 }
|
|
776 System.arraycopy (items, index, items, index + 1, itemCount++ - index);
|
|
777 items [index] = item;
|
|
778 }
|
|
779
|
|
780 void createRenderers (GtkTreeViewColumn* columnHandle, int modelIndex, bool check, int columnStyle) {
|
|
781 OS.gtk_tree_view_column_clear (columnHandle);
|
|
782 if ((style & SWT.CHECK) !is 0 && check) {
|
|
783 OS.gtk_tree_view_column_pack_start (columnHandle, checkRenderer, false);
|
|
784 OS.gtk_tree_view_column_add_attribute (columnHandle, checkRenderer, OS.active.ptr, CHECKED_COLUMN);
|
|
785 /*
|
|
786 * Feature in GTK. The inconsistent property only exists in GTK 2.2.x.
|
|
787 */
|
|
788 if (OS.GTK_VERSION >= OS.buildVERSION (2, 2, 0)) {
|
|
789 OS.gtk_tree_view_column_add_attribute (columnHandle, checkRenderer, OS.inconsistent.ptr, GRAYED_COLUMN);
|
|
790 }
|
|
791 /*
|
|
792 * Bug in GTK. GTK renders the background on top of the checkbox.
|
|
793 * This only happens in version 2.2.1 and earlier. The fix is not to set the background.
|
|
794 */
|
|
795 if (OS.GTK_VERSION > OS.buildVERSION (2, 2, 1)) {
|
|
796 if (!ownerDraw) OS.gtk_tree_view_column_add_attribute (columnHandle, checkRenderer, OS.cell_background_gdk.ptr, BACKGROUND_COLUMN);
|
|
797 }
|
|
798 if (ownerDraw) {
|
|
799 display.doCellDataProc( handle, cast(GtkTreeViewColumn*)columnHandle, cast(GtkCellRenderer*)checkRenderer );
|
|
800 OS.g_object_set_qdata (cast(GObject*)checkRenderer, Display.SWT_OBJECT_INDEX1, columnHandle);
|
|
801 }
|
|
802 }
|
|
803 auto pixbufRenderer = ownerDraw ? cast(GtkCellRenderer*)OS.g_object_new (display.gtk_cell_renderer_pixbuf_get_type (), null) : OS.gtk_cell_renderer_pixbuf_new ();
|
|
804 if (pixbufRenderer is null) error (SWT.ERROR_NO_HANDLES);
|
|
805 auto textRenderer = ownerDraw ? cast(GtkCellRenderer*)OS.g_object_new (display.gtk_cell_renderer_text_get_type (), null) : OS.gtk_cell_renderer_text_new ();
|
|
806 if (textRenderer is null) error (SWT.ERROR_NO_HANDLES);
|
|
807
|
|
808 if (ownerDraw) {
|
|
809 OS.g_object_set_qdata (cast(GObject*)pixbufRenderer, Display.SWT_OBJECT_INDEX1, columnHandle);
|
|
810 OS.g_object_set_qdata (cast(GObject*)textRenderer, Display.SWT_OBJECT_INDEX1, columnHandle);
|
|
811 }
|
|
812
|
|
813 /*
|
|
814 * Feature in GTK. When a tree view column contains only one activatable
|
|
815 * cell renderer such as a toggle renderer, mouse clicks anywhere in a cell
|
|
816 * activate that renderer. The workaround is to set a second cell renderer
|
|
817 * to be activatable.
|
|
818 */
|
|
819 if ((style & SWT.CHECK) !is 0 && check) {
|
|
820 OS.g_object_set1 (pixbufRenderer, OS.mode.ptr, OS.GTK_CELL_RENDERER_MODE_ACTIVATABLE);
|
|
821 }
|
|
822
|
|
823 /* Set alignment */
|
|
824 if ((columnStyle & SWT.RIGHT) !is 0) {
|
|
825 OS.g_object_set1_float(textRenderer, OS.xalign.ptr, 1.0f );
|
|
826 OS.gtk_tree_view_column_pack_end (columnHandle, textRenderer, true);
|
|
827 OS.gtk_tree_view_column_pack_end (columnHandle, pixbufRenderer, false);
|
|
828 OS.gtk_tree_view_column_set_alignment (columnHandle, 1f);
|
|
829 } else if ((columnStyle & SWT.CENTER) !is 0) {
|
|
830 OS.g_object_set1_float(textRenderer, OS.xalign.ptr, 0.5f );
|
|
831 OS.gtk_tree_view_column_pack_start (columnHandle, pixbufRenderer, false);
|
|
832 OS.gtk_tree_view_column_pack_end (columnHandle, textRenderer, true);
|
|
833 OS.gtk_tree_view_column_set_alignment (columnHandle, 0.5f);
|
|
834 } else {
|
|
835 OS.gtk_tree_view_column_pack_start (columnHandle, pixbufRenderer, false);
|
|
836 OS.gtk_tree_view_column_pack_start (columnHandle, textRenderer, true);
|
|
837 OS.gtk_tree_view_column_set_alignment (columnHandle, 0f);
|
|
838 }
|
|
839
|
|
840 /* Add attributes */
|
|
841 OS.gtk_tree_view_column_add_attribute (columnHandle, pixbufRenderer, OS.pixbuf.ptr, modelIndex + CELL_PIXBUF);
|
|
842 /*
|
|
843 * Bug on GTK. Gtk renders the background on top of the pixbuf.
|
|
844 * This only happens in version 2.2.1 and earlier. The fix is not to set the background.
|
|
845 */
|
|
846 if (OS.GTK_VERSION > OS.buildVERSION (2, 2, 1)) {
|
|
847 if (!ownerDraw) {
|
|
848 OS.gtk_tree_view_column_add_attribute (columnHandle, pixbufRenderer, OS.cell_background_gdk.ptr, BACKGROUND_COLUMN);
|
|
849 OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, OS.cell_background_gdk.ptr, BACKGROUND_COLUMN);
|
|
850 }
|
|
851 }
|
|
852 OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, OS.text.ptr, modelIndex + CELL_TEXT);
|
|
853 OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, OS.foreground_gdk.ptr, FOREGROUND_COLUMN);
|
|
854 OS.gtk_tree_view_column_add_attribute (columnHandle, textRenderer, OS.font_desc.ptr, FONT_COLUMN);
|
|
855
|
|
856 bool customDraw = firstCustomDraw;
|
|
857 if (columnCount !is 0) {
|
|
858 for (int i=0; i<columnCount; i++) {
|
|
859 if (columns [i].handle is cast(GtkWidget*)columnHandle) {
|
|
860 customDraw = columns [i].customDraw;
|
|
861 break;
|
|
862 }
|
|
863 }
|
|
864 }
|
|
865 if ((style & SWT.VIRTUAL) !is 0 || customDraw || ownerDraw) {
|
|
866 display.doCellDataProc( handle, cast(GtkTreeViewColumn*)columnHandle, cast(GtkCellRenderer*)textRenderer );
|
|
867 display.doCellDataProc( handle, cast(GtkTreeViewColumn*)columnHandle, cast(GtkCellRenderer*)pixbufRenderer );
|
|
868 }
|
|
869 }
|
|
870
|
|
871 override void createWidget (int index) {
|
|
872 super.createWidget (index);
|
|
873 items = new TableItem [4];
|
|
874 columns = new TableColumn [4];
|
|
875 itemCount = columnCount = 0;
|
|
876 }
|
|
877
|
|
878 GdkColor* defaultBackground () {
|
|
879 return display.COLOR_LIST_BACKGROUND;
|
|
880 }
|
|
881
|
|
882 GdkColor* defaultForeground () {
|
|
883 return display.COLOR_LIST_FOREGROUND;
|
|
884 }
|
|
885
|
|
886 override void deregister () {
|
|
887 super.deregister ();
|
|
888 display.removeWidget ( cast(GtkWidget*)OS.gtk_tree_view_get_selection (handle));
|
|
889 if (checkRenderer !is null) display.removeWidget (checkRenderer);
|
|
890 }
|
|
891
|
|
892 /**
|
|
893 * Deselects the item at the given zero-relative index in the receiver.
|
|
894 * If the item at the index was already deselected, it remains
|
|
895 * deselected. Indices that are out of range are ignored.
|
|
896 *
|
|
897 * @param index the index of the item to deselect
|
|
898 *
|
|
899 * @exception SWTException <ul>
|
|
900 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
901 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
902 * </ul>
|
|
903 */
|
|
904 public void deselect (int index) {
|
|
905 checkWidget();
|
|
906 if (index < 0 || index >= itemCount) return;
|
|
907 bool fixColumn = showFirstColumn ();
|
|
908 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
909 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
910 OS.gtk_tree_selection_unselect_iter (selection, _getItem (index).handle);
|
|
911 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
912 if (fixColumn) hideFirstColumn ();
|
|
913 }
|
|
914
|
|
915 /**
|
|
916 * Deselects the items at the given zero-relative indices in the receiver.
|
|
917 * If the item at the given zero-relative index in the receiver
|
|
918 * is selected, it is deselected. If the item at the index
|
|
919 * was not selected, it remains deselected. The range of the
|
|
920 * indices is inclusive. Indices that are out of range are ignored.
|
|
921 *
|
|
922 * @param start the start index of the items to deselect
|
|
923 * @param end the end index of the items to deselect
|
|
924 *
|
|
925 * @exception SWTException <ul>
|
|
926 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
927 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
928 * </ul>
|
|
929 */
|
|
930 public void deselect (int start, int end) {
|
|
931 checkWidget();
|
|
932 bool fixColumn = showFirstColumn ();
|
|
933 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
934 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
935 for (int index=start; index<=end; index++) {
|
|
936 if (index < 0 || index >= itemCount) continue;
|
|
937 OS.gtk_tree_selection_unselect_iter (selection, _getItem (index).handle);
|
|
938 }
|
|
939 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
940 if (fixColumn) hideFirstColumn ();
|
|
941 }
|
|
942
|
|
943 /**
|
|
944 * Deselects the items at the given zero-relative indices in the receiver.
|
|
945 * If the item at the given zero-relative index in the receiver
|
|
946 * is selected, it is deselected. If the item at the index
|
|
947 * was not selected, it remains deselected. Indices that are out
|
|
948 * of range and duplicate indices are ignored.
|
|
949 *
|
|
950 * @param indices the array of indices for the items to deselect
|
|
951 *
|
|
952 * @exception SWTException <ul>
|
|
953 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
954 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
955 * </ul>
|
|
956 */
|
|
957 public void deselect (int [] indices) {
|
|
958 checkWidget();
|
|
959 // SWT extension: allow null for zero length string
|
|
960 //if (indices is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
961 bool fixColumn = showFirstColumn ();
|
|
962 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
963 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
964 for (int i=0; i<indices.length; i++) {
|
|
965 int index = indices[i];
|
|
966 if (index < 0 || index >= itemCount) continue;
|
|
967 OS.gtk_tree_selection_unselect_iter (selection, _getItem (index).handle);
|
|
968 }
|
|
969 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
970 if (fixColumn) hideFirstColumn ();
|
|
971 }
|
|
972
|
|
973 /**
|
|
974 * Deselects all selected items in the receiver.
|
|
975 *
|
|
976 * @exception SWTException <ul>
|
|
977 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
978 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
979 * </ul>
|
|
980 */
|
|
981 public void deselectAll () {
|
|
982 checkWidget();
|
|
983 bool fixColumn = showFirstColumn ();
|
|
984 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
985 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
986 OS.gtk_tree_selection_unselect_all (selection);
|
|
987 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
988 if (fixColumn) hideFirstColumn ();
|
|
989 }
|
|
990
|
|
991 void destroyItem (TableColumn column) {
|
|
992 int index = 0;
|
|
993 while (index < columnCount) {
|
|
994 if (columns [index] is column) break;
|
|
995 index++;
|
|
996 }
|
|
997 if (index is columnCount) return;
|
|
998 auto columnHandle = column.handle;
|
|
999 if (columnCount is 1) {
|
|
1000 firstCustomDraw = column.customDraw;
|
|
1001 }
|
|
1002 System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
|
|
1003 columns [columnCount] = null;
|
|
1004 OS.gtk_tree_view_remove_column (handle, columnHandle);
|
|
1005 if (columnCount is 0) {
|
|
1006 auto oldModel = modelHandle;
|
|
1007 auto types = getColumnTypes (1);
|
|
1008 auto newModel = OS.gtk_list_store_newv (types.length, types.ptr);
|
|
1009 if (newModel is null) error (SWT.ERROR_NO_HANDLES);
|
|
1010 void* ptr;
|
|
1011 for (int i=0; i<itemCount; i++) {
|
|
1012 GtkTreeIter* newItem = cast(GtkTreeIter*) OS.g_malloc( GtkTreeIter.sizeof );
|
|
1013 if (newItem is null) error (SWT.ERROR_NO_HANDLES);
|
|
1014 OS.gtk_list_store_append (newModel, newItem);
|
|
1015 TableItem item = items [i];
|
|
1016 if (item !is null) {
|
|
1017 auto oldItem = item.handle;
|
|
1018 for (int j=0; j<FIRST_COLUMN; j++) {
|
|
1019 OS.gtk_tree_model_get1 (oldModel, oldItem, j, &ptr);
|
|
1020 OS.gtk_list_store_set1 (newModel, newItem, j, ptr);
|
|
1021 }
|
|
1022 OS.gtk_tree_model_get1 (oldModel, oldItem, column.modelIndex + CELL_PIXBUF, &ptr);
|
|
1023 OS.gtk_list_store_set1 (newModel, newItem, FIRST_COLUMN + CELL_PIXBUF, ptr);
|
|
1024 OS.gtk_tree_model_get1 (oldModel, oldItem, column.modelIndex + CELL_TEXT, &ptr);
|
|
1025 OS.gtk_list_store_set1 (newModel, newItem, FIRST_COLUMN + CELL_TEXT, ptr );
|
|
1026 OS.g_free (ptr);
|
|
1027 OS.gtk_tree_model_get1 (oldModel, oldItem, column.modelIndex + CELL_FOREGROUND, &ptr);
|
|
1028 OS.gtk_list_store_set1 (newModel, newItem, FIRST_COLUMN + CELL_FOREGROUND, ptr);
|
|
1029 OS.gtk_tree_model_get1 (oldModel, oldItem, column.modelIndex + CELL_BACKGROUND, &ptr);
|
|
1030 OS.gtk_list_store_set1 (newModel, newItem, FIRST_COLUMN + CELL_BACKGROUND, ptr);
|
|
1031 OS.gtk_tree_model_get1 (oldModel, oldItem, column.modelIndex + CELL_FONT, &ptr);
|
|
1032 OS.gtk_list_store_set1 (newModel, newItem, FIRST_COLUMN + CELL_FONT, ptr);
|
|
1033 OS.gtk_list_store_remove (oldModel, oldItem);
|
|
1034 OS.g_free (oldItem);
|
|
1035 item.handle = cast(GtkWidget*) newItem;
|
|
1036 } else {
|
|
1037 OS.g_free( newItem );
|
|
1038 }
|
|
1039 }
|
|
1040 OS.gtk_tree_view_set_model (handle, newModel);
|
|
1041 OS.g_object_unref (oldModel);
|
|
1042 modelHandle = cast(GtkWidget*)newModel;
|
|
1043 createColumn (null, 0);
|
|
1044 } else {
|
|
1045 for (int i=0; i<itemCount; i++) {
|
|
1046 TableItem item = items [i];
|
|
1047 if (item !is null) {
|
|
1048 auto iter = item.handle;
|
|
1049 int modelIndex = column.modelIndex;
|
|
1050 OS.gtk_list_store_set1 (modelHandle, iter, modelIndex + CELL_PIXBUF, null);
|
|
1051 OS.gtk_list_store_set1 (modelHandle, iter, modelIndex + CELL_TEXT, null);
|
|
1052 OS.gtk_list_store_set1 (modelHandle, iter, modelIndex + CELL_FOREGROUND, null);
|
|
1053 OS.gtk_list_store_set1 (modelHandle, iter, modelIndex + CELL_BACKGROUND, null);
|
|
1054 OS.gtk_list_store_set1 (modelHandle, iter, modelIndex + CELL_FONT, null);
|
|
1055
|
|
1056 Font [] cellFont = item.cellFont;
|
|
1057 if (cellFont !is null) {
|
|
1058 if (columnCount is 0) {
|
|
1059 item.cellFont = null;
|
|
1060 } else {
|
|
1061 Font [] temp = new Font [columnCount];
|
|
1062 System.arraycopy (cellFont, 0, temp, 0, index);
|
|
1063 System.arraycopy (cellFont, index + 1, temp, index, columnCount - index);
|
|
1064 item.cellFont = temp;
|
|
1065 }
|
|
1066 }
|
|
1067 }
|
|
1068 }
|
|
1069 if (index is 0) {
|
|
1070 TableColumn checkColumn = columns [0];
|
|
1071 createRenderers (cast(GtkTreeViewColumn*)checkColumn.handle, checkColumn.modelIndex, true, checkColumn.style);
|
|
1072 }
|
|
1073 }
|
|
1074 /* Disable searching when using VIRTUAL */
|
|
1075 if ((style & SWT.VIRTUAL) !is 0) {
|
|
1076 /*
|
|
1077 * Bug in GTK. Until GTK 2.6.5, calling gtk_tree_view_set_enable_search(FALSE)
|
|
1078 * would prevent the user from being able to type in text to search the tree.
|
|
1079 * After 2.6.5, GTK introduced Ctrl+F as being the key binding for interactive
|
|
1080 * search. This meant that even if FALSE was passed to enable_search, the user
|
|
1081 * can still bring up the search pop up using the keybinding. GTK also introduced
|
|
1082 * the notion of passing a -1 to gtk_set_search_column to disable searching
|
|
1083 * (including the search key binding). The fix is to use the right calls
|
|
1084 * for the right version.
|
|
1085 */
|
|
1086 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 5)) {
|
|
1087 OS.gtk_tree_view_set_search_column (handle, -1);
|
|
1088 } else {
|
|
1089 OS.gtk_tree_view_set_enable_search (handle, false);
|
|
1090 }
|
|
1091 } else {
|
|
1092 /* Set the search column whenever the model changes */
|
|
1093 int firstColumn = columnCount is 0 ? FIRST_COLUMN : columns [0].modelIndex;
|
|
1094 OS.gtk_tree_view_set_search_column (handle, firstColumn + CELL_TEXT);
|
|
1095 }
|
|
1096 }
|
|
1097
|
|
1098 void destroyItem (TableItem item) {
|
|
1099 int index = 0;
|
|
1100 while (index < itemCount) {
|
|
1101 if (items [index] is item) break;
|
|
1102 index++;
|
|
1103 }
|
|
1104 if (index is itemCount) return;
|
|
1105 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1106 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1107 OS.gtk_list_store_remove (modelHandle, item.handle);
|
|
1108 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1109 System.arraycopy (items, index + 1, items, index, --itemCount - index);
|
|
1110 items [itemCount] = null;
|
|
1111 if (itemCount is 0) resetCustomDraw ();
|
|
1112 }
|
|
1113
|
|
1114 override bool dragDetect (int x, int y, bool filter, bool* consume) {
|
|
1115 bool selected = false;
|
|
1116 if (filter) {
|
|
1117 GtkTreeViewColumn * path;
|
|
1118 if (OS.gtk_tree_view_get_path_at_pos (handle, x, y, cast(void**)&path, null, null, null)) {
|
|
1119 if (path !is null) {
|
|
1120 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1121 if (OS.gtk_tree_selection_path_is_selected (selection, path)) selected = true;
|
|
1122 OS.gtk_tree_path_free (path);
|
|
1123 }
|
|
1124 } else {
|
|
1125 return false;
|
|
1126 }
|
|
1127 }
|
|
1128 bool dragDetect = super.dragDetect (x, y, filter, consume);
|
|
1129 if (dragDetect && selected && consume !is null) consume[0] = true;
|
|
1130 return dragDetect;
|
|
1131 }
|
|
1132
|
|
1133 override GdkDrawable* eventWindow () {
|
|
1134 return paintWindow ();
|
|
1135 }
|
|
1136
|
|
1137 override void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) {
|
|
1138 super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus);
|
|
1139 for (int i=0; i<columnCount; i++) {
|
|
1140 TableColumn column = columns [i];
|
|
1141 if (column.toolTipText !is null) {
|
|
1142 column.setToolTipText(oldShell, null);
|
|
1143 column.setToolTipText(newShell, column.toolTipText);
|
|
1144 }
|
|
1145 }
|
|
1146 }
|
|
1147
|
|
1148 override GdkColor* getBackgroundColor () {
|
|
1149 return getBaseColor ();
|
|
1150 }
|
|
1151
|
|
1152 public override Rectangle getClientArea () {
|
|
1153 checkWidget ();
|
|
1154 forceResize ();
|
|
1155 OS.gtk_widget_realize (handle);
|
|
1156 auto fixedWindow = OS.GTK_WIDGET_WINDOW (fixedHandle);
|
|
1157 auto binWindow = OS.gtk_tree_view_get_bin_window (handle);
|
|
1158 int binX, binY;
|
|
1159 OS.gdk_window_get_origin (binWindow, &binX, &binY);
|
|
1160 int fixedX, fixedY;
|
|
1161 OS.gdk_window_get_origin (fixedWindow, &fixedX, &fixedY);
|
|
1162 auto clientHandle = clientHandle ();
|
|
1163 int width = (state & ZERO_WIDTH) !is 0 ? 0 : OS.GTK_WIDGET_WIDTH (clientHandle);
|
|
1164 int height = (state & ZERO_HEIGHT) !is 0 ? 0 : OS.GTK_WIDGET_HEIGHT (clientHandle);
|
|
1165 return new Rectangle (fixedX - binX, fixedY - binY, width, height);
|
|
1166 }
|
|
1167
|
|
1168 int getClientWidth () {
|
|
1169 int w, h;
|
|
1170 OS.gtk_widget_realize (handle);
|
|
1171 OS.gdk_drawable_get_size(OS.gtk_tree_view_get_bin_window(handle), &w, &h);
|
|
1172 return w;
|
|
1173 }
|
|
1174
|
|
1175 /**
|
|
1176 * Returns the column at the given, zero-relative index in the
|
|
1177 * receiver. Throws an exception if the index is out of range.
|
|
1178 * Columns are returned in the order that they were created.
|
|
1179 * If no <code>TableColumn</code>s were created by the programmer,
|
|
1180 * this method will throw <code>ERROR_INVALID_RANGE</code> despite
|
|
1181 * the fact that a single column of data may be visible in the table.
|
|
1182 * This occurs when the programmer uses the table like a list, adding
|
|
1183 * items but never creating a column.
|
|
1184 *
|
|
1185 * @param index the index of the column to return
|
|
1186 * @return the column at the given index
|
|
1187 *
|
|
1188 * @exception IllegalArgumentException <ul>
|
|
1189 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
1190 * </ul>
|
|
1191 * @exception SWTException <ul>
|
|
1192 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1193 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1194 * </ul>
|
|
1195 *
|
|
1196 * @see Table#getColumnOrder()
|
|
1197 * @see Table#setColumnOrder(int[])
|
|
1198 * @see TableColumn#getMoveable()
|
|
1199 * @see TableColumn#setMoveable(bool)
|
|
1200 * @see SWT#Move
|
|
1201 */
|
|
1202 public TableColumn getColumn (int index) {
|
|
1203 checkWidget();
|
|
1204 if (!(0 <= index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
|
|
1205 return columns [index];
|
|
1206 }
|
|
1207
|
|
1208 /**
|
|
1209 * Returns the number of columns contained in the receiver.
|
|
1210 * If no <code>TableColumn</code>s were created by the programmer,
|
|
1211 * this value is zero, despite the fact that visually, one column
|
|
1212 * of items may be visible. This occurs when the programmer uses
|
|
1213 * the table like a list, adding items but never creating a column.
|
|
1214 *
|
|
1215 * @return the number of columns
|
|
1216 *
|
|
1217 * @exception SWTException <ul>
|
|
1218 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1219 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1220 * </ul>
|
|
1221 */
|
|
1222 public int getColumnCount () {
|
|
1223 checkWidget();
|
|
1224 return columnCount;
|
|
1225 }
|
|
1226
|
|
1227 uint[] getColumnTypes (int columnCount) {
|
|
1228 uint[] types = new uint [FIRST_COLUMN + (columnCount * CELL_TYPES)];
|
|
1229 // per row data
|
|
1230 types [CHECKED_COLUMN] = OS.G_TYPE_BOOLEAN ();
|
|
1231 types [GRAYED_COLUMN] = OS.G_TYPE_BOOLEAN ();
|
|
1232 types [FOREGROUND_COLUMN] = OS.GDK_TYPE_COLOR ();
|
|
1233 types [BACKGROUND_COLUMN] = OS.GDK_TYPE_COLOR ();
|
|
1234 types [FONT_COLUMN] = OS.PANGO_TYPE_FONT_DESCRIPTION ();
|
|
1235 // per cell data
|
|
1236 for (int i=FIRST_COLUMN; i<types.length; i+=CELL_TYPES) {
|
|
1237 types [i + CELL_PIXBUF] = OS.GDK_TYPE_PIXBUF ();
|
|
1238 types [i + CELL_TEXT] = OS.G_TYPE_STRING ();
|
|
1239 types [i + CELL_FOREGROUND] = OS.GDK_TYPE_COLOR ();
|
|
1240 types [i + CELL_BACKGROUND] = OS.GDK_TYPE_COLOR ();
|
|
1241 types [i + CELL_FONT] = OS.PANGO_TYPE_FONT_DESCRIPTION ();
|
|
1242 }
|
|
1243 return types;
|
|
1244 }
|
|
1245
|
|
1246 /**
|
|
1247 * Returns an array of zero-relative integers that map
|
|
1248 * the creation order of the receiver's items to the
|
|
1249 * order in which they are currently being displayed.
|
|
1250 * <p>
|
|
1251 * Specifically, the indices of the returned array represent
|
|
1252 * the current visual order of the items, and the contents
|
|
1253 * of the array represent the creation order of the items.
|
|
1254 * </p><p>
|
|
1255 * Note: This is not the actual structure used by the receiver
|
|
1256 * to maintain its list of items, so modifying the array will
|
|
1257 * not affect the receiver.
|
|
1258 * </p>
|
|
1259 *
|
|
1260 * @return the current visual order of the receiver's items
|
|
1261 *
|
|
1262 * @exception SWTException <ul>
|
|
1263 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1264 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1265 * </ul>
|
|
1266 *
|
|
1267 * @see Table#setColumnOrder(int[])
|
|
1268 * @see TableColumn#getMoveable()
|
|
1269 * @see TableColumn#setMoveable(bool)
|
|
1270 * @see SWT#Move
|
|
1271 *
|
|
1272 * @since 3.1
|
|
1273 */
|
|
1274 public int [] getColumnOrder () {
|
|
1275 checkWidget ();
|
|
1276 if (columnCount is 0) return new int [0];
|
|
1277 auto list = OS.gtk_tree_view_get_columns (handle);
|
|
1278 if (list is null) return new int [0];
|
|
1279 int i = 0, count = OS.g_list_length (list);
|
|
1280 int [] order = new int [count];
|
|
1281 auto temp = list;
|
|
1282 while (temp !is null) {
|
|
1283 auto column = OS.g_list_data (temp);
|
|
1284 if (column !is null) {
|
|
1285 for (int j=0; j<columnCount; j++) {
|
|
1286 if (columns [j].handle is column) {
|
|
1287 order [i++] = j;
|
|
1288 break;
|
|
1289 }
|
|
1290 }
|
|
1291 }
|
|
1292 temp = OS.g_list_next (temp);
|
|
1293 }
|
|
1294 OS.g_list_free (list);
|
|
1295 return order;
|
|
1296 }
|
|
1297
|
|
1298 /**
|
|
1299 * Returns an array of <code>TableColumn</code>s which are the
|
|
1300 * columns in the receiver. Columns are returned in the order
|
|
1301 * that they were created. If no <code>TableColumn</code>s were
|
|
1302 * created by the programmer, the array is empty, despite the fact
|
|
1303 * that visually, one column of items may be visible. This occurs
|
|
1304 * when the programmer uses the table like a list, adding items but
|
|
1305 * never creating a column.
|
|
1306 * <p>
|
|
1307 * Note: This is not the actual structure used by the receiver
|
|
1308 * to maintain its list of items, so modifying the array will
|
|
1309 * not affect the receiver.
|
|
1310 * </p>
|
|
1311 *
|
|
1312 * @return the items in the receiver
|
|
1313 *
|
|
1314 * @exception SWTException <ul>
|
|
1315 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1316 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1317 * </ul>
|
|
1318 *
|
|
1319 * @see Table#getColumnOrder()
|
|
1320 * @see Table#setColumnOrder(int[])
|
|
1321 * @see TableColumn#getMoveable()
|
|
1322 * @see TableColumn#setMoveable(bool)
|
|
1323 * @see SWT#Move
|
|
1324 */
|
|
1325 public TableColumn [] getColumns () {
|
|
1326 checkWidget();
|
|
1327 TableColumn [] result = new TableColumn [columnCount];
|
|
1328 System.arraycopy (columns, 0, result, 0, columnCount);
|
|
1329 return result;
|
|
1330 }
|
|
1331
|
|
1332 TableItem getFocusItem () {
|
|
1333 GtkTreeViewColumn * path;
|
|
1334 OS.gtk_tree_view_get_cursor (handle, cast(void**)&path, null);
|
|
1335 if (path is null) return null;
|
|
1336 TableItem item = null;
|
|
1337 auto indices = OS.gtk_tree_path_get_indices (path);
|
|
1338 if (indices !is null) {
|
|
1339 item = _getItem (indices [0]);
|
|
1340 }
|
|
1341 OS.gtk_tree_path_free (path);
|
|
1342 return item;
|
|
1343 }
|
|
1344
|
|
1345 override GdkColor* getForegroundColor () {
|
|
1346 return getTextColor ();
|
|
1347 }
|
|
1348
|
|
1349 /**
|
|
1350 * Returns the width in pixels of a grid line.
|
|
1351 *
|
|
1352 * @return the width of a grid line in pixels
|
|
1353 *
|
|
1354 * @exception SWTException <ul>
|
|
1355 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1356 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1357 * </ul>
|
|
1358 */
|
|
1359 public int getGridLineWidth () {
|
|
1360 checkWidget();
|
|
1361 return 0;
|
|
1362 }
|
|
1363
|
|
1364 /**
|
|
1365 * Returns the height of the receiver's header
|
|
1366 *
|
|
1367 * @return the height of the header or zero if the header is not visible
|
|
1368 *
|
|
1369 * @exception SWTException <ul>
|
|
1370 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1371 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1372 * </ul>
|
|
1373 *
|
|
1374 * @since 2.0
|
|
1375 */
|
|
1376 public int getHeaderHeight () {
|
|
1377 checkWidget ();
|
|
1378 if (!OS.gtk_tree_view_get_headers_visible (handle)) return 0;
|
|
1379 if (columnCount > 0) {
|
|
1380 GtkRequisition requisition;
|
|
1381 int height = 0;
|
|
1382 for (int i=0; i<columnCount; i++) {
|
|
1383 auto buttonHandle = columns [i].buttonHandle;
|
|
1384 if (buttonHandle !is null) {
|
|
1385 OS.gtk_widget_size_request (buttonHandle, &requisition);
|
|
1386 height = Math.max (height, requisition.height);
|
|
1387 }
|
|
1388 }
|
|
1389 return height;
|
|
1390 }
|
|
1391 OS.gtk_widget_realize (handle);
|
|
1392 auto fixedWindow = OS.GTK_WIDGET_WINDOW (fixedHandle);
|
|
1393 auto binWindow = OS.gtk_tree_view_get_bin_window (handle);
|
|
1394 int binY;
|
|
1395 OS.gdk_window_get_origin (binWindow, null, &binY);
|
|
1396 int fixedY;
|
|
1397 OS.gdk_window_get_origin (fixedWindow, null, &fixedY);
|
|
1398 return binY - fixedY;
|
|
1399 }
|
|
1400
|
|
1401 /**
|
|
1402 * Returns <code>true</code> if the receiver's header is visible,
|
|
1403 * and <code>false</code> otherwise.
|
|
1404 * <p>
|
|
1405 * If one of the receiver's ancestors is not visible or some
|
|
1406 * other condition makes the receiver not visible, this method
|
|
1407 * may still indicate that it is considered visible even though
|
|
1408 * it may not actually be showing.
|
|
1409 * </p>
|
|
1410 *
|
|
1411 * @return the receiver's header's visibility state
|
|
1412 *
|
|
1413 * @exception SWTException <ul>
|
|
1414 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1415 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1416 * </ul>
|
|
1417 */
|
|
1418 public bool getHeaderVisible () {
|
|
1419 checkWidget();
|
|
1420 return cast(bool) OS.gtk_tree_view_get_headers_visible (handle);
|
|
1421 }
|
|
1422
|
|
1423 /**
|
|
1424 * Returns the item at the given, zero-relative index in the
|
|
1425 * receiver. Throws an exception if the index is out of range.
|
|
1426 *
|
|
1427 * @param index the index of the item to return
|
|
1428 * @return the item at the given index
|
|
1429 *
|
|
1430 * @exception IllegalArgumentException <ul>
|
|
1431 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
1432 * </ul>
|
|
1433 * @exception SWTException <ul>
|
|
1434 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1435 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1436 * </ul>
|
|
1437 */
|
|
1438 public TableItem getItem (int index) {
|
|
1439 checkWidget();
|
|
1440 if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
|
|
1441 return _getItem (index);
|
|
1442 }
|
|
1443
|
|
1444 /**
|
|
1445 * Returns the item at the given point in the receiver
|
|
1446 * or null if no such item exists. The point is in the
|
|
1447 * coordinate system of the receiver.
|
|
1448 * <p>
|
|
1449 * The item that is returned represents an item that could be selected by the user.
|
|
1450 * For example, if selection only occurs in items in the first column, then null is
|
|
1451 * returned if the point is outside of the item.
|
|
1452 * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
|
|
1453 * determines the extent of the selection.
|
|
1454 * </p>
|
|
1455 *
|
|
1456 * @param point the point used to locate the item
|
|
1457 * @return the item at the given point, or null if the point is not in a selectable item
|
|
1458 *
|
|
1459 * @exception IllegalArgumentException <ul>
|
|
1460 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
|
|
1461 * </ul>
|
|
1462 * @exception SWTException <ul>
|
|
1463 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1464 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1465 * </ul>
|
|
1466 */
|
|
1467 public TableItem getItem (Point point) {
|
|
1468 checkWidget();
|
|
1469 if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
1470 void* path;
|
|
1471 OS.gtk_widget_realize (handle);
|
|
1472 if (!OS.gtk_tree_view_get_path_at_pos (handle, point.x, point.y, &path, null, null, null)) return null;
|
|
1473 if (path is null) return null;
|
|
1474 auto indices = OS.gtk_tree_path_get_indices (path );
|
|
1475 TableItem item = null;
|
|
1476 if (indices !is null) {
|
|
1477 item = _getItem (indices [0]);
|
|
1478 }
|
|
1479 OS.gtk_tree_path_free (path );
|
|
1480 return item;
|
|
1481 }
|
|
1482
|
|
1483 /**
|
|
1484 * Returns the number of items contained in the receiver.
|
|
1485 *
|
|
1486 * @return the number of items
|
|
1487 *
|
|
1488 * @exception SWTException <ul>
|
|
1489 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1490 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1491 * </ul>
|
|
1492 */
|
|
1493 public int getItemCount () {
|
|
1494 checkWidget ();
|
|
1495 return itemCount;
|
|
1496 }
|
|
1497
|
|
1498 /**
|
|
1499 * Returns the height of the area which would be used to
|
|
1500 * display <em>one</em> of the items in the receiver.
|
|
1501 *
|
|
1502 * @return the height of one item
|
|
1503 *
|
|
1504 * @exception SWTException <ul>
|
|
1505 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1506 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1507 * </ul>
|
|
1508 */
|
|
1509 public int getItemHeight () {
|
|
1510 checkWidget();
|
|
1511 if (itemCount is 0) {
|
|
1512 auto column = OS.gtk_tree_view_get_column (handle, 0);
|
|
1513 int w, h;
|
|
1514 ignoreSize = true;
|
|
1515 OS.gtk_tree_view_column_cell_get_size (column, null, null, null, &w, &h);
|
|
1516 ignoreSize = false;
|
|
1517 return h;
|
|
1518 } else {
|
|
1519 int height = 0;
|
|
1520 GtkTreeIter* iter = cast(GtkTreeIter*) OS.g_malloc( GtkTreeIter.sizeof );
|
|
1521 OS.gtk_tree_model_get_iter_first (modelHandle, iter);
|
|
1522 int columnCount = Math.max (1, this.columnCount);
|
|
1523 for (int i=0; i<columnCount; i++) {
|
|
1524 auto column = OS.gtk_tree_view_get_column (handle, i);
|
|
1525 OS.gtk_tree_view_column_cell_set_cell_data (column, modelHandle, iter, false, false);
|
|
1526 int w, h;
|
|
1527 OS.gtk_tree_view_column_cell_get_size (column, null, null, null, &w, &h);
|
|
1528 height = Math.max (height, h );
|
|
1529 }
|
|
1530 OS.g_free(iter);
|
|
1531 return height;
|
|
1532 }
|
|
1533 }
|
|
1534
|
|
1535 /**
|
|
1536 * Returns a (possibly empty) array of <code>TableItem</code>s which
|
|
1537 * are the items in the receiver.
|
|
1538 * <p>
|
|
1539 * Note: This is not the actual structure used by the receiver
|
|
1540 * to maintain its list of items, so modifying the array will
|
|
1541 * not affect the receiver.
|
|
1542 * </p>
|
|
1543 *
|
|
1544 * @return the items in the receiver
|
|
1545 *
|
|
1546 * @exception SWTException <ul>
|
|
1547 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1548 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1549 * </ul>
|
|
1550 */
|
|
1551 public TableItem [] getItems () {
|
|
1552 checkWidget();
|
|
1553 TableItem [] result = new TableItem [itemCount];
|
|
1554 if ((style & SWT.VIRTUAL) !is 0) {
|
|
1555 for (int i=0; i<itemCount; i++) {
|
|
1556 result [i] = _getItem (i);
|
|
1557 }
|
|
1558 } else {
|
|
1559 System.arraycopy (items, 0, result, 0, itemCount);
|
|
1560 }
|
|
1561 return result;
|
|
1562 }
|
|
1563
|
|
1564 /**
|
|
1565 * Returns <code>true</code> if the receiver's lines are visible,
|
|
1566 * and <code>false</code> otherwise.
|
|
1567 * <p>
|
|
1568 * If one of the receiver's ancestors is not visible or some
|
|
1569 * other condition makes the receiver not visible, this method
|
|
1570 * may still indicate that it is considered visible even though
|
|
1571 * it may not actually be showing.
|
|
1572 * </p>
|
|
1573 *
|
|
1574 * @return the visibility state of the lines
|
|
1575 *
|
|
1576 * @exception SWTException <ul>
|
|
1577 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1578 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1579 * </ul>
|
|
1580 */
|
|
1581 public bool getLinesVisible() {
|
|
1582 checkWidget();
|
|
1583 return cast(bool)OS.gtk_tree_view_get_rules_hint (handle);
|
|
1584 }
|
|
1585
|
|
1586 GtkCellRendererPixbuf* getPixbufRenderer (GtkTreeViewColumn* column) {
|
|
1587 auto list = OS.gtk_tree_view_column_get_cell_renderers (column);
|
|
1588 if (list is null) return null;
|
|
1589 int count = OS.g_list_length (list);
|
|
1590 GtkCellRendererPixbuf* pixbufRenderer;
|
|
1591 int i = 0;
|
|
1592 while (i < count) {
|
|
1593 auto renderer = OS.g_list_nth_data (list, i);
|
|
1594 if (OS.GTK_IS_CELL_RENDERER_PIXBUF (cast(GTypeInstance*)renderer)) {
|
|
1595 pixbufRenderer = cast(GtkCellRendererPixbuf*)renderer;
|
|
1596 break;
|
|
1597 }
|
|
1598 i++;
|
|
1599 }
|
|
1600 OS.g_list_free (list);
|
|
1601 return pixbufRenderer;
|
|
1602 }
|
|
1603
|
|
1604 /**
|
|
1605 * Returns an array of <code>TableItem</code>s that are currently
|
|
1606 * selected in the receiver. The order of the items is unspecified.
|
|
1607 * An empty array indicates that no items are selected.
|
|
1608 * <p>
|
|
1609 * Note: This is not the actual structure used by the receiver
|
|
1610 * to maintain its selection, so modifying the array will
|
|
1611 * not affect the receiver.
|
|
1612 * </p>
|
|
1613 * @return an array representing the selection
|
|
1614 *
|
|
1615 * @exception SWTException <ul>
|
|
1616 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1617 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1618 * </ul>
|
|
1619 */
|
|
1620 public TableItem [] getSelection () {
|
|
1621 checkWidget();
|
|
1622 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1623 if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) {
|
|
1624 display.treeSelectionLength = 0;
|
|
1625 display.treeSelection = new int [itemCount];
|
|
1626 display.doTreeSelectionProcConnect( &treeSelectionCallbackData, handle, selection );
|
|
1627 TableItem [] result = new TableItem [display.treeSelectionLength];
|
|
1628 for (int i=0; i<result.length; i++) result [i] = _getItem (display.treeSelection [i]);
|
|
1629 return result;
|
|
1630 }
|
|
1631 /*
|
|
1632 * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults
|
|
1633 * in versions smaller than 2.2.4 if the model is NULL. The fix is
|
|
1634 * to give a valid pointer instead.
|
|
1635 */
|
|
1636 int dummy;
|
|
1637 void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
|
|
1638 auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
|
|
1639 if (list !is null) {
|
|
1640 int count = OS.g_list_length (list);
|
|
1641 int [] treeSelection = new int [count];
|
|
1642 int length_ = 0;
|
|
1643 for (int i=0; i<count; i++) {
|
|
1644 auto data = OS.g_list_nth_data (list, i);
|
|
1645 auto indices = OS.gtk_tree_path_get_indices (data);
|
|
1646 if (indices !is null) {
|
|
1647 treeSelection [length_] = indices [0];
|
|
1648 length_++;
|
|
1649 }
|
|
1650 }
|
|
1651 OS.g_list_free (list);
|
|
1652 TableItem [] result = new TableItem [length_];
|
|
1653 for (int i=0; i<result.length; i++) result [i] = _getItem (treeSelection [i]);
|
|
1654 return result;
|
|
1655 }
|
|
1656 return null;
|
|
1657 }
|
|
1658
|
|
1659 /**
|
|
1660 * Returns the number of selected items contained in the receiver.
|
|
1661 *
|
|
1662 * @return the number of selected items
|
|
1663 *
|
|
1664 * @exception SWTException <ul>
|
|
1665 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1666 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1667 * </ul>
|
|
1668 */
|
|
1669 public int getSelectionCount () {
|
|
1670 checkWidget();
|
|
1671 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1672 if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) {
|
|
1673 display.treeSelectionLength = 0;
|
|
1674 display.treeSelection = null;
|
|
1675 display.doTreeSelectionProcConnect( &treeSelectionCallbackData, handle, selection );
|
|
1676 return display.treeSelectionLength;
|
|
1677 }
|
|
1678 return OS.gtk_tree_selection_count_selected_rows (selection);
|
|
1679 }
|
|
1680
|
|
1681 /**
|
|
1682 * Returns the zero-relative index of the item which is currently
|
|
1683 * selected in the receiver, or -1 if no item is selected.
|
|
1684 *
|
|
1685 * @return the index of the selected item
|
|
1686 *
|
|
1687 * @exception SWTException <ul>
|
|
1688 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1689 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1690 * </ul>
|
|
1691 */
|
|
1692 public int getSelectionIndex () {
|
|
1693 checkWidget();
|
|
1694 if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) {
|
|
1695 display.treeSelectionLength = 0;
|
|
1696 display.treeSelection = new int [itemCount];
|
|
1697 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1698 display.doTreeSelectionProcConnect( &treeSelectionCallbackData, handle, selection );
|
|
1699 if (display.treeSelectionLength is 0) return -1;
|
|
1700 return display.treeSelection [0];
|
|
1701 }
|
|
1702 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1703 /*
|
|
1704 * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults
|
|
1705 * in versions smaller than 2.2.4 if the model is NULL. The fix is
|
|
1706 * to give a valid pointer instead.
|
|
1707 */
|
|
1708 int dummy;
|
|
1709 void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
|
|
1710 auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
|
|
1711 if (list !is null) {
|
|
1712 int count = OS.g_list_length (list);
|
|
1713 int index;
|
|
1714 for (int i=0; i<count; i++) {
|
|
1715 auto data = OS.g_list_nth_data (list, i);
|
|
1716 auto indices = OS.gtk_tree_path_get_indices (data);
|
|
1717 if (indices !is null) {
|
|
1718 index = indices[0];
|
|
1719 break;
|
|
1720 }
|
|
1721 }
|
|
1722 OS.g_list_free (list);
|
|
1723 return index;
|
|
1724 }
|
|
1725 return -1;
|
|
1726 }
|
|
1727
|
|
1728 /**
|
|
1729 * Returns the zero-relative indices of the items which are currently
|
|
1730 * selected in the receiver. The order of the indices is unspecified.
|
|
1731 * The array is empty if no items are selected.
|
|
1732 * <p>
|
|
1733 * Note: This is not the actual structure used by the receiver
|
|
1734 * to maintain its selection, so modifying the array will
|
|
1735 * not affect the receiver.
|
|
1736 * </p>
|
|
1737 * @return the array of indices of the selected items
|
|
1738 *
|
|
1739 * @exception SWTException <ul>
|
|
1740 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1741 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1742 * </ul>
|
|
1743 */
|
|
1744 public int [] getSelectionIndices () {
|
|
1745 checkWidget();
|
|
1746 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1747 if (OS.GTK_VERSION < OS.buildVERSION (2, 2, 0)) {
|
|
1748 display.treeSelectionLength = 0;
|
|
1749 display.treeSelection = new int [itemCount];
|
|
1750 display.doTreeSelectionProcConnect( &treeSelectionCallbackData, handle, selection );
|
|
1751 if (display.treeSelectionLength is display.treeSelection.length) return display.treeSelection;
|
|
1752 int [] result = new int [display.treeSelectionLength];
|
|
1753 System.arraycopy (display.treeSelection, 0, result, 0, display.treeSelectionLength);
|
|
1754 return result;
|
|
1755 }
|
|
1756 /*
|
|
1757 * Bug in GTK. gtk_tree_selection_get_selected_rows() segmentation faults
|
|
1758 * in versions smaller than 2.2.4 if the model is NULL. The fix is
|
|
1759 * to give a valid pointer instead.
|
|
1760 */
|
|
1761 int dummy;
|
|
1762 void* model = OS.GTK_VERSION < OS.buildVERSION (2, 2, 4) ? &dummy : null;
|
|
1763 auto list = OS.gtk_tree_selection_get_selected_rows (selection, &model);
|
|
1764 if (list !is null) {
|
|
1765 int count = OS.g_list_length (list);
|
|
1766 int [] treeSelection = new int [count];
|
|
1767 int length_ = 0;
|
|
1768 for (int i=0; i<count; i++) {
|
|
1769 auto data = OS.g_list_nth_data (list, i);
|
|
1770 auto indices = OS.gtk_tree_path_get_indices (data);
|
|
1771 if (indices !is null) {
|
|
1772 treeSelection [length_] = indices [0];
|
|
1773 length_++;
|
|
1774 }
|
|
1775 }
|
|
1776 OS.g_list_free (list);
|
|
1777 int [] result = new int [length_];
|
|
1778 System.arraycopy (treeSelection, 0, result, 0, length_);
|
|
1779 return result;
|
|
1780 }
|
|
1781 return null;
|
|
1782 }
|
|
1783
|
|
1784 /**
|
|
1785 * Returns the column which shows the sort indicator for
|
|
1786 * the receiver. The value may be null if no column shows
|
|
1787 * the sort indicator.
|
|
1788 *
|
|
1789 * @return the sort indicator
|
|
1790 *
|
|
1791 * @exception SWTException <ul>
|
|
1792 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1793 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1794 * </ul>
|
|
1795 *
|
|
1796 * @see #setSortColumn(TableColumn)
|
|
1797 *
|
|
1798 * @since 3.2
|
|
1799 */
|
|
1800 public TableColumn getSortColumn () {
|
|
1801 checkWidget ();
|
|
1802 return sortColumn;
|
|
1803 }
|
|
1804
|
|
1805 /**
|
|
1806 * Returns the direction of the sort indicator for the receiver.
|
|
1807 * The value will be one of <code>UP</code>, <code>DOWN</code>
|
|
1808 * or <code>NONE</code>.
|
|
1809 *
|
|
1810 * @return the sort direction
|
|
1811 *
|
|
1812 * @exception SWTException <ul>
|
|
1813 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1814 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1815 * </ul>
|
|
1816 *
|
|
1817 * @see #setSortDirectioncast(int)
|
|
1818 *
|
|
1819 * @since 3.2
|
|
1820 */
|
|
1821 public int getSortDirection () {
|
|
1822 checkWidget ();
|
|
1823 return sortDirection;
|
|
1824 }
|
|
1825
|
|
1826 GtkCellRendererText* getTextRenderer (GtkTreeViewColumn* column) {
|
|
1827 auto list = OS.gtk_tree_view_column_get_cell_renderers (column);
|
|
1828 if (list is null) return null;
|
|
1829 int count = OS.g_list_length (list);
|
|
1830 GtkCellRendererText* textRenderer;
|
|
1831 int i = 0;
|
|
1832 while (i < count) {
|
|
1833 auto renderer = OS.g_list_nth_data (list, i);
|
|
1834 if (OS.GTK_IS_CELL_RENDERER_TEXT (cast(GTypeInstance*)renderer)) {
|
|
1835 textRenderer = cast(GtkCellRendererText*)renderer;
|
|
1836 break;
|
|
1837 }
|
|
1838 i++;
|
|
1839 }
|
|
1840 OS.g_list_free (list);
|
|
1841 return textRenderer;
|
|
1842 }
|
|
1843
|
|
1844 /**
|
|
1845 * Returns the zero-relative index of the item which is currently
|
|
1846 * at the top of the receiver. This index can change when items are
|
|
1847 * scrolled or new items are added or removed.
|
|
1848 *
|
|
1849 * @return the index of the top item
|
|
1850 *
|
|
1851 * @exception SWTException <ul>
|
|
1852 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
1853 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
1854 * </ul>
|
|
1855 */
|
|
1856 public int getTopIndex () {
|
|
1857 checkWidget();
|
|
1858 void* path;
|
|
1859 OS.gtk_widget_realize (handle);
|
|
1860 if (!OS.gtk_tree_view_get_path_at_pos (handle, 1, 1, &path, null, null, null)) return 0;
|
|
1861 if (path is null) return 0;
|
|
1862 auto indices = OS.gtk_tree_path_get_indices (path);
|
|
1863 int index;
|
|
1864 if (indices !is null) index = indices[0];
|
|
1865 OS.gtk_tree_path_free (path);
|
|
1866 return index;
|
|
1867 }
|
|
1868
|
|
1869 override int gtk_button_press_event (GtkWidget* widget, GdkEventButton* gdkEvent) {
|
|
1870 if (gdkEvent.window !is OS.gtk_tree_view_get_bin_window (handle)) return 0;
|
|
1871 auto result = super.gtk_button_press_event (widget, gdkEvent);
|
|
1872 if (result !is 0) return result;
|
|
1873 /*
|
|
1874 * Feature in GTK. In a multi-select table view, when multiple items are already
|
|
1875 * selected, the selection state of the item is toggled and the previous selection
|
|
1876 * is cleared. This is not the desired behaviour when bringing up a popup menu.
|
|
1877 * Also, when an item is reselected with the right button, the tree view issues
|
|
1878 * an unwanted selection event. The workaround is to detect that case and not
|
|
1879 * run the default handler when the item is already part of the current selection.
|
|
1880 */
|
|
1881 int button = gdkEvent.button;
|
|
1882 if (button is 3 && gdkEvent.type is OS.GDK_BUTTON_PRESS) {
|
|
1883 void* path;
|
|
1884 if (OS.gtk_tree_view_get_path_at_pos (handle, cast(int)gdkEvent.x, cast(int)gdkEvent.y, &path, null, null, null)) {
|
|
1885 if (path !is null) {
|
|
1886 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1887 if (OS.gtk_tree_selection_path_is_selected (selection, path)) result = 1;
|
|
1888 OS.gtk_tree_path_free (path);
|
|
1889 }
|
|
1890 }
|
|
1891 }
|
|
1892
|
|
1893 /*
|
|
1894 * Feature in GTK. When the user clicks in a single selection GtkTreeView
|
|
1895 * and there are no selected items, the first item is selected automatically
|
|
1896 * before the click is processed, causing two selection events. The is fix
|
|
1897 * is the set the cursor item to be same as the clicked item to stop the
|
|
1898 * widget from automatically selecting the first item.
|
|
1899 */
|
|
1900 if ((style & SWT.SINGLE) !is 0 && getSelectionCount () is 0) {
|
|
1901 void* path;
|
|
1902 if (OS.gtk_tree_view_get_path_at_pos (handle, cast(int)gdkEvent.x, cast(int)gdkEvent.y, &path, null, null, null)) {
|
|
1903 if (path !is null) {
|
|
1904 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
1905 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1906 OS.gtk_tree_view_set_cursor (handle, path, null, false);
|
|
1907 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
1908 OS.gtk_tree_path_free (path);
|
|
1909 }
|
|
1910 }
|
|
1911 }
|
|
1912 /*
|
|
1913 * Bug in GTK. GTK segments fault, if the GtkTreeView widget is
|
|
1914 * not in focus and all items in the widget are disposed before
|
|
1915 * it finishes processing a button press. The fix is to give
|
|
1916 * focus to the widget before it starts processing the event.
|
|
1917 */
|
|
1918 if (!OS.GTK_WIDGET_HAS_FOCUS (handle)) {
|
|
1919 OS.gtk_widget_grab_focus (handle);
|
|
1920 }
|
|
1921 return result;
|
|
1922 }
|
|
1923
|
|
1924 override int gtk_button_release_event (GtkWidget* widget, GdkEventButton* event) {
|
|
1925 auto window = OS.GDK_EVENT_WINDOW (event);
|
|
1926 if (window !is OS.gtk_tree_view_get_bin_window (handle)) return 0;
|
|
1927 return super.gtk_button_release_event (widget, event);
|
|
1928 }
|
|
1929
|
|
1930 override int gtk_changed (GtkWidget* widget) {
|
|
1931 TableItem item = getFocusItem ();
|
|
1932 if (item !is null) {
|
|
1933 Event event = new Event ();
|
|
1934 event.item = item;
|
|
1935 postEvent (SWT.Selection, event);
|
|
1936 }
|
|
1937 return 0;
|
|
1938 }
|
|
1939
|
|
1940 override int gtk_key_press_event (GtkWidget* widget, GdkEventKey* keyEvent) {
|
|
1941 auto result = super.gtk_key_press_event (widget, keyEvent);
|
|
1942 if (result !is 0) return result;
|
|
1943 if (OS.GTK_VERSION < OS.buildVERSION (2, 2 ,0)) {
|
|
1944 /*
|
|
1945 * Feature in GTK 2.0.x. When an item is default selected using
|
|
1946 * the return key, GTK does not issue notification. The fix is
|
|
1947 * to issue this notification when the return key is pressed.
|
|
1948 */
|
|
1949 int key = keyEvent.keyval;
|
|
1950 switch (key) {
|
|
1951 case OS.GDK_Return:
|
|
1952 case OS.GDK_KP_Enter: {
|
|
1953 Event event = new Event ();
|
|
1954 event.item = getFocusItem ();
|
|
1955 postEvent (SWT.DefaultSelection, event);
|
|
1956 break;
|
|
1957 }
|
|
1958 default:
|
|
1959 }
|
|
1960 }
|
|
1961 return result;
|
|
1962 }
|
|
1963
|
|
1964 override int gtk_popup_menu (GtkWidget* widget) {
|
|
1965 auto result = super.gtk_popup_menu (widget);
|
|
1966 /*
|
|
1967 * Bug in GTK. The context menu for the typeahead in GtkTreeViewer
|
|
1968 * opens in the bottom right corner of the screen when Shift+F10
|
|
1969 * is pressed and the typeahead window was not visible. The fix is
|
|
1970 * to prevent the context menu from opening by stopping the default
|
|
1971 * handler.
|
|
1972 *
|
|
1973 * NOTE: The bug only happens in GTK 2.6.5 and lower.
|
|
1974 */
|
|
1975 return OS.GTK_VERSION < OS.buildVERSION (2, 6, 5) ? 1 : result;
|
|
1976 }
|
|
1977
|
|
1978 override int gtk_motion_notify_event (GtkWidget* widget, GdkEventMotion* event) {
|
|
1979 auto window = OS.GDK_EVENT_WINDOW (event);
|
|
1980 if (window !is OS.gtk_tree_view_get_bin_window (handle)) return 0;
|
|
1981 return super.gtk_motion_notify_event (widget, event);
|
|
1982 }
|
|
1983
|
|
1984 override void gtk_row_activated (GtkTreeView* tree, GtkTreePath* path, GtkTreeViewColumn* column) {
|
|
1985 TableItem item = null;
|
|
1986 auto indices = OS.gtk_tree_path_get_indices (path);
|
|
1987 if (indices !is null) {
|
|
1988 item = _getItem (indices [0]);
|
|
1989 }
|
|
1990 Event event = new Event ();
|
|
1991 event.item = item;
|
|
1992 postEvent (SWT.DefaultSelection, event);
|
|
1993 }
|
|
1994
|
|
1995 override int gtk_toggled (int /*long*/ renderer, char* pathStr) {
|
|
1996 auto path = OS.gtk_tree_path_new_from_string (pathStr);
|
|
1997 if (path is null) return 0;
|
|
1998 auto indices = OS.gtk_tree_path_get_indices (path);
|
|
1999 if (indices !is null) {
|
|
2000 TableItem item = _getItem (indices [0]);
|
|
2001 item.setChecked (!item.getChecked ());
|
|
2002 Event event = new Event ();
|
|
2003 event.detail = SWT.CHECK;
|
|
2004 event.item = item;
|
|
2005 postEvent (SWT.Selection, event);
|
|
2006 }
|
|
2007 OS.gtk_tree_path_free (path);
|
|
2008 return 0;
|
|
2009 }
|
|
2010
|
|
2011 override void gtk_widget_size_request (GtkWidget* widget, GtkRequisition* requisition) {
|
|
2012 /*
|
|
2013 * Bug in GTK. For some reason, gtk_widget_size_request() fails
|
|
2014 * to include the height of the tree view items when there are
|
|
2015 * no columns visible. The fix is to temporarily make one column
|
|
2016 * visible.
|
|
2017 */
|
|
2018 if (columnCount is 0) {
|
|
2019 super.gtk_widget_size_request (widget, requisition);
|
|
2020 return;
|
|
2021 }
|
|
2022 auto columns = OS.gtk_tree_view_get_columns (handle), list = columns;
|
|
2023 bool fixVisible = columns !is null;
|
|
2024 while (list !is null) {
|
|
2025 auto column = OS.g_list_data (list);
|
|
2026 if (OS.gtk_tree_view_column_get_visible (column)) {
|
|
2027 fixVisible = false;
|
|
2028 break;
|
|
2029 }
|
|
2030 list = OS.g_list_next (list);
|
|
2031 }
|
|
2032 void* columnHandle;
|
|
2033 if (fixVisible) {
|
|
2034 columnHandle = OS.g_list_data (columns);
|
|
2035 OS.gtk_tree_view_column_set_visible (columnHandle, true);
|
|
2036 }
|
|
2037 super.gtk_widget_size_request (widget, requisition);
|
|
2038 if (fixVisible) {
|
|
2039 OS.gtk_tree_view_column_set_visible (columnHandle, false);
|
|
2040 }
|
|
2041 if (columns !is null) OS.g_list_free (columns);
|
|
2042 }
|
|
2043
|
|
2044 void hideFirstColumn () {
|
|
2045 auto firstColumn = OS.gtk_tree_view_get_column (handle, 0);
|
|
2046 OS.gtk_tree_view_column_set_visible (firstColumn, false);
|
|
2047 }
|
|
2048
|
|
2049 override void hookEvents () {
|
|
2050 super.hookEvents ();
|
|
2051 auto selection = OS.gtk_tree_view_get_selection(handle);
|
|
2052 OS.g_signal_connect_closure (selection, OS.changed.ptr, display.closures [CHANGED], false);
|
|
2053 OS.g_signal_connect_closure (handle, OS.row_activated.ptr, display.closures [ROW_ACTIVATED], false);
|
|
2054 if (checkRenderer !is null) {
|
|
2055 OS.g_signal_connect_closure (checkRenderer, OS.toggled.ptr, display.closures [TOGGLED], false);
|
|
2056 }
|
|
2057 }
|
|
2058
|
|
2059 /**
|
|
2060 * Searches the receiver's list starting at the first column
|
|
2061 * (index 0) until a column is found that is equal to the
|
|
2062 * argument, and returns the index of that column. If no column
|
|
2063 * is found, returns -1.
|
|
2064 *
|
|
2065 * @param column the search column
|
|
2066 * @return the index of the column
|
|
2067 *
|
|
2068 * @exception IllegalArgumentException <ul>
|
|
2069 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
|
|
2070 * </ul>
|
|
2071 * @exception SWTException <ul>
|
|
2072 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2073 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2074 * </ul>
|
|
2075 */
|
|
2076 public int indexOf (TableColumn column) {
|
|
2077 checkWidget();
|
|
2078 if (column is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2079 for (int i=0; i<columnCount; i++) {
|
|
2080 if (columns [i] is column) return i;
|
|
2081 }
|
|
2082 return -1;
|
|
2083 }
|
|
2084
|
|
2085 /**
|
|
2086 * Searches the receiver's list starting at the first item
|
|
2087 * (index 0) until an item is found that is equal to the
|
|
2088 * argument, and returns the index of that item. If no item
|
|
2089 * is found, returns -1.
|
|
2090 *
|
|
2091 * @param item the search item
|
|
2092 * @return the index of the item
|
|
2093 *
|
|
2094 * @exception IllegalArgumentException <ul>
|
|
2095 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
|
|
2096 * </ul>
|
|
2097 * @exception SWTException <ul>
|
|
2098 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2099 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2100 * </ul>
|
|
2101 */
|
|
2102 public int indexOf (TableItem item) {
|
|
2103 checkWidget();
|
|
2104 if (item is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2105 if (1 <= lastIndexOf && lastIndexOf < itemCount - 1) {
|
|
2106 if (items [lastIndexOf] is item) return lastIndexOf;
|
|
2107 if (items [lastIndexOf + 1] is item) return ++lastIndexOf;
|
|
2108 if (items [lastIndexOf - 1] is item) return --lastIndexOf;
|
|
2109 }
|
|
2110 if (lastIndexOf < itemCount / 2) {
|
|
2111 for (int i=0; i<itemCount; i++) {
|
|
2112 if (items [i] is item) return lastIndexOf = i;
|
|
2113 }
|
|
2114 } else {
|
|
2115 for (int i=itemCount - 1; i>=0; --i) {
|
|
2116 if (items [i] is item) return lastIndexOf = i;
|
|
2117 }
|
|
2118 }
|
|
2119 return -1;
|
|
2120 }
|
|
2121
|
|
2122 /**
|
|
2123 * Returns <code>true</code> if the item is selected,
|
|
2124 * and <code>false</code> otherwise. Indices out of
|
|
2125 * range are ignored.
|
|
2126 *
|
|
2127 * @param index the index of the item
|
|
2128 * @return the selection state of the item at the index
|
|
2129 *
|
|
2130 * @exception SWTException <ul>
|
|
2131 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2132 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2133 * </ul>
|
|
2134 */
|
|
2135 public bool isSelected (int index) {
|
|
2136 checkWidget();
|
|
2137 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2138 char* buffer = toStringz( to!(String)(index));
|
|
2139 auto path = OS.gtk_tree_path_new_from_string (buffer);
|
|
2140 bool answer = cast(bool)OS.gtk_tree_selection_path_is_selected (selection, path);
|
|
2141 OS.gtk_tree_path_free (path);
|
|
2142 return answer;
|
|
2143 }
|
|
2144
|
|
2145 override bool mnemonicHit (wchar key) {
|
|
2146 for (int i=0; i<columnCount; i++) {
|
|
2147 auto labelHandle = columns [i].labelHandle;
|
|
2148 if (labelHandle !is null && mnemonicHit (labelHandle, key)) return true;
|
|
2149 }
|
|
2150 return false;
|
|
2151 }
|
|
2152
|
|
2153 override bool mnemonicMatch (wchar key) {
|
|
2154 for (int i=0; i<columnCount; i++) {
|
|
2155 auto labelHandle = columns [i].labelHandle;
|
|
2156 if (labelHandle !is null && mnemonicMatch (labelHandle, key)) return true;
|
|
2157 }
|
|
2158 return false;
|
|
2159 }
|
|
2160
|
|
2161 override GdkDrawable* paintWindow () {
|
|
2162 OS.gtk_widget_realize (handle);
|
|
2163 return OS.gtk_tree_view_get_bin_window (handle);
|
|
2164 }
|
|
2165
|
|
2166 void recreateRenderers () {
|
|
2167 if (checkRenderer !is null) {
|
|
2168 display.removeWidget (checkRenderer);
|
|
2169 OS.g_object_unref (checkRenderer);
|
|
2170 checkRenderer = ownerDraw ? cast(GtkWidget*)OS.g_object_new (display.gtk_cell_renderer_toggle_get_type(), null) : cast(GtkWidget*)OS.gtk_cell_renderer_toggle_new ();
|
|
2171 if (checkRenderer is null) error (SWT.ERROR_NO_HANDLES);
|
|
2172 OS.g_object_ref (checkRenderer);
|
|
2173 display.addWidget (checkRenderer, this);
|
|
2174 OS.g_signal_connect_closure (checkRenderer, OS.toggled.ptr, display.closures [TOGGLED], false);
|
|
2175 }
|
|
2176 if (columnCount is 0) {
|
|
2177 createRenderers (OS.gtk_tree_view_get_column (handle, 0), Table.FIRST_COLUMN, true, 0);
|
|
2178 } else {
|
|
2179 for (int i = 0; i < columnCount; i++) {
|
|
2180 TableColumn column = columns [i];
|
|
2181 createRenderers (cast(GtkTreeViewColumn*)column.handle, column.modelIndex, i is 0, column.style);
|
|
2182 }
|
|
2183 }
|
|
2184 }
|
|
2185
|
|
2186 override void redrawBackgroundImage () {
|
|
2187 Control control = findBackgroundControl ();
|
|
2188 if (control !is null && control.backgroundImage !is null) {
|
|
2189 redrawWidget (0, 0, 0, 0, true, false, false);
|
|
2190 }
|
|
2191 }
|
|
2192
|
|
2193 override void register () {
|
|
2194 super.register ();
|
|
2195 display.addWidget ( cast(GtkWidget*)OS.gtk_tree_view_get_selection (handle), this);
|
|
2196 if (checkRenderer !is null) display.addWidget (checkRenderer, this);
|
|
2197 }
|
|
2198
|
|
2199 override void releaseChildren (bool destroy) {
|
|
2200 if (items !is null) {
|
|
2201 for (int i=0; i<itemCount; i++) {
|
|
2202 TableItem item = items [i];
|
|
2203 if (item !is null && !item.isDisposed ()) {
|
|
2204 item.release (false);
|
|
2205 }
|
|
2206 }
|
|
2207 items = null;
|
|
2208 }
|
|
2209 if (columns !is null) {
|
|
2210 for (int i=0; i<columnCount; i++) {
|
|
2211 TableColumn column = columns [i];
|
|
2212 if (column !is null && !column.isDisposed ()) {
|
|
2213 column.release (false);
|
|
2214 }
|
|
2215 }
|
|
2216 columns = null;
|
|
2217 }
|
|
2218 super.releaseChildren (destroy);
|
|
2219 }
|
|
2220
|
|
2221 override void releaseWidget () {
|
|
2222 super.releaseWidget ();
|
|
2223 if (modelHandle !is null) OS.g_object_unref (modelHandle);
|
|
2224 modelHandle = null;
|
|
2225 if (checkRenderer !is null) OS.g_object_unref (checkRenderer);
|
|
2226 checkRenderer = null;
|
|
2227 if (imageList !is null) imageList.dispose ();
|
|
2228 if (headerImageList !is null) headerImageList.dispose ();
|
|
2229 imageList = headerImageList = null;
|
|
2230 currentItem = null;
|
|
2231 }
|
|
2232
|
|
2233 /**
|
|
2234 * Removes the item from the receiver at the given
|
|
2235 * zero-relative index.
|
|
2236 *
|
|
2237 * @param index the index for the item
|
|
2238 *
|
|
2239 * @exception IllegalArgumentException <ul>
|
|
2240 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
2241 * </ul>
|
|
2242 * @exception SWTException <ul>
|
|
2243 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2244 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2245 * </ul>
|
|
2246 */
|
|
2247 public void remove (int index) {
|
|
2248 checkWidget();
|
|
2249 if (!(0 <= index && index < itemCount)) error (SWT.ERROR_ITEM_NOT_REMOVED);
|
|
2250 GtkTreeIter iter;
|
|
2251 TableItem item = items [index];
|
|
2252 bool disposed = false;
|
|
2253 if (item !is null) {
|
|
2254 disposed = item.isDisposed ();
|
|
2255 if (!disposed) {
|
|
2256 iter = *cast(GtkTreeIter*)item.handle;
|
|
2257 item.release (false);
|
|
2258 }
|
|
2259 } else {
|
|
2260 OS.gtk_tree_model_iter_nth_child (modelHandle, &iter, null, index);
|
|
2261 }
|
|
2262 if (!disposed) {
|
|
2263 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2264 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2265 OS.gtk_list_store_remove (modelHandle, &iter);
|
|
2266 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2267 System.arraycopy (items, index + 1, items, index, --itemCount - index);
|
|
2268 items [itemCount] = null;
|
|
2269 }
|
|
2270 }
|
|
2271
|
|
2272 /**
|
|
2273 * Removes the items from the receiver which are
|
|
2274 * between the given zero-relative start and end
|
|
2275 * indices (inclusive).
|
|
2276 *
|
|
2277 * @param start the start of the range
|
|
2278 * @param end the end of the range
|
|
2279 *
|
|
2280 * @exception IllegalArgumentException <ul>
|
|
2281 * <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>
|
|
2282 * </ul>
|
|
2283 * @exception SWTException <ul>
|
|
2284 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2285 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2286 * </ul>
|
|
2287 */
|
|
2288 public void remove (int start, int end) {
|
|
2289 checkWidget();
|
|
2290 if (start > end) return;
|
|
2291 if (!(0 <= start && start <= end && end < itemCount)) {
|
|
2292 error (SWT.ERROR_INVALID_RANGE);
|
|
2293 }
|
|
2294 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2295 GtkTreeIter iter;
|
|
2296 OS.gtk_tree_model_iter_nth_child (modelHandle, &iter, null, start);
|
|
2297 int index = start;
|
|
2298 while (index <= end) {
|
|
2299 TableItem item = items [index];
|
|
2300 if (item !is null && !item.isDisposed ()) item.release (false);
|
|
2301 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2302 OS.gtk_list_store_remove (modelHandle, &iter);
|
|
2303 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2304 index++;
|
|
2305 }
|
|
2306 System.arraycopy (items, index, items, start, itemCount - index);
|
|
2307 for (int i=itemCount-(index-start); i<itemCount; i++) items [i] = null;
|
|
2308 itemCount = itemCount - (index - start);
|
|
2309 }
|
|
2310
|
|
2311 /**
|
|
2312 * Removes the items from the receiver's list at the given
|
|
2313 * zero-relative indices.
|
|
2314 *
|
|
2315 * @param indices the array of indices of the items
|
|
2316 *
|
|
2317 * @exception IllegalArgumentException <ul>
|
|
2318 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
|
|
2319 * </ul>
|
|
2320 * @exception SWTException <ul>
|
|
2321 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2322 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2323 * </ul>
|
|
2324 */
|
|
2325 public void remove (int [] indices) {
|
|
2326 checkWidget();
|
|
2327 // SWT extension: allow null for zero length string
|
|
2328 //if (indices is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2329 if (indices.length is 0) return;
|
|
2330 int [] newIndices = new int [indices.length];
|
|
2331 System.arraycopy (indices, 0, newIndices, 0, indices.length);
|
|
2332 sort (newIndices);
|
|
2333 int start = newIndices [newIndices.length - 1], end = newIndices [0];
|
|
2334 if (!(0 <= start && start <= end && end < itemCount)) {
|
|
2335 error (SWT.ERROR_INVALID_RANGE);
|
|
2336 }
|
|
2337 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2338 int last = -1;
|
|
2339 GtkTreeIter iter;
|
|
2340 for (int i=0; i<newIndices.length; i++) {
|
|
2341 int index = newIndices [i];
|
|
2342 if (index !is last) {
|
|
2343 TableItem item = items [index];
|
|
2344 bool disposed = false;
|
|
2345 if (item !is null) {
|
|
2346 disposed = item.isDisposed ();
|
|
2347 if (!disposed) {
|
|
2348 iter = *cast(GtkTreeIter*) item.handle;
|
|
2349 item.release (false);
|
|
2350 }
|
|
2351 } else {
|
|
2352 OS.gtk_tree_model_iter_nth_child (modelHandle, &iter, null, index);
|
|
2353 }
|
|
2354 if (!disposed) {
|
|
2355 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2356 OS.gtk_list_store_remove (modelHandle, &iter);
|
|
2357 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2358 System.arraycopy (items, index + 1, items, index, --itemCount - index);
|
|
2359 items [itemCount] = null;
|
|
2360 }
|
|
2361 last = index;
|
|
2362 }
|
|
2363 }
|
|
2364 }
|
|
2365
|
|
2366 /**
|
|
2367 * Removes all of the items from the receiver.
|
|
2368 *
|
|
2369 * @exception SWTException <ul>
|
|
2370 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2371 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2372 * </ul>
|
|
2373 */
|
|
2374 public void removeAll () {
|
|
2375 checkWidget();
|
|
2376 int index = itemCount - 1;
|
|
2377 while (index >= 0) {
|
|
2378 TableItem item = items [index];
|
|
2379 if (item !is null && !item.isDisposed ()) item.release (false);
|
|
2380 --index;
|
|
2381 }
|
|
2382 items = new TableItem [4];
|
|
2383 itemCount = 0;
|
|
2384 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2385 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2386 OS.gtk_list_store_clear (modelHandle);
|
|
2387 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2388
|
|
2389 resetCustomDraw ();
|
|
2390 /* Disable searching when using VIRTUAL */
|
|
2391 if ((style & SWT.VIRTUAL) !is 0) {
|
|
2392 /*
|
|
2393 * Bug in GTK. Until GTK 2.6.5, calling gtk_tree_view_set_enable_search(FALSE)
|
|
2394 * would prevent the user from being able to type in text to search the tree.
|
|
2395 * After 2.6.5, GTK introduced Ctrl+F as being the key binding for interactive
|
|
2396 * search. This meant that even if FALSE was passed to enable_search, the user
|
|
2397 * can still bring up the search pop up using the keybinding. GTK also introduced
|
|
2398 * the notion of passing a -1 to gtk_set_search_column to disable searching
|
|
2399 * (including the search key binding). The fix is to use the right calls
|
|
2400 * for the right version.
|
|
2401 */
|
|
2402 if (OS.GTK_VERSION >= OS.buildVERSION (2, 6, 5)){
|
|
2403 OS.gtk_tree_view_set_search_column (handle, -1);
|
|
2404 } else {
|
|
2405 OS.gtk_tree_view_set_enable_search (handle, false);
|
|
2406 }
|
|
2407 } else {
|
|
2408 /* Set the search column whenever the model changes */
|
|
2409 int firstColumn = columnCount is 0 ? FIRST_COLUMN : columns [0].modelIndex;
|
|
2410 OS.gtk_tree_view_set_search_column (handle, firstColumn + CELL_TEXT);
|
|
2411 }
|
|
2412 }
|
|
2413
|
|
2414 /**
|
|
2415 * Removes the listener from the collection of listeners who will
|
|
2416 * be notified when the user changes the receiver's selection.
|
|
2417 *
|
|
2418 * @param listener the listener which should no longer be notified
|
|
2419 *
|
|
2420 * @exception IllegalArgumentException <ul>
|
|
2421 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
|
|
2422 * </ul>
|
|
2423 * @exception SWTException <ul>
|
|
2424 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2425 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2426 * </ul>
|
|
2427 *
|
|
2428 * @see SelectionListener
|
|
2429 * @see #addSelectionListener(SelectionListener)
|
|
2430 */
|
|
2431 public void removeSelectionListener(SelectionListener listener) {
|
|
2432 checkWidget();
|
|
2433 if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2434 if (eventTable is null) return;
|
|
2435 eventTable.unhook (SWT.Selection, listener);
|
|
2436 eventTable.unhook (SWT.DefaultSelection,listener);
|
|
2437 }
|
|
2438
|
|
2439 override void rendererGetSizeProc (
|
|
2440 GtkCellRenderer *cell,
|
|
2441 GtkWidget *widget,
|
|
2442 GdkRectangle *cell_area,
|
|
2443 int *x_offset,
|
|
2444 int *y_offset,
|
|
2445 int *width,
|
|
2446 int *height)
|
|
2447 {
|
|
2448 auto g_class = OS.g_type_class_peek_parent (OS.G_OBJECT_GET_CLASS (cell));
|
|
2449 GtkCellRendererClass* klass = cast(GtkCellRendererClass*)g_class;
|
|
2450 klass.get_size( cell, handle, cell_area, x_offset, y_offset, width, height);
|
|
2451 if (!ignoreSize && OS.GTK_IS_CELL_RENDERER_TEXT (cell)) {
|
|
2452 auto iter = OS.g_object_get_qdata (cast(GObject*)cell, Display.SWT_OBJECT_INDEX2);
|
|
2453 TableItem item = null;
|
|
2454 if (iter !is null) {
|
|
2455 auto path = OS.gtk_tree_model_get_path (modelHandle, iter);
|
|
2456 auto buffer = OS.gtk_tree_path_get_indices (path);
|
|
2457 int index = buffer [0];
|
|
2458 item = _getItem (index);
|
|
2459 OS.gtk_tree_path_free (path);
|
|
2460 }
|
|
2461 if (item !is null) {
|
|
2462 int columnIndex = 0;
|
|
2463 if (columnCount > 0) {
|
|
2464 auto columnHandle = OS.g_object_get_qdata (cast(GObject*)cell, Display.SWT_OBJECT_INDEX1);
|
|
2465 for (int i = 0; i < columnCount; i++) {
|
|
2466 if (columns [i].handle is columnHandle) {
|
|
2467 columnIndex = i;
|
|
2468 break;
|
|
2469 }
|
|
2470 }
|
|
2471 }
|
|
2472 if (hooks (SWT.MeasureItem)) {
|
|
2473 int contentWidth, contentHeight;
|
|
2474 if (width !is null) contentWidth = *width;
|
|
2475 if (height !is null) contentHeight = *height;
|
|
2476 Image image = item.getImage (columnIndex);
|
|
2477 int imageWidth = 0;
|
|
2478 if (image !is null) {
|
|
2479 Rectangle bounds = image.getBounds ();
|
|
2480 imageWidth = bounds.width;
|
|
2481 }
|
|
2482 contentWidth += imageWidth;
|
|
2483 GC gc = new GC (this);
|
|
2484 gc.setFont (item.getFont (columnIndex));
|
|
2485 Event event = new Event ();
|
|
2486 event.item = item;
|
|
2487 event.index = columnIndex;
|
|
2488 event.gc = gc;
|
|
2489 event.width = contentWidth;
|
|
2490 event.height = contentHeight;
|
|
2491 sendEvent (SWT.MeasureItem, event);
|
|
2492 gc.dispose ();
|
|
2493 contentWidth = event.width - imageWidth;
|
|
2494 if (contentHeight < event.height) contentHeight = event.height;
|
|
2495 if (width !is null) *width = contentWidth;
|
|
2496 if (height !is null) *height = contentHeight;
|
|
2497 }
|
|
2498 }
|
|
2499 }
|
|
2500 }
|
|
2501
|
|
2502 override void rendererRenderProc (
|
|
2503 GtkCellRenderer * cell,
|
|
2504 GdkDrawable * window,
|
|
2505 GtkWidget * widget,
|
|
2506 GdkRectangle *background_area,
|
|
2507 GdkRectangle *cell_area,
|
|
2508 GdkRectangle *expose_area,
|
|
2509 int flags)
|
|
2510 {
|
|
2511 TableItem item = null;
|
|
2512 auto iter = OS.g_object_get_qdata (cast(GObject*)cell, Display.SWT_OBJECT_INDEX2);
|
|
2513 if (iter !is null) {
|
|
2514 auto path = OS.gtk_tree_model_get_path (modelHandle, iter);
|
|
2515 auto buffer = OS.gtk_tree_path_get_indices (path);
|
|
2516 int index = buffer [0];
|
|
2517 item = _getItem (index);
|
|
2518 OS.gtk_tree_path_free (path);
|
|
2519 }
|
|
2520 auto columnHandle = OS.g_object_get_qdata (cast(GObject*)cell, Display.SWT_OBJECT_INDEX1);
|
|
2521 int columnIndex = 0;
|
|
2522 if (columnCount > 0) {
|
|
2523 for (int i = 0; i < columnCount; i++) {
|
|
2524 if (columns [i].handle is columnHandle) {
|
|
2525 columnIndex = i;
|
|
2526 break;
|
|
2527 }
|
|
2528 }
|
|
2529 }
|
|
2530 if (item !is null) {
|
|
2531 if (OS.GTK_IS_CELL_RENDERER_TOGGLE (cell) || (OS.GTK_IS_CELL_RENDERER_PIXBUF (cell) && (columnIndex !is 0 || (style & SWT.CHECK) is 0))) {
|
|
2532 drawFlags = cast(int)/*64*/flags;
|
|
2533 drawState = SWT.FOREGROUND;
|
|
2534 void* ptr;
|
|
2535 OS.gtk_tree_model_get1 (modelHandle, item.handle, Table.BACKGROUND_COLUMN, &ptr);
|
|
2536 if (ptr is null) {
|
|
2537 int modelIndex = columnCount is 0 ? Table.FIRST_COLUMN : columns [columnIndex].modelIndex;
|
|
2538 OS.gtk_tree_model_get1 (modelHandle, item.handle, modelIndex + Table.CELL_BACKGROUND, &ptr);
|
|
2539 }
|
|
2540 if (ptr !is null) drawState |= SWT.BACKGROUND;
|
|
2541 if ((flags & OS.GTK_CELL_RENDERER_SELECTED) !is 0) drawState |= SWT.SELECTED;
|
|
2542 if ((flags & OS.GTK_CELL_RENDERER_FOCUSED) !is 0) drawState |= SWT.FOCUSED;
|
|
2543
|
|
2544 GdkRectangle rect;
|
|
2545 auto path = OS.gtk_tree_model_get_path (modelHandle, iter);
|
|
2546 OS.gtk_tree_view_get_background_area (handle, path, columnHandle, &rect);
|
|
2547 OS.gtk_tree_path_free (path);
|
|
2548
|
|
2549 if ((drawState & SWT.SELECTED) is 0) {
|
|
2550 Control control = findBackgroundControl ();
|
|
2551 if (control !is null && control.backgroundImage !is null) {
|
|
2552 OS.gdk_window_clear_area (window, rect.x, rect.y, rect.width, rect.height);
|
|
2553 }
|
|
2554 }
|
|
2555
|
|
2556 if (hooks (SWT.EraseItem)) {
|
|
2557 bool wasSelected = false;
|
|
2558 if ((drawState & SWT.SELECTED) !is 0) {
|
|
2559 wasSelected = true;
|
|
2560 OS.gdk_window_clear_area (window, rect.x, rect.y, rect.width, rect.height);
|
|
2561 }
|
|
2562 GC gc = new GC (this);
|
|
2563 if ((drawState & SWT.SELECTED) !is 0) {
|
|
2564 gc.setBackground (display.getSystemColor (SWT.COLOR_LIST_SELECTION));
|
|
2565 gc.setForeground (display.getSystemColor (SWT.COLOR_LIST_SELECTION_TEXT));
|
|
2566 } else {
|
|
2567 gc.setBackground (item.getBackground (columnIndex));
|
|
2568 gc.setForeground (item.getForeground (columnIndex));
|
|
2569 }
|
|
2570 gc.setFont (item.getFont (columnIndex));
|
|
2571 if ((style & SWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
|
|
2572 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
|
|
2573 Event event = new Event ();
|
|
2574 event.item = item;
|
|
2575 event.index = columnIndex;
|
|
2576 event.gc = gc;
|
|
2577 event.x = rect.x;
|
|
2578 event.y = rect.y;
|
|
2579 event.width = rect.width;
|
|
2580 event.height = rect.height;
|
|
2581 event.detail = drawState;
|
|
2582 sendEvent (SWT.EraseItem, event);
|
|
2583 drawForeground = null;
|
|
2584 drawState = event.doit ? event.detail : 0;
|
|
2585 drawFlags &= ~(OS.GTK_CELL_RENDERER_FOCUSED | OS.GTK_CELL_RENDERER_SELECTED);
|
|
2586 if ((drawState & SWT.SELECTED) !is 0) drawFlags |= OS.GTK_CELL_RENDERER_SELECTED;
|
|
2587 if ((drawState & SWT.FOCUSED) !is 0) drawFlags |= OS.GTK_CELL_RENDERER_FOCUSED;
|
|
2588 if ((drawState & SWT.SELECTED) !is 0) {
|
|
2589 auto style = OS.gtk_widget_get_style (widget);
|
|
2590 //TODO - parity and sorted
|
|
2591 OS.gtk_paint_flat_box (style, window, OS.GTK_STATE_SELECTED, OS.GTK_SHADOW_NONE, &rect, widget, "cell_odd".ptr, rect.x, rect.y, rect.width, rect.height);
|
|
2592 } else {
|
|
2593 if (wasSelected) drawForeground = gc.getForeground ().handle;
|
|
2594 }
|
|
2595 gc.dispose();
|
|
2596 }
|
|
2597 }
|
|
2598 }
|
|
2599 int /*long*/ result = 0;
|
|
2600 if ((drawState & SWT.BACKGROUND) !is 0 && (drawState & SWT.SELECTED) is 0) {
|
|
2601 GC gc = new GC (this);
|
|
2602 gc.setBackground (item.getBackground (columnIndex));
|
|
2603 gc.fillRectangle (background_area.x, background_area.y, background_area.width, background_area.height);
|
|
2604 gc.dispose ();
|
|
2605 }
|
|
2606 if ((drawState & SWT.FOREGROUND) !is 0 || OS.GTK_IS_CELL_RENDERER_TOGGLE (cell)) {
|
|
2607 auto g_class = OS.g_type_class_peek_parent (OS.G_OBJECT_GET_CLASS (cell));
|
|
2608 GtkCellRendererClass* klass = cast(GtkCellRendererClass*)g_class;
|
|
2609 if (drawForeground !is null && OS.GTK_IS_CELL_RENDERER_TEXT (cell)) {
|
|
2610 OS.g_object_set1 (cell, OS.foreground_gdk.ptr, cast(int)drawForeground);
|
|
2611 }
|
|
2612 klass.render( cell, window, widget, background_area, cell_area, expose_area, drawFlags);
|
|
2613 }
|
|
2614 if (item !is null) {
|
|
2615 if (OS.GTK_IS_CELL_RENDERER_TEXT (cell)) {
|
|
2616 if (hooks (SWT.PaintItem)) {
|
|
2617 GdkRectangle rect;
|
|
2618 auto path = OS.gtk_tree_model_get_path (modelHandle, iter);
|
|
2619 OS.gtk_tree_view_get_background_area (handle, path, columnHandle, &rect);
|
|
2620 OS.gtk_tree_path_free (path);
|
|
2621 ignoreSize = true;
|
|
2622 int contentX, contentWidth;
|
|
2623 OS.gtk_cell_renderer_get_size (cell, handle, null, null, null, &contentWidth, null);
|
|
2624 OS.gtk_tree_view_column_cell_get_position (columnHandle, cell, &contentX, null);
|
|
2625 ignoreSize = false;
|
|
2626 Image image = item.getImage (columnIndex);
|
|
2627 int imageWidth = 0;
|
|
2628 if (image !is null) {
|
|
2629 Rectangle bounds = image.getBounds ();
|
|
2630 imageWidth = bounds.width;
|
|
2631 }
|
|
2632 contentX -= imageWidth;
|
|
2633 contentWidth += imageWidth;
|
|
2634 GC gc = new GC (this);
|
|
2635 if ((drawState & SWT.SELECTED) !is 0) {
|
|
2636 gc.setBackground (display.getSystemColor (SWT.COLOR_LIST_SELECTION));
|
|
2637 gc.setForeground (display.getSystemColor (SWT.COLOR_LIST_SELECTION_TEXT));
|
|
2638 } else {
|
|
2639 gc.setBackground (item.getBackground (columnIndex));
|
|
2640 Color foreground = drawForeground !is null ? Color.gtk_new (display, drawForeground) : item.getForeground (columnIndex);
|
|
2641 gc.setForeground (foreground);
|
|
2642 }
|
|
2643 gc.setFont (item.getFont (columnIndex));
|
|
2644 if ((style & SWT.MIRRORED) !is 0) rect.x = getClientWidth () - rect.width - rect.x;
|
|
2645 gc.setClipping (rect.x, rect.y, rect.width, rect.height);
|
|
2646 Event event = new Event ();
|
|
2647 event.item = item;
|
|
2648 event.index = columnIndex;
|
|
2649 event.gc = gc;
|
|
2650 event.x = rect.x + contentX;
|
|
2651 event.y = rect.y;
|
|
2652 event.width = contentWidth;
|
|
2653 event.height = rect.height;
|
|
2654 event.detail = drawState;
|
|
2655 sendEvent (SWT.PaintItem, event);
|
|
2656 gc.dispose();
|
|
2657 }
|
|
2658 }
|
|
2659 }
|
|
2660 }
|
|
2661
|
|
2662 void resetCustomDraw () {
|
|
2663 if ((style & SWT.VIRTUAL) !is 0 || ownerDraw) return;
|
|
2664 int end = Math.max (1, columnCount);
|
|
2665 for (int i=0; i<end; i++) {
|
|
2666 bool customDraw = columnCount !is 0 ? columns [i].customDraw : firstCustomDraw;
|
|
2667 if (customDraw) {
|
|
2668 auto column = OS.gtk_tree_view_get_column (handle, i);
|
|
2669 auto textRenderer = getTextRenderer (column);
|
|
2670 display.doCellDataProc( null, cast(GtkTreeViewColumn*)column, cast(GtkCellRenderer*)textRenderer );
|
|
2671 if (columnCount !is 0) columns [i].customDraw = false;
|
|
2672 }
|
|
2673 }
|
|
2674 firstCustomDraw = false;
|
|
2675 }
|
|
2676
|
|
2677 /**
|
|
2678 * Selects the item at the given zero-relative index in the receiver.
|
|
2679 * If the item at the index was already selected, it remains
|
|
2680 * selected. Indices that are out of range are ignored.
|
|
2681 *
|
|
2682 * @param index the index of the item to select
|
|
2683 *
|
|
2684 * @exception SWTException <ul>
|
|
2685 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2686 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2687 * </ul>
|
|
2688 */
|
|
2689 public void select (int index) {
|
|
2690 checkWidget();
|
|
2691 if (!(0 <= index && index < itemCount)) return;
|
|
2692 bool fixColumn = showFirstColumn ();
|
|
2693 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2694 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2695 TableItem item = _getItem (index);
|
|
2696 OS.gtk_tree_selection_select_iter (selection, item.handle);
|
|
2697 if ((style & SWT.SINGLE) !is 0) {
|
|
2698 auto path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
|
|
2699 OS.gtk_tree_view_set_cursor (handle, path, null, false);
|
|
2700 OS.gtk_tree_path_free (path);
|
|
2701 }
|
|
2702 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2703 if (fixColumn) hideFirstColumn ();
|
|
2704 }
|
|
2705
|
|
2706 /**
|
|
2707 * Selects the items in the range specified by the given zero-relative
|
|
2708 * indices in the receiver. The range of indices is inclusive.
|
|
2709 * The current selection is not cleared before the new items are selected.
|
|
2710 * <p>
|
|
2711 * If an item in the given range is not selected, it is selected.
|
|
2712 * If an item in the given range was already selected, it remains selected.
|
|
2713 * Indices that are out of range are ignored and no items will be selected
|
|
2714 * if start is greater than end.
|
|
2715 * If the receiver is single-select and there is more than one item in the
|
|
2716 * given range, then all indices are ignored.
|
|
2717 * </p>
|
|
2718 *
|
|
2719 * @param start the start of the range
|
|
2720 * @param end the end of the range
|
|
2721 *
|
|
2722 * @exception SWTException <ul>
|
|
2723 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2724 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2725 * </ul>
|
|
2726 *
|
|
2727 * @see Table#setSelection(int,int)
|
|
2728 */
|
|
2729 public void select (int start, int end) {
|
|
2730 checkWidget ();
|
|
2731 if (end < 0 || start > end || ((style & SWT.SINGLE) !is 0 && start !is end)) return;
|
|
2732 if (itemCount is 0 || start >= itemCount) return;
|
|
2733 start = Math.max (0, start);
|
|
2734 end = Math.min (end, itemCount - 1);
|
|
2735 bool fixColumn = showFirstColumn ();
|
|
2736 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2737 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2738 for (int index=start; index<=end; index++) {
|
|
2739 TableItem item = _getItem (index);
|
|
2740 OS.gtk_tree_selection_select_iter (selection, item.handle);
|
|
2741 if ((style & SWT.SINGLE) !is 0) {
|
|
2742 auto path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
|
|
2743 OS.gtk_tree_view_set_cursor (handle, path, null, false);
|
|
2744 OS.gtk_tree_path_free (path);
|
|
2745 }
|
|
2746 }
|
|
2747 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2748 if (fixColumn) hideFirstColumn ();
|
|
2749 }
|
|
2750
|
|
2751 /**
|
|
2752 * Selects the items at the given zero-relative indices in the receiver.
|
|
2753 * The current selection is not cleared before the new items are selected.
|
|
2754 * <p>
|
|
2755 * If the item at a given index is not selected, it is selected.
|
|
2756 * If the item at a given index was already selected, it remains selected.
|
|
2757 * Indices that are out of range and duplicate indices are ignored.
|
|
2758 * If the receiver is single-select and multiple indices are specified,
|
|
2759 * then all indices are ignored.
|
|
2760 * </p>
|
|
2761 *
|
|
2762 * @param indices the array of indices for the items to select
|
|
2763 *
|
|
2764 * @exception SWTException <ul>
|
|
2765 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2766 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2767 * </ul>
|
|
2768 *
|
|
2769 * @see Table#setSelection(int[])
|
|
2770 */
|
|
2771 public void select (int [] indices) {
|
|
2772 checkWidget ();
|
|
2773 // SWT extension: allow null for zero length string
|
|
2774 //if (indices is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2775 int length = indices.length;
|
|
2776 if (length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1)) return;
|
|
2777 bool fixColumn = showFirstColumn ();
|
|
2778 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2779 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2780 for (int i=0; i<length; i++) {
|
|
2781 int index = indices [i];
|
|
2782 if (!(0 <= index && index < itemCount)) continue;
|
|
2783 TableItem item = _getItem (index);
|
|
2784 OS.gtk_tree_selection_select_iter (selection, item.handle);
|
|
2785 if ((style & SWT.SINGLE) !is 0) {
|
|
2786 auto path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
|
|
2787 OS.gtk_tree_view_set_cursor (handle, path, null, false);
|
|
2788 OS.gtk_tree_path_free (path);
|
|
2789 }
|
|
2790 }
|
|
2791 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2792 if (fixColumn) hideFirstColumn ();
|
|
2793 }
|
|
2794
|
|
2795 /**
|
|
2796 * Selects all of the items in the receiver.
|
|
2797 * <p>
|
|
2798 * If the receiver is single-select, do nothing.
|
|
2799 * </p>
|
|
2800 *
|
|
2801 * @exception SWTException <ul>
|
|
2802 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2803 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2804 * </ul>
|
|
2805 */
|
|
2806 public void selectAll () {
|
|
2807 checkWidget();
|
|
2808 if ((style & SWT.SINGLE) !is 0) return;
|
|
2809 bool fixColumn = showFirstColumn ();
|
|
2810 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2811 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2812 OS.gtk_tree_selection_select_all (selection);
|
|
2813 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2814 if (fixColumn) hideFirstColumn ();
|
|
2815 }
|
|
2816
|
|
2817 void selectFocusIndex (int index) {
|
|
2818 /*
|
|
2819 * Note that this method both selects and sets the focus to the
|
|
2820 * specified index, so any previous selection in the list will be lost.
|
|
2821 * gtk does not provide a way to just set focus to a specified list item.
|
|
2822 */
|
|
2823 if (!(0 <= index && index < itemCount)) return;
|
|
2824 TableItem item = _getItem (index);
|
|
2825 auto path = OS.gtk_tree_model_get_path (modelHandle, item.handle);
|
|
2826 auto selection = OS.gtk_tree_view_get_selection (handle);
|
|
2827 OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2828 OS.gtk_tree_view_set_cursor (handle, path, null, false);
|
|
2829 /*
|
|
2830 * Bug in GTK. For some reason, when an event loop is run from
|
|
2831 * within a key pressed handler and a dialog is displayed that
|
|
2832 * contains a GtkTreeView, gtk_tree_view_set_cursor() does
|
|
2833 * not set the cursor or select the item. The fix is to select the
|
|
2834 * item with gtk_tree_selection_select_iter() as well.
|
|
2835 *
|
|
2836 * NOTE: This happens in GTK 2.2.1 and is fixed in GTK 2.2.4.
|
|
2837 */
|
|
2838 OS.gtk_tree_selection_select_iter (selection, item.handle);
|
|
2839 OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, null, null, udCHANGED);
|
|
2840 OS.gtk_tree_path_free (path);
|
|
2841 }
|
|
2842
|
|
2843 override void setBackgroundColor (GdkColor* color) {
|
|
2844 super.setBackgroundColor (color);
|
|
2845 OS.gtk_widget_modify_base (handle, 0, color);
|
|
2846 }
|
|
2847
|
|
2848 override void setBackgroundPixmap (GdkPixmap* pixmap) {
|
|
2849 super.setBackgroundPixmap (pixmap);
|
|
2850 auto window = paintWindow ();
|
|
2851 if (window !is null) OS.gdk_window_set_back_pixmap (window, null, true);
|
|
2852 }
|
|
2853
|
|
2854 override int setBounds (int x, int y, int width, int height, bool move, bool resize) {
|
|
2855 int result = super.setBounds (x, y, width, height, move, resize);
|
|
2856 /*
|
|
2857 * Bug on GTK. The tree view sometimes does not get a paint
|
|
2858 * event or resizes to a one pixel square when resized in a new
|
|
2859 * shell that is not visible after any event loop has been run. The
|
|
2860 * problem is intermittent. It doesn't seem to happen the first time
|
|
2861 * a new shell is created. The fix is to ensure the tree view is realized
|
|
2862 * after it has been resized.
|
|
2863 */
|
|
2864 OS.gtk_widget_realize (handle);
|
|
2865 /*
|
|
2866 * Bug in GTK. An empty GtkTreeView fails to repaint the focus rectangle
|
|
2867 * correctly when resized on versions before 2.6.0. The fix is to force
|
|
2868 * the widget to redraw.
|
|
2869 */
|
|
2870 if (OS.GTK_VERSION < OS.buildVERSION (2, 6, 0) && itemCount is 0) redraw (false);
|
|
2871 return result;
|
|
2872 }
|
|
2873
|
|
2874 /**
|
|
2875 * Sets the order that the items in the receiver should
|
|
2876 * be displayed in to the given argument which is described
|
|
2877 * in terms of the zero-relative ordering of when the items
|
|
2878 * were added.
|
|
2879 *
|
|
2880 * @param order the new order to display the items
|
|
2881 *
|
|
2882 * @exception SWTException <ul>
|
|
2883 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2884 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2885 * </ul>
|
|
2886 * @exception IllegalArgumentException <ul>
|
|
2887 * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
|
|
2888 * </ul>
|
|
2889 *
|
|
2890 * @see Table#getColumnOrder()
|
|
2891 * @see TableColumn#getMoveable()
|
|
2892 * @see TableColumn#setMoveable(bool)
|
|
2893 * @see SWT#Move
|
|
2894 *
|
|
2895 * @since 3.1
|
|
2896 */
|
|
2897 public void setColumnOrder (int [] order) {
|
|
2898 checkWidget ();
|
|
2899 // SWT extension: allow null for zero length string
|
|
2900 //if (order is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
2901 if (columnCount is 0) {
|
|
2902 if (order.length > 0) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
2903 return;
|
|
2904 }
|
|
2905 if (order.length !is columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
2906 bool [] seen = new bool [columnCount];
|
|
2907 for (int i = 0; i<order.length; i++) {
|
|
2908 int index = order [i];
|
|
2909 if (index < 0 || index >= columnCount) error (SWT.ERROR_INVALID_RANGE);
|
|
2910 if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
2911 seen [index] = true;
|
|
2912 }
|
|
2913 for (int i=0; i<order.length; i++) {
|
|
2914 auto column = columns [order [i]].handle;
|
|
2915 auto baseColumn = i is 0 ? null : columns [order [i-1]].handle;
|
|
2916 OS.gtk_tree_view_move_column_after (handle, column, baseColumn);
|
|
2917 }
|
|
2918 }
|
|
2919
|
|
2920 override void setFontDescription (PangoFontDescription* font) {
|
|
2921 super.setFontDescription (font);
|
|
2922 TableColumn[] columns = getColumns ();
|
|
2923 for (int i = 0; i < columns.length; i++) {
|
|
2924 if (columns[i] !is null) {
|
|
2925 columns[i].setFontDescription (font);
|
|
2926 }
|
|
2927 }
|
|
2928 }
|
|
2929
|
|
2930 /**
|
|
2931 * Marks the receiver's header as visible if the argument is <code>true</code>,
|
|
2932 * and marks it invisible otherwise.
|
|
2933 * <p>
|
|
2934 * If one of the receiver's ancestors is not visible or some
|
|
2935 * other condition makes the receiver not visible, marking
|
|
2936 * it visible may not actually cause it to be displayed.
|
|
2937 * </p>
|
|
2938 *
|
|
2939 * @param show the new visibility state
|
|
2940 *
|
|
2941 * @exception SWTException <ul>
|
|
2942 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2943 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2944 * </ul>
|
|
2945 */
|
|
2946 public void setHeaderVisible (bool show) {
|
|
2947 checkWidget ();
|
|
2948 OS.gtk_tree_view_set_headers_visible (handle, show);
|
|
2949 }
|
|
2950
|
|
2951 /**
|
|
2952 * Sets the number of items contained in the receiver.
|
|
2953 *
|
|
2954 * @param count the number of items
|
|
2955 *
|
|
2956 * @exception SWTException <ul>
|
|
2957 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
2958 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
2959 * </ul>
|
|
2960 *
|
|
2961 * @since 3.0
|
|
2962 */
|
|
2963 public void setItemCount (int count) {
|
|
2964 checkWidget ();
|
|
2965 count = Math.max (0, count);
|
|
2966 if (count is itemCount) return;
|
|
2967 bool isVirtual = (style & SWT.VIRTUAL) !is 0;
|
|
2968 if (!isVirtual) setRedraw (false);
|
|
2969 remove (count, itemCount - 1);
|
|
2970 int length = Math.max (4, (count + 3) / 4 * 4);
|
|
2971 TableItem [] newItems = new TableItem [length];
|
|
2972 System.arraycopy (items, 0, newItems, 0, itemCount);
|
|
2973 items = newItems;
|
|
2974 if (isVirtual) {
|
|
2975 GtkTreeIter iter;
|
|
2976 for (int i=itemCount; i<count; i++) {
|
|
2977 OS.gtk_list_store_append (modelHandle, &iter);
|
|
2978 }
|
|
2979 itemCount = count;
|
|
2980 } else {
|
|
2981 for (int i=itemCount; i<count; i++) {
|
|
2982 new TableItem (this, SWT.NONE, i, true);
|
|
2983 }
|
|
2984 }
|
|
2985 if (!isVirtual) setRedraw (true);
|
|
2986 }
|
|
2987
|
|
2988 /**
|
|
2989 * Marks the receiver's lines as visible if the argument is <code>true</code>,
|
|
2990 * and marks it invisible otherwise.
|
|
2991 * <p>
|
|
2992 * If one of the receiver's ancestors is not visible or some
|
|
2993 * other condition makes the receiver not visible, marking
|
|
2994 * it visible may not actually cause it to be displayed.
|
|
2995 * </p>
|
|
2996 *
|
|
2997 * @param show the new visibility state
|
|
2998 *
|
|
2999 * @exception SWTException <ul>
|
|
3000 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3001 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3002 * </ul>
|
|
3003 */
|
|
3004 public void setLinesVisible (bool show) {
|
|
3005 checkWidget();
|
|
3006 OS.gtk_tree_view_set_rules_hint (handle, show);
|
|
3007 }
|
|
3008
|
|
3009 override void setParentBackground () {
|
|
3010 super.setParentBackground ();
|
|
3011 auto window = paintWindow ();
|
|
3012 if (window !is null) OS.gdk_window_set_back_pixmap (window, null, true);
|
|
3013 }
|
|
3014
|
|
3015 override void setParentWindow (GtkWidget* widget) {
|
|
3016 auto window = eventWindow ();
|
|
3017 OS.gtk_widget_set_parent_window (widget, window);
|
|
3018 }
|
|
3019
|
|
3020 override public void setRedraw (bool redraw) {
|
|
3021 checkWidget();
|
|
3022 super.setRedraw (redraw);
|
|
3023 if (redraw && drawCount is 0) {
|
|
3024 /* Resize the item array to match the item count */
|
|
3025 if (items.length > 4 && items.length - itemCount > 3) {
|
|
3026 int length = Math.max (4, (itemCount + 3) / 4 * 4);
|
|
3027 TableItem [] newItems = new TableItem [length];
|
|
3028 System.arraycopy (items, 0, newItems, 0, itemCount);
|
|
3029 items = newItems;
|
|
3030 }
|
|
3031 }
|
|
3032 }
|
|
3033
|
|
3034 void setScrollWidth (GtkTreeViewColumn* column, TableItem item) {
|
|
3035 if (columnCount !is 0 || currentItem is item) return;
|
|
3036 /*
|
|
3037 * Use GTK_TREE_VIEW_COLUMN_GROW_ONLY on GTK versions < 2.3.2
|
|
3038 * because fixed_height_mode is not supported.
|
|
3039 */
|
|
3040 if (((style & SWT.VIRTUAL) !is 0) && OS.GTK_VERSION < OS.buildVERSION (2, 3, 2)) return;
|
|
3041 int width = OS.gtk_tree_view_column_get_fixed_width (column);
|
|
3042 int itemWidth = calculateWidth (column, cast(GtkTreeIter*)item.handle);
|
|
3043 if (width < itemWidth) {
|
|
3044 OS.gtk_tree_view_column_set_fixed_width (column, itemWidth);
|
|
3045 }
|
|
3046 }
|
|
3047
|
|
3048 /**
|
|
3049 * Sets the column used by the sort indicator for the receiver. A null
|
|
3050 * value will clear the sort indicator. The current sort column is cleared
|
|
3051 * before the new column is set.
|
|
3052 *
|
|
3053 * @param column the column used by the sort indicator or <code>null</code>
|
|
3054 *
|
|
3055 * @exception IllegalArgumentException <ul>
|
|
3056 * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
|
|
3057 * </ul>
|
|
3058 * @exception SWTException <ul>
|
|
3059 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3060 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3061 * </ul>
|
|
3062 *
|
|
3063 * @since 3.2
|
|
3064 */
|
|
3065 public void setSortColumn (TableColumn column) {
|
|
3066 checkWidget ();
|
|
3067 if (column !is null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
3068 if (sortColumn !is null && !sortColumn.isDisposed()) {
|
|
3069 OS.gtk_tree_view_column_set_sort_indicator (sortColumn.handle, false);
|
|
3070 }
|
|
3071 sortColumn = column;
|
|
3072 if (sortColumn !is null && sortDirection !is SWT.NONE) {
|
|
3073 OS.gtk_tree_view_column_set_sort_indicator (sortColumn.handle, true);
|
|
3074 OS.gtk_tree_view_column_set_sort_order (sortColumn.handle, sortDirection is SWT.DOWN ? 0 : 1);
|
|
3075 }
|
|
3076 }
|
|
3077
|
|
3078 /**
|
|
3079 * Sets the direction of the sort indicator for the receiver. The value
|
|
3080 * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
|
|
3081 *
|
|
3082 * @param direction the direction of the sort indicator
|
|
3083 *
|
|
3084 * @exception SWTException <ul>
|
|
3085 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3086 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3087 * </ul>
|
|
3088 *
|
|
3089 * @since 3.2
|
|
3090 */
|
|
3091 public void setSortDirection (int direction) {
|
|
3092 checkWidget ();
|
|
3093 if (direction !is SWT.UP && direction !is SWT.DOWN && direction !is SWT.NONE) return;
|
|
3094 sortDirection = direction;
|
|
3095 if (sortColumn is null || sortColumn.isDisposed ()) return;
|
|
3096 if (sortDirection is SWT.NONE) {
|
|
3097 OS.gtk_tree_view_column_set_sort_indicator (sortColumn.handle, false);
|
|
3098 } else {
|
|
3099 OS.gtk_tree_view_column_set_sort_indicator (sortColumn.handle, true);
|
|
3100 OS.gtk_tree_view_column_set_sort_order (sortColumn.handle, sortDirection is SWT.DOWN ? 0 : 1);
|
|
3101 }
|
|
3102 }
|
|
3103
|
|
3104 /**
|
|
3105 * Selects the item at the given zero-relative index in the receiver.
|
|
3106 * The current selection is first cleared, then the new item is selected.
|
|
3107 *
|
|
3108 * @param index the index of the item to select
|
|
3109 *
|
|
3110 * @exception SWTException <ul>
|
|
3111 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3112 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3113 * </ul>
|
|
3114 *
|
|
3115 * @see Table#deselectAll()
|
|
3116 * @see Table#selectcast(int)
|
|
3117 */
|
|
3118 public void setSelection (int index) {
|
|
3119 checkWidget ();
|
|
3120 bool fixColumn = showFirstColumn ();
|
|
3121 deselectAll ();
|
|
3122 selectFocusIndex (index);
|
|
3123 showSelection ();
|
|
3124 if (fixColumn) hideFirstColumn ();
|
|
3125 }
|
|
3126
|
|
3127 /**
|
|
3128 * Selects the items in the range specified by the given zero-relative
|
|
3129 * indices in the receiver. The range of indices is inclusive.
|
|
3130 * The current selection is cleared before the new items are selected.
|
|
3131 * <p>
|
|
3132 * Indices that are out of range are ignored and no items will be selected
|
|
3133 * if start is greater than end.
|
|
3134 * If the receiver is single-select and there is more than one item in the
|
|
3135 * given range, then all indices are ignored.
|
|
3136 * </p>
|
|
3137 *
|
|
3138 * @param start the start index of the items to select
|
|
3139 * @param end the end index of the items to select
|
|
3140 *
|
|
3141 * @exception SWTException <ul>
|
|
3142 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3143 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3144 * </ul>
|
|
3145 *
|
|
3146 * @see Table#deselectAll()
|
|
3147 * @see Table#select(int,int)
|
|
3148 */
|
|
3149 public void setSelection (int start, int end) {
|
|
3150 checkWidget ();
|
|
3151 deselectAll();
|
|
3152 if (end < 0 || start > end || ((style & SWT.SINGLE) !is 0 && start !is end)) return;
|
|
3153 if (itemCount is 0 || start >= itemCount) return;
|
|
3154 bool fixColumn = showFirstColumn ();
|
|
3155 start = Math.max (0, start);
|
|
3156 end = Math.min (end, itemCount - 1);
|
|
3157 selectFocusIndex (start);
|
|
3158 if ((style & SWT.MULTI) !is 0) {
|
|
3159 select (start, end);
|
|
3160 }
|
|
3161 showSelection ();
|
|
3162 if (fixColumn) hideFirstColumn ();
|
|
3163 }
|
|
3164
|
|
3165 /**
|
|
3166 * Selects the items at the given zero-relative indices in the receiver.
|
|
3167 * The current selection is cleared before the new items are selected.
|
|
3168 * <p>
|
|
3169 * Indices that are out of range and duplicate indices are ignored.
|
|
3170 * If the receiver is single-select and multiple indices are specified,
|
|
3171 * then all indices are ignored.
|
|
3172 * </p>
|
|
3173 *
|
|
3174 * @param indices the indices of the items to select
|
|
3175 *
|
|
3176 * @exception SWTException <ul>
|
|
3177 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3178 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3179 * </ul>
|
|
3180 *
|
|
3181 * @see Table#deselectAll()
|
|
3182 * @see Table#select(int[])
|
|
3183 */
|
|
3184 public void setSelection (int [] indices) {
|
|
3185 checkWidget ();
|
|
3186 // SWT extension: allow null for zero length string
|
|
3187 //if (indices is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
3188 deselectAll ();
|
|
3189 int length = indices.length;
|
|
3190 if (length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1)) return;
|
|
3191 bool fixColumn = showFirstColumn ();
|
|
3192 selectFocusIndex (indices [0]);
|
|
3193 if ((style & SWT.MULTI) !is 0) {
|
|
3194 select (indices);
|
|
3195 }
|
|
3196 showSelection ();
|
|
3197 if (fixColumn) hideFirstColumn ();
|
|
3198 }
|
|
3199
|
|
3200 /**
|
|
3201 * Sets the receiver's selection to the given item.
|
|
3202 * The current selection is cleared before the new item is selected.
|
|
3203 * <p>
|
|
3204 * If the item is not in the receiver, then it is ignored.
|
|
3205 * </p>
|
|
3206 *
|
|
3207 * @param item the item to select
|
|
3208 *
|
|
3209 * @exception IllegalArgumentException <ul>
|
|
3210 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
|
|
3211 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
|
|
3212 * </ul>
|
|
3213 * @exception SWTException <ul>
|
|
3214 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3215 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3216 * </ul>
|
|
3217 *
|
|
3218 * @since 3.2
|
|
3219 */
|
|
3220 public void setSelection (TableItem item) {
|
|
3221 if (item is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
3222 setSelection ( [item] );
|
|
3223 }
|
|
3224
|
|
3225
|
|
3226 /**
|
|
3227 * Sets the receiver's selection to be the given array of items.
|
|
3228 * The current selection is cleared before the new items are selected.
|
|
3229 * <p>
|
|
3230 * Items that are not in the receiver are ignored.
|
|
3231 * If the receiver is single-select and multiple items are specified,
|
|
3232 * then all items are ignored.
|
|
3233 * </p>
|
|
3234 *
|
|
3235 * @param items the array of items
|
|
3236 *
|
|
3237 * @exception IllegalArgumentException <ul>
|
|
3238 * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
|
|
3239 * </ul>
|
|
3240 * @exception SWTException <ul>
|
|
3241 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3242 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3243 * </ul>
|
|
3244 *
|
|
3245 * @see Table#deselectAll()
|
|
3246 * @see Table#select(int[])
|
|
3247 * @see Table#setSelection(int[])
|
|
3248 */
|
|
3249 public void setSelection (TableItem [] items) {
|
|
3250 checkWidget ();
|
|
3251 // SWT extension: allow null for zero length string
|
|
3252 //if (items is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
3253 bool fixColumn = showFirstColumn ();
|
|
3254 deselectAll ();
|
|
3255 int length = items.length;
|
|
3256 if (!(length is 0 || ((style & SWT.SINGLE) !is 0 && length > 1))) {
|
|
3257 bool first = true;
|
|
3258 for (int i = 0; i < length; i++) {
|
|
3259 int index = indexOf (items [i]);
|
|
3260 if (index !is -1) {
|
|
3261 if (first) {
|
|
3262 first = false;
|
|
3263 selectFocusIndex (index);
|
|
3264 } else {
|
|
3265 select (index);
|
|
3266 }
|
|
3267 }
|
|
3268 }
|
|
3269 showSelection ();
|
|
3270 }
|
|
3271 if (fixColumn) hideFirstColumn ();
|
|
3272 }
|
|
3273
|
|
3274 /**
|
|
3275 * Sets the zero-relative index of the item which is currently
|
|
3276 * at the top of the receiver. This index can change when items
|
|
3277 * are scrolled or new items are added and removed.
|
|
3278 *
|
|
3279 * @param index the index of the top item
|
|
3280 *
|
|
3281 * @exception SWTException <ul>
|
|
3282 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3283 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3284 * </ul>
|
|
3285 */
|
|
3286 public void setTopIndex (int index) {
|
|
3287 checkWidget();
|
|
3288 if (!(0 <= index && index < itemCount)) return;
|
|
3289 auto path = OS.gtk_tree_model_get_path (modelHandle, _getItem (index).handle);
|
|
3290 OS.gtk_tree_view_scroll_to_cell (handle, path, null, true, 0f, 0f);
|
|
3291 if (OS.GTK_VERSION < OS.buildVERSION (2, 8, 0)) {
|
|
3292 /*
|
|
3293 * Bug in GTK. According to the documentation, gtk_tree_view_scroll_to_cell
|
|
3294 * should vertically scroll the cell to the top if use_align is true and row_align is 0.
|
|
3295 * However, prior to version 2.8 it does not scroll at all. The fix is to determine
|
|
3296 * the new location and use gtk_tree_view_scroll_to_point.
|
|
3297 * If the widget is a pinhead, calling gtk_tree_view_scroll_to_point
|
|
3298 * will have no effect. Therefore, it is still neccessary to call
|
|
3299 * gtk_tree_view_scroll_to_cell.
|
|
3300 */
|
|
3301 OS.gtk_widget_realize (handle);
|
|
3302 GdkRectangle cellRect;
|
|
3303 OS.gtk_tree_view_get_cell_area (handle, path, null, &cellRect);
|
|
3304 int tx, ty;
|
|
3305 OS.gtk_tree_view_widget_to_tree_coords(handle, cellRect.x, cellRect.y, &tx, &ty);
|
|
3306 OS.gtk_tree_view_scroll_to_point (handle, -1, ty);
|
|
3307 }
|
|
3308 OS.gtk_tree_path_free (path);
|
|
3309 }
|
|
3310
|
|
3311 /**
|
|
3312 * Shows the column. If the column is already showing in the receiver,
|
|
3313 * this method simply returns. Otherwise, the columns are scrolled until
|
|
3314 * the column is visible.
|
|
3315 *
|
|
3316 * @param column the column to be shown
|
|
3317 *
|
|
3318 * @exception IllegalArgumentException <ul>
|
|
3319 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
|
|
3320 * <li>ERROR_INVALID_ARGUMENT - if the column has been disposed</li>
|
|
3321 * </ul>
|
|
3322 * @exception SWTException <ul>
|
|
3323 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3324 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3325 * </ul>
|
|
3326 *
|
|
3327 * @since 3.0
|
|
3328 */
|
|
3329 public void showColumn (TableColumn column) {
|
|
3330 checkWidget ();
|
|
3331 if (column is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
3332 if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
|
|
3333 if (column.parent !is this) return;
|
|
3334 /*
|
|
3335 * This code is intentionally commented. According to the
|
|
3336 * documentation, gtk_tree_view_scroll_to_cell should scroll the
|
|
3337 * minimum amount to show the column but instead it scrolls strangely.
|
|
3338 */
|
|
3339 //OS.gtk_tree_view_scroll_to_cell (handle, 0, column.handle, false, 0, 0);
|
|
3340 OS.gtk_widget_realize (handle);
|
|
3341 GdkRectangle cellRect;
|
|
3342 OS.gtk_tree_view_get_cell_area (handle, null, column.handle, &cellRect);
|
|
3343 GdkRectangle visibleRect;
|
|
3344 OS.gtk_tree_view_get_visible_rect (handle, &visibleRect);
|
|
3345 if (cellRect.x < visibleRect.x) {
|
|
3346 OS.gtk_tree_view_scroll_to_point (handle, cellRect.x, -1);
|
|
3347 } else {
|
|
3348 int width = Math.min (visibleRect.width, cellRect.width);
|
|
3349 if (cellRect.x + width > visibleRect.x + visibleRect.width) {
|
|
3350 int tree_x = cellRect.x + width - visibleRect.width;
|
|
3351 OS.gtk_tree_view_scroll_to_point (handle, tree_x, -1);
|
|
3352 }
|
|
3353 }
|
|
3354 }
|
|
3355
|
|
3356 bool showFirstColumn () {
|
|
3357 /*
|
|
3358 * Bug in GTK. If no columns are visible, changing the selection
|
|
3359 * will fail. The fix is to temporarily make a column visible.
|
|
3360 */
|
|
3361 int columnCount = Math.max (1, this.columnCount);
|
|
3362 for (int i=0; i<columnCount; i++) {
|
|
3363 auto column = OS.gtk_tree_view_get_column (handle, i);
|
|
3364 if (OS.gtk_tree_view_column_get_visible (column)) return false;
|
|
3365 }
|
|
3366 auto firstColumn = OS.gtk_tree_view_get_column (handle, 0);
|
|
3367 OS.gtk_tree_view_column_set_visible (firstColumn, true);
|
|
3368 return true;
|
|
3369 }
|
|
3370
|
|
3371 /**
|
|
3372 * Shows the item. If the item is already showing in the receiver,
|
|
3373 * this method simply returns. Otherwise, the items are scrolled until
|
|
3374 * the item is visible.
|
|
3375 *
|
|
3376 * @param item the item to be shown
|
|
3377 *
|
|
3378 * @exception IllegalArgumentException <ul>
|
|
3379 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
|
|
3380 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
|
|
3381 * </ul>
|
|
3382 * @exception SWTException <ul>
|
|
3383 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3384 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3385 * </ul>
|
|
3386 *
|
|
3387 * @see Table#showSelection()
|
|
3388 */
|
|
3389 public void showItem (TableItem item) {
|
|
3390 checkWidget ();
|
|
3391 if (item is null) error (SWT.ERROR_NULL_ARGUMENT);
|
|
3392 if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
|
|
3393 if (item.parent !is this) return;
|
|
3394 showItem (cast(GtkTreeIter*)item.handle);
|
|
3395 }
|
|
3396
|
|
3397 void showItem (GtkTreeIter* iter) {
|
|
3398 auto path = OS.gtk_tree_model_get_path (modelHandle, iter);
|
|
3399 /*
|
|
3400 * This code intentionally commented.
|
|
3401 * Bug in GTK. According to the documentation, gtk_tree_view_scroll_to_cell
|
|
3402 * should scroll the minimum amount to show the cell if use_align is false.
|
|
3403 * However, what actually happens is the cell is scrolled to the top.
|
|
3404 * The fix is to determine the new location and use gtk_tree_view_scroll_to_point.
|
|
3405 * If the widget is a pinhead, calling gtk_tree_view_scroll_to_point
|
|
3406 * will have no effect. Therefore, it is still neccessary to
|
|
3407 * call gtk_tree_view_scroll_to_cell.
|
|
3408 */
|
|
3409 // OS.gtk_tree_view_scroll_to_cell (handle, path, 0, false, 0, 0);
|
|
3410 OS.gtk_widget_realize (handle);
|
|
3411 GdkRectangle visibleRect;
|
|
3412 OS.gtk_tree_view_get_visible_rect (handle, &visibleRect);
|
|
3413 GdkRectangle cellRect;
|
|
3414 OS.gtk_tree_view_get_cell_area (handle, path, null, &cellRect);
|
|
3415 int tx, ty;
|
|
3416 OS.gtk_tree_view_widget_to_tree_coords(handle, cellRect.x, cellRect.y, &tx, &ty);
|
|
3417 if (ty < visibleRect.y ) {
|
|
3418 OS.gtk_tree_view_scroll_to_cell (handle, path, null, true, 0f, 0f);
|
|
3419 OS.gtk_tree_view_scroll_to_point (handle, -1, ty);
|
|
3420 } else {
|
|
3421 int height = Math.min (visibleRect.height, cellRect.height);
|
|
3422 if (ty + height > visibleRect.y + visibleRect.height) {
|
|
3423 OS.gtk_tree_view_scroll_to_cell (handle, path, null, true, 1f, 0f);
|
|
3424 ty += cellRect.height - visibleRect.height;
|
|
3425 OS.gtk_tree_view_scroll_to_point (handle, -1, ty);
|
|
3426 }
|
|
3427 }
|
|
3428 OS.gtk_tree_path_free (path);
|
|
3429 }
|
|
3430
|
|
3431 /**
|
|
3432 * Shows the selection. If the selection is already showing in the receiver,
|
|
3433 * this method simply returns. Otherwise, the items are scrolled until
|
|
3434 * the selection is visible.
|
|
3435 *
|
|
3436 * @exception SWTException <ul>
|
|
3437 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
|
|
3438 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
|
|
3439 * </ul>
|
|
3440 *
|
|
3441 * @see Table#showItem(TableItem)
|
|
3442 */
|
|
3443 public void showSelection () {
|
|
3444 checkWidget();
|
|
3445 TableItem [] selection = getSelection ();
|
|
3446 if (selection.length is 0) return;
|
|
3447 TableItem item = selection [0];
|
|
3448 showItem (cast(GtkTreeIter*)item.handle);
|
|
3449 }
|
|
3450
|
|
3451 override void treeSelectionProc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, int[] selection, int length_) {
|
|
3452 if (selection !is null) {
|
|
3453 auto indices = OS.gtk_tree_path_get_indices (path);
|
|
3454 if (indices !is null) {
|
|
3455 selection [length_] = indices [0];
|
|
3456 }
|
|
3457 }
|
|
3458 }
|
|
3459
|
|
3460 override void updateScrollBarValue (ScrollBar bar) {
|
|
3461 super.updateScrollBarValue (bar);
|
|
3462 /*
|
|
3463 * Bug in GTK. Scrolling changes the XWindow position
|
|
3464 * and makes the child widgets appear to scroll even
|
|
3465 * though when queried their position is unchanged.
|
|
3466 * The fix is to queue a resize event for each child to
|
|
3467 * force the position to be corrected.
|
|
3468 */
|
|
3469 auto parentHandle = parentingHandle ();
|
|
3470 auto list = OS.gtk_container_get_children (parentHandle);
|
|
3471 if (list is null) return;
|
|
3472 auto temp = list;
|
|
3473 while (temp !is null) {
|
|
3474 auto widget = OS.g_list_data (temp);
|
|
3475 if (widget !is null) OS.gtk_widget_queue_resize (widget);
|
|
3476 temp = OS.g_list_next (temp);
|
|
3477 }
|
|
3478 OS.g_list_free (list);
|
|
3479 }
|
|
3480
|
|
3481 }
|