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.TableItem;
14 
15 import java.lang.all;
16 
17 
18 
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.SWTException;
21 import org.eclipse.swt.graphics.Color;
22 import org.eclipse.swt.graphics.Font;
23 import org.eclipse.swt.graphics.Image;
24 import org.eclipse.swt.graphics.Rectangle;
25 import org.eclipse.swt.internal.gtk.OS;
26 import org.eclipse.swt.widgets.Item;
27 import org.eclipse.swt.widgets.Table;
28 import org.eclipse.swt.widgets.ImageList;
29 import org.eclipse.swt.widgets.TreeItem;
30 
31 
32 /**
33  * Instances of this class represent a selectable user interface object
34  * that represents an item in a table.
35  * <dl>
36  * <dt><b>Styles:</b></dt>
37  * <dd>(none)</dd>
38  * <dt><b>Events:</b></dt>
39  * <dd>(none)</dd>
40  * </dl>
41  * <p>
42  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
43  * </p>
44  *
45  * @see <a href="http://www.eclipse.org/swt/snippets/#table">Table, TableItem, TableColumn snippets</a>
46  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
47  */
48 public class TableItem : Item {
49     Table parent;
50     Font font;
51     Font[] cellFont;
52     bool cached, grayed;
53 
54 /**
55  * Constructs a new instance of this class given its parent
56  * (which must be a <code>Table</code>), a style value
57  * describing its behavior and appearance, and the index
58  * at which to place it in the items maintained by its parent.
59  * <p>
60  * The style value is either one of the style constants defined in
61  * class <code>SWT</code> which is applicable to instances of this
62  * class, or must be built by <em>bitwise OR</em>'ing together
63  * (that is, using the <code>int</code> "|" operator) two or more
64  * of those <code>SWT</code> style constants. The class description
65  * lists the style constants that are applicable to the class.
66  * Style bits are also inherited from superclasses.
67  * </p>
68  *
69  * @param parent a composite control which will be the parent of the new instance (cannot be null)
70  * @param style the style of control to construct
71  * @param index the zero-relative index to store the receiver in its parent
72  *
73  * @exception IllegalArgumentException <ul>
74  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
75  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
76  * </ul>
77  * @exception SWTException <ul>
78  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
79  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
80  * </ul>
81  *
82  * @see SWT
83  * @see Widget#checkSubclass
84  * @see Widget#getStyle
85  */
86 public this (Table parent, int style, int index) {
87     this (parent, style, index, true);
88 }
89 
90 /**
91  * Constructs a new instance of this class given its parent
92  * (which must be a <code>Table</code>) and a style value
93  * describing its behavior and appearance. The item is added
94  * to the end of the items maintained by its parent.
95  * <p>
96  * The style value is either one of the style constants defined in
97  * class <code>SWT</code> which is applicable to instances of this
98  * class, or must be built by <em>bitwise OR</em>'ing together
99  * (that is, using the <code>int</code> "|" operator) two or more
100  * of those <code>SWT</code> style constants. The class description
101  * lists the style constants that are applicable to the class.
102  * Style bits are also inherited from superclasses.
103  * </p>
104  *
105  * @param parent a composite control which will be the parent of the new instance (cannot be null)
106  * @param style the style of control to construct
107  *
108  * @exception IllegalArgumentException <ul>
109  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
110  * </ul>
111  * @exception SWTException <ul>
112  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
113  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
114  * </ul>
115  *
116  * @see SWT
117  * @see Widget#checkSubclass
118  * @see Widget#getStyle
119  */
120 public this (Table parent, int style) {
121     this (parent, style, checkNull (parent).getItemCount (), true);
122 }
123 
124 
125 this (Table parent, int style, int index, bool create) {
126     super (parent, style);
127     this.parent = parent;
128     if (create) {
129         parent.createItem (this, index);
130     } else {
131         handle = cast(GtkWidget*)OS.g_malloc (GtkTreeIter.sizeof);
132         OS.gtk_tree_model_iter_nth_child (parent.modelHandle, handle, null, index);
133     }
134 }
135 
136 static Table checkNull (Table control) {
137     if (control is null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
138     return control;
139 }
140 
141 Color _getBackground () {
142     void* ptr;
143     OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.BACKGROUND_COLUMN, &ptr);
144     if (ptr is null) return parent.getBackground ();
145     GdkColor* gdkColor = new GdkColor ();
146     *gdkColor = *cast(GdkColor*) ptr;
147     return Color.gtk_new (display, gdkColor);
148 }
149 
150 Color _getBackground (int index) {
151     int count = Math.max (1, parent.columnCount);
152     if (0 > index || index > count - 1) return _getBackground ();
153     void* ptr;
154     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
155     OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_BACKGROUND, &ptr);
156     if (ptr is null) return _getBackground ();
157     GdkColor* gdkColor = new GdkColor ();
158     *gdkColor = *cast(GdkColor*) ptr;
159     return Color.gtk_new (display, gdkColor);
160 }
161 
162 bool _getChecked () {
163     void* ptr;
164     OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, &ptr);
165     return ptr !is null;
166 }
167 
168 Color _getForeground () {
169     void* ptr;
170     OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.FOREGROUND_COLUMN, &ptr);
171     if (ptr is null) return parent.getForeground ();
172     GdkColor* gdkColor = new GdkColor ();
173     *gdkColor = *cast(GdkColor*) ptr;
174     return Color.gtk_new (display, gdkColor);
175 }
176 
177 Color _getForeground (int index) {
178     int count = Math.max (1, parent.columnCount);
179     if (0 > index || index > count - 1) return _getForeground ();
180     void* ptr;
181     int modelIndex =  parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
182     OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_FOREGROUND, &ptr);
183     if (ptr is null) return _getForeground ();
184     GdkColor* gdkColor = new GdkColor ();
185     *gdkColor = *cast(GdkColor*) ptr;
186     return Color.gtk_new (display, gdkColor);
187 }
188 
189 Image _getImage (int index) {
190     int count = Math.max (1, parent.getColumnCount ());
191     if (0 > index || index > count - 1) return null;
192     void* ptr;
193     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
194     OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_PIXBUF, &ptr);
195     if (ptr is null) return null;
196     ImageList imageList = parent.imageList;
197     int imageIndex = imageList.indexOf (ptr);
198     if (imageIndex is -1) return null;
199     return imageList.get (imageIndex);
200 }
201 
202 String _getText (int index) {
203     int count = Math.max (1, parent.getColumnCount ());
204     if (0 > index || index > count - 1) return "";
205     void* ptr;
206     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
207     OS.gtk_tree_model_get1 (parent.modelHandle, handle, modelIndex + Table.CELL_TEXT, &ptr);
208     if (ptr is null) return "";
209     String buffer = fromStringz( cast(char*)ptr)._idup();
210     OS.g_free (ptr);
211     return buffer;
212 }
213 
214 protected override void checkSubclass () {
215     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
216 }
217 
218 void clear () {
219     if (parent.currentItem is this) return;
220     if (cached || (parent.style & SWT.VIRTUAL) is 0) {
221         int columnCount = OS.gtk_tree_model_get_n_columns (parent.modelHandle);
222         for (int i=0; i<columnCount; i++) {
223             OS.gtk_list_store_set1 (parent.modelHandle, handle, i, null);
224         }
225         /*
226         * Bug in GTK.  When using fixed-height-mode,
227         * row changes do not cause the row to be repainted.  The fix is to
228         * invalidate the row when it is cleared.
229         */
230         if ((parent.style & SWT.VIRTUAL) !is 0) {
231             if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
232                 redraw ();
233             }
234         }
235     }
236     cached = false;
237     font = null;
238     cellFont = null;
239 }
240 
241 override void destroyWidget () {
242     parent.destroyItem (this);
243     releaseHandle ();
244 }
245 
246 /**
247  * Returns the receiver's background color.
248  *
249  * @return the background color
250  *
251  * @exception SWTException <ul>
252  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
254  * </ul>
255  *
256  * @since 2.0
257  */
258 public Color getBackground () {
259     checkWidget ();
260     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
261     return _getBackground ();
262 }
263 
264 /**
265  * Returns a rectangle describing the receiver's size and location
266  * relative to its parent.
267  *
268  * @return the receiver's bounding rectangle
269  *
270  * @exception SWTException <ul>
271  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
272  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
273  * </ul>
274  *
275  * @since 3.2
276  */
277 public Rectangle getBounds () {
278     // TODO fully test on early and later versions of GTK
279     // shifted a bit too far right on later versions of GTK - however, old Tree also had this problem
280     checkWidget ();
281     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
282     auto parentHandle = parent.handle;
283     auto column = OS.gtk_tree_view_get_column (parentHandle, 0);
284     if (column is null) return new Rectangle (0, 0, 0, 0);
285     auto textRenderer = parent.getTextRenderer (column);
286     auto pixbufRenderer = parent.getPixbufRenderer (column);
287     if (textRenderer is null || pixbufRenderer is null)  return new Rectangle (0, 0, 0, 0);
288 
289     auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
290     OS.gtk_widget_realize (parentHandle);
291 
292     bool isExpander = OS.gtk_tree_model_iter_n_children (parent.modelHandle, handle) > 0;
293     bool isExpanded = cast(bool)OS.gtk_tree_view_row_expanded (parentHandle, path);
294     OS.gtk_tree_view_column_cell_set_cell_data (column, parent.modelHandle, handle, isExpander, isExpanded);
295 
296     GdkRectangle rect;
297     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
298     OS.gtk_tree_path_free (path);
299     if ((parent.getStyle () & SWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
300     int right = rect.x + rect.width;
301 
302     int x, w;
303     parent.ignoreSize = true;
304     OS.gtk_cell_renderer_get_size (textRenderer, parentHandle, null, null, null, &w, null);
305     parent.ignoreSize = false;
306     rect.width = w;
307     int buffer;
308     if (OS.gtk_tree_view_get_expander_column (parentHandle) is column) {
309         OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &buffer);
310         rect.x += buffer + TreeItem.EXPANDER_EXTRA_PADDING;
311     }
312     OS.gtk_widget_style_get1 (parentHandle, OS.horizontal_separator.ptr, &buffer);
313     int horizontalSeparator = buffer;
314     rect.x += horizontalSeparator;
315 
316     if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
317         OS.gtk_tree_view_column_cell_get_position (column, textRenderer, &x, null);
318         rect.x += x;
319     } else {
320         if ((parent.style & SWT.CHECK) !is 0) {
321             OS.gtk_cell_renderer_get_size (parent.checkRenderer, parentHandle, null, null, null, &w, null);
322             rect.x += w + horizontalSeparator;
323         }
324         OS.gtk_cell_renderer_get_size (pixbufRenderer, parentHandle, null, null, null, &w, null);
325         rect.x += w + horizontalSeparator;
326     }
327     if (parent.columnCount > 0) {
328         if (rect.x + rect.width > right) {
329             rect.width = Math.max (0, right - rect.x);
330         }
331     }
332     int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
333     return new Rectangle (rect.x, rect.y, width, rect.height + 1);
334 }
335 
336 /**
337  * Returns the background color at the given column index in the receiver.
338  *
339  * @param index the column index
340  * @return the background color
341  *
342  * @exception SWTException <ul>
343  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
344  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
345  * </ul>
346  *
347  * @since 3.0
348  */
349 public Color getBackground (int index) {
350     checkWidget ();
351     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
352     return _getBackground (index);
353 }
354 
355 /**
356  * Returns a rectangle describing the receiver's size and location
357  * relative to its parent at a column in the table.
358  *
359  * @param index the index that specifies the column
360  * @return the receiver's bounding column rectangle
361  *
362  * @exception SWTException <ul>
363  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
364  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
365  * </ul>
366  */
367 public Rectangle getBounds (int index) {
368     checkWidget();
369     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
370     auto parentHandle = parent.handle;
371     GtkTreeViewColumn* column;
372     if (index >= 0 && index < parent.columnCount) {
373         column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
374     } else {
375         column = OS.gtk_tree_view_get_column (parentHandle, index);
376     }
377     if (column is null) return new Rectangle (0, 0, 0, 0);
378     auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
379     OS.gtk_widget_realize (parentHandle);
380     GdkRectangle rect;
381     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
382     OS.gtk_tree_path_free (path);
383     if ((parent.getStyle () & SWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
384 
385     if (index is 0 && (parent.style & SWT.CHECK) !is 0) {
386         if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
387             int x, w;
388             OS.gtk_tree_view_column_cell_get_position (column, parent.checkRenderer, &x, &w);
389             rect.x += x + w;
390             rect.width -= x + w;
391         } else {
392             int w;
393             OS.gtk_cell_renderer_get_size (parent.checkRenderer, parentHandle, null, null, null, &w, null);
394             int buffer;
395             OS.gtk_widget_style_get1 (parentHandle, OS.horizontal_separator.ptr, &buffer);
396             rect.x += w + buffer;
397             rect.width -= w + buffer;
398         }
399     }
400     int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
401     return new Rectangle (rect.x, rect.y, width, rect.height + 1);
402 }
403 
404 /**
405  * Returns <code>true</code> if the receiver is checked,
406  * and false otherwise.  When the parent does not have
407  * the <code>CHECK</code> style, return false.
408  *
409  * @return the checked state of the checkbox
410  *
411  * @exception SWTException <ul>
412  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
413  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
414  * </ul>
415  */
416 public bool getChecked () {
417     checkWidget();
418     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
419     if ((parent.style & SWT.CHECK) is 0) return false;
420     return _getChecked ();
421 }
422 
423 /**
424  * Returns the font that the receiver will use to paint textual information for this item.
425  *
426  * @return the receiver's font
427  *
428  * @exception SWTException <ul>
429  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
430  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
431  * </ul>
432  *
433  * @since 3.0
434  */
435 public Font getFont () {
436     checkWidget ();
437     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
438     return font !is null ? font : parent.getFont ();
439 }
440 
441 /**
442  * Returns the font that the receiver will use to paint textual information
443  * for the specified cell in this item.
444  *
445  * @param index the column index
446  * @return the receiver's font
447  *
448  * @exception SWTException <ul>
449  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
450  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
451  * </ul>
452  *
453  * @since 3.0
454  */
455 public Font getFont (int index) {
456     checkWidget ();
457     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
458     int count = Math.max (1, parent.columnCount);
459     if (0 > index || index > count - 1) return getFont ();
460     if (cellFont is null || cellFont [index] is null) return getFont ();
461     return cellFont [index];
462 }
463 
464 /**
465  * Returns the foreground color that the receiver will use to draw.
466  *
467  * @return the receiver's foreground color
468  *
469  * @exception SWTException <ul>
470  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
471  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
472  * </ul>
473  *
474  * @since 2.0
475  */
476 public Color getForeground () {
477     checkWidget ();
478     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
479     return _getForeground ();
480 }
481 
482 /**
483  *
484  * Returns the foreground color at the given column index in the receiver.
485  *
486  * @param index the column index
487  * @return the foreground color
488  *
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  * @since 3.0
495  */
496 public Color getForeground (int index) {
497     checkWidget ();
498     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
499     return _getForeground (index);
500 }
501 
502 /**
503  * Returns <code>true</code> if the receiver is grayed,
504  * and false otherwise. When the parent does not have
505  * the <code>CHECK</code> style, return false.
506  *
507  * @return the grayed state of the checkbox
508  *
509  * @exception SWTException <ul>
510  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
511  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
512  * </ul>
513  */
514 public bool getGrayed () {
515     checkWidget ();
516     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
517     if ((parent.style & SWT.CHECK) is 0) return false;
518     return grayed;
519 }
520 
521 public override Image getImage () {
522     checkWidget ();
523     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
524     return getImage (0);
525 }
526 
527 /**
528  * Returns the image stored at the given column index in the receiver,
529  * or null if the image has not been set or if the column does not exist.
530  *
531  * @param index the column index
532  * @return the image stored at the given column index in the receiver
533  *
534  * @exception SWTException <ul>
535  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
536  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
537  * </ul>
538  */
539 public Image getImage (int index) {
540     checkWidget ();
541     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
542     return _getImage (index);
543 }
544 
545 /**
546  * Returns a rectangle describing the size and location
547  * relative to its parent of an image at a column in the
548  * table.  An empty rectangle is returned if index exceeds
549  * the index of the table's last column.
550  *
551  * @param index the index that specifies the column
552  * @return the receiver's bounding image rectangle
553  *
554  * @exception SWTException <ul>
555  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
556  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
557  * </ul>
558  */
559 public Rectangle getImageBounds (int index) {
560     checkWidget ();
561     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
562     auto parentHandle = parent.handle;
563     GtkTreeViewColumn* column;
564     if (index >= 0 && index < parent.columnCount) {
565         column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
566     } else {
567         column = OS.gtk_tree_view_get_column (parentHandle, index);
568     }
569     if (column is null) return new Rectangle (0, 0, 0, 0);
570     auto pixbufRenderer = parent.getPixbufRenderer (column);
571     if (pixbufRenderer is null)  return new Rectangle (0, 0, 0, 0);
572     GdkRectangle rect;
573     auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
574     OS.gtk_widget_realize (parentHandle);
575     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
576     OS.gtk_tree_path_free (path);
577     if ((parent.getStyle () & SWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
578     /*
579     * The OS call gtk_cell_renderer_get_size() provides the width of image to be drawn
580     * by the cell renderer.  If there is no image in the cell, the width is zero.  If the table contains
581     * images of varying widths, gtk_cell_renderer_get_size() will return the width of the image,
582     * not the width of the area in which the image is drawn.
583     * New API was added in GTK 2.1.3 for determining the full width of the renderer area.
584     * For earlier versions of GTK, the result is only correct if all rows have images of the same
585     * width.
586     */
587     if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
588         int x, w;
589         OS.gtk_tree_view_column_cell_get_position (column, pixbufRenderer, &x, &w);
590         rect.x += x;
591         rect.width = w;
592     } else {
593         int w;
594         OS.gtk_tree_view_column_cell_set_cell_data (column, parent.modelHandle, handle, false, false);
595         OS.gtk_cell_renderer_get_size (pixbufRenderer, parentHandle, null, null, null, &w, null);
596         rect.width = w;
597     }
598     int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
599     return new Rectangle (rect.x, rect.y, width, rect.height + 1);
600 }
601 
602 /**
603  * Gets the image indent.
604  *
605  * @return the indent
606  *
607  * @exception SWTException <ul>
608  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
609  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
610  * </ul>
611  */
612 public int getImageIndent () {
613     checkWidget ();
614     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
615     /* Image indent is not supported on GTK */
616     return 0;
617 }
618 
619 override String getNameText () {
620     if ((parent.style & SWT.VIRTUAL) !is 0) {
621         if (!cached) return "*virtual*"; //$NON-NLS-1$
622     }
623     return super.getNameText ();
624 }
625 
626 /**
627  * Returns the receiver's parent, which must be a <code>Table</code>.
628  *
629  * @return the receiver's parent
630  *
631  * @exception SWTException <ul>
632  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
633  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
634  * </ul>
635  */
636 public Table getParent () {
637     checkWidget ();
638     return parent;
639 }
640 
641 public override String getText () {
642     checkWidget ();
643     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
644     return getText (0);
645 }
646 
647 /**
648  * Returns the text stored at the given column index in the receiver,
649  * or empty string if the text has not been set.
650  *
651  * @param index the column index
652  * @return the text stored at the given column index in the receiver
653  *
654  * @exception SWTException <ul>
655  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
656  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
657  * </ul>
658  */
659 public String getText (int index) {
660     checkWidget ();
661     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
662     return _getText (index);
663 }
664 
665 /**
666  * Returns a rectangle describing the size and location
667  * relative to its parent of the text at a column in the
668  * table.  An empty rectangle is returned if index exceeds
669  * the index of the table's last column.
670  *
671  * @param index the index that specifies the column
672  * @return the receiver's bounding text rectangle
673  *
674  * @exception SWTException <ul>
675  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
676  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
677  * </ul>
678  *
679  * @since 3.3
680  */
681 public Rectangle getTextBounds (int index) {
682     checkWidget ();
683     if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
684     int count = Math.max (1, parent.getColumnCount ());
685     if (0 > index || index > count - 1) return new Rectangle (0, 0, 0, 0);
686     // TODO fully test on early and later versions of GTK
687     // shifted a bit too far right on later versions of GTK - however, old Tree also had this problem
688     auto parentHandle = parent.handle;
689     GtkTreeViewColumn* column;
690     if (index >= 0 && index < parent.columnCount) {
691         column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
692     } else {
693         column = OS.gtk_tree_view_get_column (parentHandle, index);
694     }
695     if (column is null) return new Rectangle (0, 0, 0, 0);
696     auto textRenderer = parent.getTextRenderer (column);
697     auto pixbufRenderer = parent.getPixbufRenderer (column);
698     if (textRenderer is null || pixbufRenderer is null)  return new Rectangle (0, 0, 0, 0);
699 
700     auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
701     OS.gtk_widget_realize (parentHandle);
702 
703     bool isExpander = OS.gtk_tree_model_iter_n_children (parent.modelHandle, handle) > 0;
704     bool isExpanded = cast(bool)OS.gtk_tree_view_row_expanded (parentHandle, path);
705     OS.gtk_tree_view_column_cell_set_cell_data (column, parent.modelHandle, handle, isExpander, isExpanded);
706 
707     GdkRectangle rect;
708     OS.gtk_tree_view_get_cell_area (parentHandle, path, column, &rect);
709     OS.gtk_tree_path_free (path);
710     if ((parent.getStyle () & SWT.MIRRORED) !is 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
711     int right = rect.x + rect.width;
712 
713     int x, w;
714     parent.ignoreSize = true;
715     OS.gtk_cell_renderer_get_size (textRenderer, parentHandle, null, null, null, &w, null);
716     parent.ignoreSize = false;
717     int buffer;
718     if (OS.gtk_tree_view_get_expander_column (parentHandle) is column) {
719         OS.gtk_widget_style_get1 (parentHandle, OS.expander_size.ptr, &buffer);
720         rect.x += buffer + TreeItem.EXPANDER_EXTRA_PADDING;
721     }
722     OS.gtk_widget_style_get1 (parentHandle, OS.horizontal_separator.ptr, &buffer);
723     int horizontalSeparator = buffer;
724     rect.x += horizontalSeparator;
725 
726     if (OS.GTK_VERSION >= OS.buildVERSION (2, 1, 3)) {
727         OS.gtk_tree_view_column_cell_get_position (column, textRenderer, &x, null);
728         rect.x += x;
729     } else {
730         if ((parent.style & SWT.CHECK) !is 0) {
731             OS.gtk_cell_renderer_get_size (parent.checkRenderer, parentHandle, null, null, null, &w, null);
732             rect.x += w + horizontalSeparator;
733         }
734         OS.gtk_cell_renderer_get_size (pixbufRenderer, parentHandle, null, null, null, &w, null);
735         rect.x += w + horizontalSeparator;
736     }
737     if (parent.columnCount > 0) {
738         if (rect.x + rect.width > right) {
739             rect.width = Math.max (0, right - rect.x);
740         }
741     }
742     int width = OS.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
743     return new Rectangle (rect.x, rect.y, width, rect.height + 1);
744 }
745 
746 void redraw () {
747     if ((OS.GTK_WIDGET_FLAGS (parent.handle) & OS.GTK_REALIZED) !is 0) {
748         auto parentHandle = parent.handle;
749         auto path = OS.gtk_tree_model_get_path (parent.modelHandle, handle);
750         GdkRectangle rect;
751         OS.gtk_tree_view_get_cell_area (parentHandle, path, null, &rect);
752         OS.gtk_tree_path_free (path);
753         auto window = OS.gtk_tree_view_get_bin_window (parentHandle);
754         rect.x = 0;
755         int w, h;
756         OS.gdk_drawable_get_size (window, &w, &h);
757         rect.width = w;
758         OS.gdk_window_invalidate_rect (window, &rect, false);
759     }
760 }
761 
762 override void releaseHandle () {
763     if (handle !is null) OS.g_free (handle);
764     handle = null;
765     super.releaseHandle ();
766     parent = null;
767 }
768 
769 override void releaseWidget () {
770     super.releaseWidget ();
771     font = null;
772     cellFont = null;
773 }
774 
775 /**
776  * Sets the receiver's background color to the color specified
777  * by the argument, or to the default system color for the item
778  * if the argument is null.
779  *
780  * @param color the new color (or null)
781  *
782  * @exception IllegalArgumentException <ul>
783  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
784  * </ul>
785  * @exception SWTException <ul>
786  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
787  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
788  * </ul>
789  *
790  * @since 2.0
791  */
792 public void setBackground (Color color) {
793     checkWidget ();
794     if (color !is null && color.isDisposed ()) {
795         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
796     }
797     if (_getBackground ().opEquals (color)) return;
798     GdkColor* gdkColor = color !is null ? color.handle : null;
799     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.BACKGROUND_COLUMN, gdkColor);
800     /*
801     * Bug in GTK.  When using fixed-height-mode,
802     * row changes do not cause the row to be repainted.  The fix is to
803     * invalidate the row when it is cleared.
804     */
805     if ((parent.style & SWT.VIRTUAL) !is 0) {
806         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
807             redraw ();
808         }
809     }
810     cached = true;
811 }
812 
813 /**
814  * Sets the background color at the given column index in the receiver
815  * to the color specified by the argument, or to the default system color for the item
816  * if the argument is null.
817  *
818  * @param index the column index
819  * @param color the new color (or null)
820  *
821  * @exception IllegalArgumentException <ul>
822  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
823  * </ul>
824  * @exception SWTException <ul>
825  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
826  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
827  * </ul>
828  *
829  * @since 3.0
830  */
831 public void setBackground (int index, Color color) {
832     checkWidget ();
833     if (color !is null && color.isDisposed ()) {
834         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
835     }
836     if (_getBackground (index).opEquals (color)) return;
837     int count = Math.max (1, parent.getColumnCount ());
838     if (0 > index || index > count - 1) return;
839     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
840     GdkColor* gdkColor = color !is null ? color.handle : null;
841     OS.gtk_list_store_set1 (parent.modelHandle, handle, modelIndex + Table.CELL_BACKGROUND, gdkColor);
842     /*
843     * Bug in GTK.  When using fixed-height-mode,
844     * row changes do not cause the row to be repainted.  The fix is to
845     * invalidate the row when it is cleared.
846     */
847     if ((parent.style & SWT.VIRTUAL) !is 0) {
848         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
849             redraw ();
850         }
851     }
852     cached = true;
853 
854     if (color !is null) {
855         bool customDraw = (parent.columnCount is 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
856         if (!customDraw) {
857             if ((parent.style & SWT.VIRTUAL) is 0) {
858                 auto parentHandle = parent.handle;
859                 GtkTreeViewColumn* column;
860                 if (parent.columnCount > 0) {
861                     column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
862                 } else {
863                     column = OS.gtk_tree_view_get_column (parentHandle, index);
864                 }
865                 if (column is null) return;
866                 auto textRenderer = parent.getTextRenderer (column);
867                 auto imageRenderer = parent.getPixbufRenderer (column);
868                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)textRenderer );
869                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)imageRenderer );
870             }
871             if (parent.columnCount is 0) {
872                 parent.firstCustomDraw = true;
873             } else {
874                 parent.columns [index].customDraw = true;
875             }
876         }
877     }
878 }
879 
880 /**
881  * Sets the checked state of the checkbox for this item.  This state change
882  * only applies if the Table was created with the SWT.CHECK style.
883  *
884  * @param checked the new checked state of the checkbox
885  *
886  * @exception SWTException <ul>
887  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
888  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
889  * </ul>
890  */
891 public void setChecked (bool checked) {
892     checkWidget();
893     if ((parent.style & SWT.CHECK) is 0) return;
894     if (_getChecked () is checked) return;
895     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, cast(void*)cast(int)checked);
896     /*
897     * GTK+'s "inconsistent" state does not match SWT's concept of grayed.  To
898     * show checked+grayed differently from unchecked+grayed, we must toggle the
899     * grayed state on check and uncheck.
900     */
901     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.GRAYED_COLUMN, cast(void*)cast(int)( !checked ? false : grayed));
902     cached = true;
903 }
904 
905 /**
906  * Sets the font that the receiver will use to paint textual information
907  * for this item to the font specified by the argument, or to the default font
908  * for that kind of control if the argument is null.
909  *
910  * @param font the new font (or null)
911  *
912  * @exception IllegalArgumentException <ul>
913  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
914  * </ul>
915  * @exception SWTException <ul>
916  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
917  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
918  * </ul>
919  *
920  * @since 3.0
921  */
922 public void setFont (Font font){
923     checkWidget ();
924     if (font !is null && font.isDisposed ()) {
925         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
926     }
927     Font oldFont = this.font;
928     if (oldFont is font) return;
929     this.font = font;
930     if (oldFont !is null && oldFont.opEquals (font)) return;
931     auto fontHandle = font !is null ? font.handle : null;
932     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.FONT_COLUMN, fontHandle);
933     /*
934     * Bug in GTK.  When using fixed-height-mode,
935     * row changes do not cause the row to be repainted.  The fix is to
936     * invalidate the row when it is cleared.
937     */
938     if ((parent.style & SWT.VIRTUAL) !is 0) {
939         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
940             redraw ();
941         }
942     }
943     cached = true;
944 }
945 
946 /**
947  * Sets the font that the receiver will use to paint textual information
948  * for the specified cell in this item to the font specified by the
949  * argument, or to the default font for that kind of control if the
950  * argument is null.
951  *
952  * @param index the column index
953  * @param font the new font (or null)
954  *
955  * @exception IllegalArgumentException <ul>
956  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
957  * </ul>
958  * @exception SWTException <ul>
959  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
960  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
961  * </ul>
962  *
963  * @since 3.0
964  */
965 public void setFont (int index, Font font) {
966     checkWidget ();
967     if (font !is null && font.isDisposed ()) {
968         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
969     }
970     int count = Math.max (1, parent.getColumnCount ());
971     if (0 > index || index > count - 1) return;
972     if (cellFont is null) {
973         if (font is null) return;
974         cellFont = new Font [count];
975     }
976     Font oldFont = cellFont [index];
977     if (oldFont is font) return;
978     cellFont [index] = font;
979     if (oldFont !is null && oldFont.opEquals (font)) return;
980 
981     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
982     auto fontHandle  = font !is null ? font.handle : null;
983     OS.gtk_list_store_set1 (parent.modelHandle, handle, modelIndex + Table.CELL_FONT, fontHandle);
984     /*
985     * Bug in GTK.  When using fixed-height-mode,
986     * row changes do not cause the row to be repainted.  The fix is to
987     * invalidate the row when it is cleared.
988     */
989     if ((parent.style & SWT.VIRTUAL) !is 0) {
990         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
991             redraw ();
992         }
993     }
994     cached = true;
995 
996     if (font !is null) {
997         bool customDraw = (parent.columnCount is 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
998         if (!customDraw) {
999             if ((parent.style & SWT.VIRTUAL) is 0) {
1000                 auto parentHandle = parent.handle;
1001                 GtkTreeViewColumn* column;
1002                 if (parent.columnCount > 0) {
1003                     column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
1004                 } else {
1005                     column = OS.gtk_tree_view_get_column (parentHandle, index);
1006                 }
1007                 if (column is null) return;
1008                 auto textRenderer = parent.getTextRenderer (column);
1009                 auto imageRenderer = parent.getPixbufRenderer (column);
1010                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)textRenderer );
1011                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)imageRenderer );
1012             }
1013             if (parent.columnCount is 0) {
1014                 parent.firstCustomDraw = true;
1015             } else {
1016                 parent.columns [index].customDraw = true;
1017             }
1018         }
1019     }
1020 }
1021 
1022 /**
1023  * Sets the receiver's foreground color to the color specified
1024  * by the argument, or to the default system color for the item
1025  * if the argument is null.
1026  *
1027  * @param color the new color (or null)
1028  *
1029  * @exception IllegalArgumentException <ul>
1030  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1031  * </ul>
1032  * @exception SWTException <ul>
1033  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1034  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1035  * </ul>
1036  *
1037  * @since 2.0
1038  */
1039 public void setForeground (Color color){
1040     checkWidget ();
1041     if (color !is null && color.isDisposed ()) {
1042         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
1043     }
1044     if (_getForeground ().opEquals (color)) return;
1045     GdkColor* gdkColor = color !is null ? color.handle : null;
1046     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.FOREGROUND_COLUMN, gdkColor);
1047     /*
1048     * Bug in GTK.  When using fixed-height-mode,
1049     * row changes do not cause the row to be repainted.  The fix is to
1050     * invalidate the row when it is cleared.
1051     */
1052     if ((parent.style & SWT.VIRTUAL) !is 0) {
1053         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
1054             redraw ();
1055         }
1056     }
1057     cached = true;
1058 }
1059 
1060 /**
1061  * Sets the foreground color at the given column index in the receiver
1062  * to the color specified by the argument, or to the default system color for the item
1063  * if the argument is null.
1064  *
1065  * @param index the column index
1066  * @param color the new color (or null)
1067  *
1068  * @exception IllegalArgumentException <ul>
1069  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1070  * </ul>
1071  * @exception SWTException <ul>
1072  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1073  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1074  * </ul>
1075  *
1076  * @since 3.0
1077  */
1078 public void setForeground (int index, Color color){
1079     checkWidget ();
1080     if (color !is null && color.isDisposed ()) {
1081         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
1082     }
1083     if (_getForeground (index).opEquals (color)) return;
1084     int count = Math.max (1, parent.getColumnCount ());
1085     if (0 > index || index > count - 1) return;
1086     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
1087     GdkColor* gdkColor = color !is null ? color.handle : null;
1088     OS.gtk_list_store_set1 (parent.modelHandle, handle, modelIndex + Table.CELL_FOREGROUND, gdkColor);
1089     /*
1090     * Bug in GTK.  When using fixed-height-mode,
1091     * row changes do not cause the row to be repainted.  The fix is to
1092     * invalidate the row when it is cleared.
1093     */
1094     if ((parent.style & SWT.VIRTUAL) !is 0) {
1095         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
1096             redraw ();
1097         }
1098     }
1099     cached = true;
1100 
1101     if (color !is null) {
1102         bool customDraw = (parent.columnCount is 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
1103         if (!customDraw) {
1104             if ((parent.style & SWT.VIRTUAL) is 0) {
1105                 auto parentHandle = parent.handle;
1106                 GtkTreeViewColumn* column;
1107                 if (parent.columnCount > 0) {
1108                     column = cast(GtkTreeViewColumn*)parent.columns [index].handle;
1109                 } else {
1110                     column = OS.gtk_tree_view_get_column (parentHandle, index);
1111                 }
1112                 if (column is null) return;
1113                 auto textRenderer = parent.getTextRenderer (column);
1114                 auto imageRenderer = parent.getPixbufRenderer (column);
1115                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)textRenderer );
1116                 display.doCellDataProc( parentHandle, column, cast(GtkCellRenderer*)imageRenderer );
1117             }
1118             if (parent.columnCount is 0) {
1119                 parent.firstCustomDraw = true;
1120             } else {
1121                 parent.columns [index].customDraw = true;
1122             }
1123         }
1124     }
1125 }
1126 
1127 /**
1128  * Sets the grayed state of the checkbox for this item.  This state change
1129  * only applies if the Table was created with the SWT.CHECK style.
1130  *
1131  * @param grayed the new grayed state of the checkbox;
1132  *
1133  * @exception SWTException <ul>
1134  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1135  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1136  * </ul>
1137  */
1138 public void setGrayed (bool grayed) {
1139     checkWidget();
1140     if ((parent.style & SWT.CHECK) is 0) return;
1141     if (this.grayed is grayed) return;
1142     this.grayed = grayed;
1143     /*
1144     * GTK+'s "inconsistent" state does not match SWT's concept of grayed.
1145     * Render checked+grayed as "inconsistent", unchecked+grayed as blank.
1146     */
1147     void* ptr;
1148     OS.gtk_tree_model_get1 (parent.modelHandle, handle, Table.CHECKED_COLUMN, &ptr);
1149     OS.gtk_list_store_set1 (parent.modelHandle, handle, Table.GRAYED_COLUMN, cast(void*)cast(int)( ptr is null ? false : grayed));
1150     cached = true;
1151 }
1152 
1153 /**
1154  * Sets the receiver's image at a column.
1155  *
1156  * @param index the column index
1157  * @param image the new image
1158  *
1159  * @exception IllegalArgumentException <ul>
1160  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
1161  * </ul>
1162  * @exception SWTException <ul>
1163  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1164  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1165  * </ul>
1166  */
1167 public void setImage (int index, Image image) {
1168     checkWidget ();
1169     if (image !is null && image.isDisposed ()) {
1170         error(SWT.ERROR_INVALID_ARGUMENT);
1171     }
1172     if (image !is null && image.type is SWT.ICON) {
1173         if (image.opEquals (_getImage (index))) return;
1174     }
1175     int count = Math.max (1, parent.getColumnCount ());
1176     if (0 > index || index > count - 1) return;
1177     void* pixbuf;
1178     if (image !is null) {
1179         ImageList imageList = parent.imageList;
1180         if (imageList is null) imageList = parent.imageList = new ImageList ();
1181         int imageIndex = imageList.indexOf (image);
1182         if (imageIndex is -1) imageIndex = imageList.add (image);
1183         pixbuf = imageList.getPixbuf (imageIndex);
1184     }
1185     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
1186     OS.gtk_list_store_set1 (parent.modelHandle, handle, modelIndex + Table.CELL_PIXBUF, pixbuf);
1187     /*
1188     * Bug in GTK.  When using fixed-height-mode,
1189     * row changes do not cause the row to be repainted.  The fix is to
1190     * invalidate the row when it is cleared.
1191     */
1192     if ((parent.style & SWT.VIRTUAL) !is 0) {
1193         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
1194             redraw ();
1195         }
1196     }
1197     /*
1198      * Bug in GTK.  When in fixed height mode, GTK does not recalculate the cell renderer width
1199      * when the image is changed in the model.  The fix is to force it to recalculate the width if
1200      * more space is required.
1201      */
1202     if ((parent.style & SWT.VIRTUAL) !is 0 && parent.currentItem is null) {
1203         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2)) {
1204             if (image !is null) {
1205                 auto parentHandle = parent.handle;
1206                 auto column = OS.gtk_tree_view_get_column (parentHandle, index);
1207                 int w;
1208                 auto pixbufRenderer = parent.getPixbufRenderer(column);
1209                 OS.gtk_tree_view_column_cell_get_position (column, pixbufRenderer, null, &w);
1210                 if (w < image.getBounds().width) {
1211                     /*
1212                     * There is no direct way to clear the cell renderer width so we
1213                     * are relying on the fact that it is done as part of modifying
1214                     * the style.
1215                     */
1216                     auto style = OS.gtk_widget_get_modifier_style (parentHandle);
1217                     parent.modifyStyle (parentHandle, style);
1218                 }
1219             }
1220         }
1221     }
1222     cached = true;
1223 }
1224 
1225 public override void setImage (Image image) {
1226     checkWidget ();
1227     setImage (0, image);
1228 }
1229 
1230 /**
1231  * Sets the image for multiple columns in the table.
1232  *
1233  * @param images the array of new images
1234  *
1235  * @exception IllegalArgumentException <ul>
1236  *    <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
1237  * </ul>
1238  * @exception SWTException <ul>
1239  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1240  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1241  * </ul>
1242  */
1243 public void setImage (Image [] images) {
1244     checkWidget ();
1245     for (int i=0; i<images.length; i++) {
1246         setImage (i, images [i]);
1247     }
1248 }
1249 
1250 /**
1251  * Sets the indent of the first column's image, expressed in terms of the image's width.
1252  *
1253  * @param indent the new indent
1254  *
1255  * </ul>
1256  * @exception SWTException <ul>
1257  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1258  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1259  * </ul>
1260  *
1261  * @deprecated this functionality is not supported on most platforms
1262  */
1263 public void setImageIndent (int indent) {
1264     checkWidget ();
1265     if (indent < 0) return;
1266     /* Image indent is not supported on GTK */
1267     cached = true;
1268 }
1269 
1270 /**
1271  * Sets the receiver's text at a column
1272  *
1273  * @param index the column index
1274  * @param string the new text
1275  *
1276  * @exception SWTException <ul>
1277  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1278  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1279  * </ul>
1280  */
1281 public void setText (int index, String string) {
1282     checkWidget ();
1283     if (_getText (index).equals (string)) return;
1284     int count = Math.max (1, parent.getColumnCount ());
1285     if (0 > index || index > count - 1) return;
1286     char* buffer = toStringz( string );
1287     int modelIndex = parent.columnCount is 0 ? Table.FIRST_COLUMN : parent.columns [index].modelIndex;
1288     OS.gtk_list_store_set1 (parent.modelHandle, handle, modelIndex + Table.CELL_TEXT, buffer);
1289     /*
1290     * Bug in GTK.  When using fixed-height-mode,
1291     * row changes do not cause the row to be repainted.  The fix is to
1292     * invalidate the row when it is cleared.
1293     */
1294     if ((parent.style & SWT.VIRTUAL) !is 0) {
1295         if (OS.GTK_VERSION >= OS.buildVERSION (2, 3, 2) && OS.GTK_VERSION < OS.buildVERSION (2, 6, 3)) {
1296             redraw ();
1297         }
1298     }
1299     cached = true;
1300 }
1301 
1302 public override void setText (String string) {
1303     checkWidget ();
1304     setText (0, string);
1305 }
1306 
1307 /**
1308  * Sets the text for multiple columns in the table.
1309  *
1310  * @param strings the array of new strings
1311  *
1312  * @exception SWTException <ul>
1313  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1314  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1315  * </ul>
1316  */
1317 public void setText (String [] strings) {
1318     checkWidget ();
1319     for (int i=0; i<strings.length; i++) {
1320         String string = strings [i];
1321         if (string !is null) setText (i, string);
1322     }
1323 }
1324 }