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