1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15 
16 
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.internal.*;
20 import org.eclipse.swt.internal.gtk.*;
21 import org.eclipse.swt.internal.gtk3.*;
22 
23 /**
24  * Instances of this class represent a selectable user interface object
25  * that represents a hierarchy of tree items in a tree widget.
26  *
27  * <dl>
28  * <dt><b>Styles:</b></dt>
29  * <dd>(none)</dd>
30  * <dt><b>Events:</b></dt>
31  * <dd>(none)</dd>
32  * </dl>
33  * <p>
34  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
35  * </p>
36  *
37  * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
38  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
39  * @noextend This class is not intended to be subclassed by clients.
40  */
41 public class TreeItem extends Item {
42 	Tree parent;
43 	Font font;
44 	Font[] cellFont;
45 	String [] strings;
46 	boolean cached, grayed, isExpanded, updated, settingData;
47 	static final int EXPANDER_EXTRA_PADDING = 4;
48 
49 /**
50  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
51  * Item is inserted as last direct child of the tree.
52  * <p>
53  * For bulk insert scenarios, see TreeItem#TreeItem(Tree,int,int)
54  *
55  * @param parent a tree control which will be the parent of the new instance (cannot be null)
56  * @param style no styles are currently supported, pass SWT.NONE
57  *
58  * @exception IllegalArgumentException <ul>
59  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
60  * </ul>
61  * @exception SWTException <ul>
62  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
63  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
64  * </ul>
65  *
66  * @see SWT
67  * @see Widget#checkSubclass
68  * @see Widget#getStyle
69  */
TreeItem(Tree parent, int style)70 public TreeItem (Tree parent, int style) {
71 	this (checkNull (parent), 0, style, -1, true);
72 }
73 
74 /**
75  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
76  * Item is inserted as <code>index</code> direct child of the tree.
77  * <p>
78  * The fastest way to insert many items is:
79  * <ol>
80  * <li>Use {@link Tree#setRedraw} to disable drawing during bulk insert</li>
81  * <li>Insert every item at index 0 (insert them in reverse to get the same result)</li>
82  * </ol>
83  *
84  * @param parent a tree control which will be the parent of the new instance (cannot be null)
85  * @param style no styles are currently supported, pass SWT.NONE
86  * @param index the zero-relative index to store the receiver in its parent
87  *
88  * @exception IllegalArgumentException <ul>
89  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
90  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
91  * </ul>
92  * @exception SWTException <ul>
93  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
94  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
95  * </ul>
96  *
97  * @see SWT
98  * @see Widget#checkSubclass
99  * @see Widget#getStyle
100  * @see Tree#setRedraw
101  */
TreeItem(Tree parent, int style, int index)102 public TreeItem (Tree parent, int style, int index) {
103 	this (checkNull (parent), 0, style, checkIndex (index), true);
104 }
105 
106 /**
107  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
108  * Item is inserted as last direct child of the specified <code>TreeItem</code>.
109  * <p>
110  * For bulk insert scenarios, see TreeItem#TreeItem(TreeItem,int,int)
111  *
112  * @param parentItem a tree control which will be the parent of the new instance (cannot be null)
113  * @param style no styles are currently supported, pass SWT.NONE
114  *
115  * @exception IllegalArgumentException <ul>
116  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
117  * </ul>
118  * @exception SWTException <ul>
119  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
120  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
121  * </ul>
122  *
123  * @see SWT
124  * @see Widget#checkSubclass
125  * @see Widget#getStyle
126  */
TreeItem(TreeItem parentItem, int style)127 public TreeItem (TreeItem parentItem, int style) {
128 	this (checkNull (parentItem).parent, parentItem.handle, style, -1, true);
129 }
130 
131 /**
132  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
133  * Item is inserted as <code>index</code> direct child of the specified <code>TreeItem</code>.
134  * <p>
135  * The fastest way to insert many items is:
136  * <ol>
137  * <li>Use {@link Tree#setRedraw} to disable drawing during bulk insert</li>
138  * <li>Insert child items while parent item is collapsed</li>
139  * <li>Insert every item at index 0 (insert them in reverse to get the same result)</li>
140  * </ol>
141  *
142  * @param parentItem a tree control which will be the parent of the new instance (cannot be null)
143  * @param style no styles are currently supported, pass SWT.NONE
144  * @param index the zero-relative index to store the receiver in its parent
145  *
146  * @exception IllegalArgumentException <ul>
147  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
148  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
149  * </ul>
150  * @exception SWTException <ul>
151  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
152  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
153  * </ul>
154  *
155  * @see SWT
156  * @see Widget#checkSubclass
157  * @see Widget#getStyle
158  * @see Tree#setRedraw
159  */
TreeItem(TreeItem parentItem, int style, int index)160 public TreeItem (TreeItem parentItem, int style, int index) {
161 	this (checkNull (parentItem).parent, parentItem.handle, style, checkIndex (index), true);
162 }
163 
TreeItem(Tree parent, long parentIter, int style, int index, boolean create)164 TreeItem (Tree parent, long parentIter, int style, int index, boolean create) {
165 	super (parent, style);
166 	this.parent = parent;
167 	if (create) {
168 		parent.createItem (this, parentIter, index);
169 	} else {
170 		handle = OS.g_malloc (GTK.GtkTreeIter_sizeof ());
171 		GTK.gtk_tree_model_iter_nth_child (parent.modelHandle, handle, parentIter, index);
172 	}
173 }
174 
checkIndex(int index)175 static int checkIndex (int index) {
176 	if (index < 0) SWT.error (SWT.ERROR_INVALID_RANGE);
177 	return index;
178 }
179 
checkNull(TreeItem item)180 static TreeItem checkNull (TreeItem item) {
181 	if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
182 	return item;
183 }
184 
checkNull(Tree control)185 static Tree checkNull (Tree control) {
186 	if (control == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
187 	return control;
188 }
189 
190 @Override
checkSubclass()191 protected void checkSubclass () {
192 	if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
193 }
194 
_getBackground()195 Color _getBackground () {
196 	long [] ptr = new long [1];
197 	GTK.gtk_tree_model_get (parent.modelHandle, handle, Tree.BACKGROUND_COLUMN, ptr, -1);
198 	if (ptr [0] == 0) return parent.getBackground ();
199 	GdkRGBA gdkRGBA = new GdkRGBA ();
200 	OS.memmove(gdkRGBA, ptr [0], GdkRGBA.sizeof);
201 	GDK.gdk_rgba_free (ptr [0]);
202 	return Color.gtk_new(display, gdkRGBA);
203 }
204 
_getBackground(int index)205 Color _getBackground (int index) {
206 	int count = Math.max (1, parent.columnCount);
207 	if (0 > index || index > count - 1) return _getBackground ();
208 	long [] ptr = new long [1];
209 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
210 	GTK.gtk_tree_model_get (parent.modelHandle, handle, modelIndex + Tree.CELL_BACKGROUND, ptr, -1);
211 	if (ptr [0] == 0) return _getBackground ();
212 	GdkRGBA gdkRGBA = new GdkRGBA ();
213 	OS.memmove(gdkRGBA, ptr [0], GdkRGBA.sizeof);
214 	GDK.gdk_rgba_free (ptr [0]);
215 	return Color.gtk_new(display, gdkRGBA);
216 }
217 
_getChecked()218 boolean _getChecked () {
219 	int [] ptr = new int [1];
220 	GTK.gtk_tree_model_get (parent.modelHandle, handle, Tree.CHECKED_COLUMN, ptr, -1);
221 	return ptr [0] != 0;
222 }
223 
_getForeground()224 Color _getForeground () {
225 	long [] ptr = new long [1];
226 	GTK.gtk_tree_model_get (parent.modelHandle, handle, Tree.FOREGROUND_COLUMN, ptr, -1);
227 	if (ptr [0] == 0) return parent.getForeground ();
228 	GdkRGBA gdkRGBA = new GdkRGBA ();
229 	OS.memmove(gdkRGBA, ptr [0], GdkRGBA.sizeof);
230 	GDK.gdk_rgba_free (ptr [0]);
231 	return Color.gtk_new(display, gdkRGBA);
232 }
233 
_getForeground(int index)234 Color _getForeground (int index) {
235 	int count = Math.max (1, parent.columnCount);
236 	if (0 > index || index > count - 1) return _getForeground ();
237 	long [] ptr = new long [1];
238 	int modelIndex =  parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
239 	GTK.gtk_tree_model_get (parent.modelHandle, handle, modelIndex + Tree.CELL_FOREGROUND, ptr, -1);
240 	if (ptr [0] == 0) return _getForeground ();
241 	GdkRGBA gdkRGBA = new GdkRGBA ();
242 	OS.memmove(gdkRGBA, ptr [0], GdkRGBA.sizeof);
243 	GDK.gdk_rgba_free (ptr [0]);
244 	return Color.gtk_new(display, gdkRGBA);
245 }
246 
_getImage(int index)247 Image _getImage(int index) {
248 	int count = Math.max(1, parent.getColumnCount());
249 	if (0 > index || index > count - 1) return null;
250 
251 	long[] surfaceHandle = new long[1];
252 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns[index].modelIndex;
253 	GTK.gtk_tree_model_get (parent.modelHandle, handle, modelIndex + Tree.CELL_SURFACE, surfaceHandle, -1);
254 	if (surfaceHandle[0] == 0) return null;
255 
256 	int imageIndex = parent.imageList.indexOf(surfaceHandle[0]);
257 	if (imageIndex == -1) {
258 		return null;
259 	} else {
260 		return parent.imageList.get(imageIndex);
261 	}
262 }
263 
_getText(int index)264 String _getText (int index) {
265 	int count = Math.max (1, parent.getColumnCount ());
266 	if (0 > index || index > count - 1) return "";
267 	long [] ptr = new long [1];
268 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
269 	GTK.gtk_tree_model_get (parent.modelHandle, handle, modelIndex + Tree.CELL_TEXT, ptr, -1);
270 	if (ptr [0] == 0) return ""; //$NON-NLS-1$
271 	int length = C.strlen (ptr [0]);
272 	byte[] buffer = new byte [length];
273 	C.memmove (buffer, ptr [0], length);
274 	OS.g_free (ptr [0]);
275 	return new String (Converter.mbcsToWcs (buffer));
276 }
277 
clear()278 void clear () {
279 	if (parent.currentItem == this) return;
280 	if (cached || (parent.style & SWT.VIRTUAL) == 0) {
281 		int columnCount = GTK.gtk_tree_model_get_n_columns (parent.modelHandle);
282 		/* the columns before FOREGROUND_COLUMN contain int values, subsequent columns contain pointers */
283 		for (int i=Tree.CHECKED_COLUMN; i<Tree.FOREGROUND_COLUMN; i++) {
284 			GTK.gtk_tree_store_set (parent.modelHandle, handle, i, 0, -1);
285 		}
286 		for (int i=Tree.FOREGROUND_COLUMN; i<columnCount; i++) {
287 			GTK.gtk_tree_store_set (parent.modelHandle, handle, i, (long )0, -1);
288 		}
289 	}
290 	cached = false;
291 	font = null;
292 	strings = null;
293 	cellFont = null;
294 }
295 
296 /**
297  * Clears the item at the given zero-relative index in the receiver.
298  * The text, icon and other attributes of the item are set to the default
299  * value.  If the tree was created with the <code>SWT.VIRTUAL</code> style,
300  * these attributes are requested again as needed.
301  *
302  * @param index the index of the item to clear
303  * @param all <code>true</code> if all child items of the indexed item should be
304  * cleared recursively, and <code>false</code> otherwise
305  *
306  * @exception IllegalArgumentException <ul>
307  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
308  * </ul>
309  * @exception SWTException <ul>
310  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
311  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
312  * </ul>
313  *
314  * @see SWT#VIRTUAL
315  * @see SWT#SetData
316  *
317  * @since 3.2
318  */
clear(int index, boolean all)319 public void clear (int index, boolean all) {
320 	checkWidget ();
321 	parent.clear (handle, index, all);
322 }
323 
324 /**
325  * Clears all the items in the receiver. The text, icon and other
326  * attributes of the items are set to their default values. If the
327  * tree was created with the <code>SWT.VIRTUAL</code> style, these
328  * attributes are requested again as needed.
329  *
330  * @param all <code>true</code> if all child items should be cleared
331  * recursively, and <code>false</code> otherwise
332  *
333  * @exception SWTException <ul>
334  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
335  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
336  * </ul>
337  *
338  * @see SWT#VIRTUAL
339  * @see SWT#SetData
340  *
341  * @since 3.2
342  */
clearAll(boolean all)343 public void clearAll (boolean all) {
344 	checkWidget ();
345 	parent.clearAll (all, handle);
346 }
347 
348 @Override
destroyWidget()349 void destroyWidget () {
350 	parent.releaseItem (this, false);
351 	parent.destroyItem (this);
352 	releaseHandle ();
353 }
354 
355 /**
356  * Returns the receiver's background color.
357  *
358  * @return the background color
359  *
360  * @exception SWTException <ul>
361  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
362  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
363  * </ul>
364  *
365  * @since 2.0
366  *
367  */
getBackground()368 public Color getBackground () {
369 	checkWidget ();
370 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
371 	return _getBackground ();
372 }
373 
374 /**
375  * Returns the background color at the given column index in the receiver.
376  *
377  * @param index the column index
378  * @return the background color
379  *
380  * @exception SWTException <ul>
381  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
382  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
383  * </ul>
384  *
385  * @since 3.1
386  */
getBackground(int index)387 public Color getBackground (int index) {
388 	checkWidget ();
389 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
390 	return _getBackground (index);
391 }
392 
393 /**
394  * Returns a rectangle describing the receiver's size and location
395  * relative to its parent at a column in the tree.
396  *
397  * @param index the index that specifies the column
398  * @return the receiver's bounding column rectangle
399  *
400  * @exception SWTException <ul>
401  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
402  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
403  * </ul>
404  *
405  * @since 3.1
406  */
getBounds(int index)407 public Rectangle getBounds (int index) {
408 	checkWidget ();
409 	return DPIUtil.autoScaleDown (getBoundsInPixels (index));
410 }
411 
getBoundsInPixels(int index)412 Rectangle getBoundsInPixels (int index) {
413 	// TODO fully test on early and later versions of GTK
414 	checkWidget();
415 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
416 	long parentHandle = parent.handle;
417 	long column = 0;
418 	if (index >= 0 && index < parent.columnCount) {
419 		column = parent.columns [index].handle;
420 	} else {
421 		column = GTK.gtk_tree_view_get_column (parentHandle, index);
422 	}
423 	if (column == 0) return new Rectangle (0, 0, 0, 0);
424 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
425 	GTK.gtk_widget_realize (parentHandle);
426 	GdkRectangle rect = new GdkRectangle ();
427 	GTK.gtk_tree_view_get_cell_area (parentHandle, path, column, rect);
428 	if ((parent.getStyle () & SWT.MIRRORED) != 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
429 
430 	GTK.gtk_tree_path_free (path);
431 
432 	if (index == 0 && (parent.style & SWT.CHECK) != 0) {
433 		int [] x = new int [1], w = new int [1];
434 		gtk_tree_view_column_cell_get_position (column, parent.checkRenderer, x, w);
435 		rect.x += x [0] + w [0];
436 		rect.width -= x [0] + w [0];
437 	}
438 	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
439 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
440 	return r;
441 }
442 
443 /**
444  * Returns a rectangle describing the size and location of the receiver's
445  * text relative to its parent.
446  *
447  * @return the bounding rectangle of the receiver's text
448  *
449  * @exception SWTException <ul>
450  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
451  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
452  * </ul>
453  */
getBounds()454 public Rectangle getBounds () {
455 	checkWidget ();
456 	return DPIUtil.autoScaleDown (getBoundsInPixels ());
457 }
458 
getBoundsInPixels()459 Rectangle getBoundsInPixels () {
460 	// TODO fully test on early and later versions of GTK
461 	// shifted a bit too far right on later versions of GTK - however, old Tree also had this problem
462 	checkWidget ();
463 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
464 	long parentHandle = parent.handle;
465 	long column = GTK.gtk_tree_view_get_column (parentHandle, 0);
466 	if (column == 0) return new Rectangle (0, 0, 0, 0);
467 	long textRenderer = parent.getTextRenderer (column);
468 	long pixbufRenderer = parent.getPixbufRenderer (column);
469 	if (textRenderer == 0 || pixbufRenderer == 0)  return new Rectangle (0, 0, 0, 0);
470 
471 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
472 	GTK.gtk_widget_realize (parentHandle);
473 
474 	boolean isExpander = GTK.gtk_tree_model_iter_n_children (parent.modelHandle, handle) > 0;
475 	boolean isExpanded = GTK.gtk_tree_view_row_expanded (parentHandle, path);
476 	GTK.gtk_tree_view_column_cell_set_cell_data (column, parent.modelHandle, handle, isExpander, isExpanded);
477 
478 	GdkRectangle rect = new GdkRectangle ();
479 	GTK.gtk_tree_view_get_cell_area (parentHandle, path, column, rect);
480 	if ((parent.getStyle () & SWT.MIRRORED) != 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
481 	int right = rect.x + rect.width;
482 
483 	int [] x = new int [1], w = new int [1];
484 	parent.ignoreSize = true;
485 	gtk_cell_renderer_get_preferred_size (textRenderer, parentHandle, w, null);
486 	parent.ignoreSize = false;
487 	rect.width = w [0];
488 	int [] buffer = new int [1];
489 	GTK.gtk_tree_path_free (path);
490 
491 	int horizontalSeparator;
492 	if (GTK.GTK4) {
493 		long separator = GTK.gtk_separator_new(GTK.GTK_ORIENTATION_HORIZONTAL);
494 		GtkAllocation allocation = new GtkAllocation ();
495 		GTK.gtk_widget_get_allocation(separator, allocation);
496 		horizontalSeparator = allocation.height;
497 	} else {
498 		GTK3.gtk_widget_style_get (parentHandle, OS.horizontal_separator, buffer, 0);
499 		horizontalSeparator = buffer[0];
500 	}
501 	rect.x += horizontalSeparator;
502 
503 	gtk_tree_view_column_cell_get_position (column, textRenderer, x, null);
504 	rect.x += x [0];
505 	if (parent.columnCount > 0) {
506 		if (rect.x + rect.width > right) {
507 			rect.width = Math.max (0, right - rect.x);
508 		}
509 	}
510 	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
511 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
512 	return r;
513 }
514 
515 /**
516  * Returns <code>true</code> if the receiver is checked,
517  * and false otherwise.  When the parent does not have
518  * the <code>CHECK</code> style, return false.
519  *
520  * @return the checked state
521  *
522  * @exception SWTException <ul>
523  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
524  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
525  * </ul>
526  */
getChecked()527 public boolean getChecked () {
528 	checkWidget();
529 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
530 	if ((parent.style & SWT.CHECK) == 0) return false;
531 	return _getChecked ();
532 }
533 
534 /**
535  * Returns <code>true</code> if the receiver is expanded,
536  * and false otherwise.
537  * <p>
538  *
539  * @return the expanded state
540  *
541  * @exception SWTException <ul>
542  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
543  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
544  * </ul>
545  */
getExpanded()546 public boolean getExpanded () {
547 	checkWidget();
548 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
549 	boolean answer = GTK.gtk_tree_view_row_expanded (parent.handle, path);
550 	GTK.gtk_tree_path_free (path);
551 	return answer;
552 }
553 
554 /**
555  * Returns the font that the receiver will use to paint textual information for this item.
556  *
557  * @return the receiver's font
558  *
559  * @exception SWTException <ul>
560  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
561  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
562  * </ul>
563  *
564  * @since 3.0
565  */
getFont()566 public Font getFont () {
567 	checkWidget ();
568 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
569 	return font != null ? font : parent.getFont ();
570 }
571 
572 /**
573  * Returns the font that the receiver will use to paint textual information
574  * for the specified cell in this item.
575  *
576  * @param index the column index
577  * @return the receiver's font
578  *
579  * @exception SWTException <ul>
580  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
581  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
582  * </ul>
583  *
584  * @since 3.1
585  */
getFont(int index)586 public Font getFont (int index) {
587 	checkWidget ();
588 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
589 	int count = Math.max (1, parent.columnCount);
590 	if (0 > index || index > count - 1) return getFont ();
591 	if (cellFont == null || cellFont [index] == null) return getFont ();
592 	return cellFont [index];
593 }
594 
595 
596 /**
597  * Returns the foreground color that the receiver will use to draw.
598  *
599  * @return the receiver's foreground color
600  *
601  * @exception SWTException <ul>
602  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
603  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
604  * </ul>
605  *
606  * @since 2.0
607  *
608  */
getForeground()609 public Color getForeground () {
610 	checkWidget ();
611 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
612 	return _getForeground ();
613 }
614 
615 /**
616  *
617  * Returns the foreground color at the given column index in the receiver.
618  *
619  * @param index the column index
620  * @return the foreground color
621  *
622  * @exception SWTException <ul>
623  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
624  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
625  * </ul>
626  *
627  * @since 3.1
628  */
getForeground(int index)629 public Color getForeground (int index) {
630 	checkWidget ();
631 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
632 	return _getForeground (index);
633 }
634 
635 /**
636  * Returns <code>true</code> if the receiver is grayed,
637  * and false otherwise. When the parent does not have
638  * the <code>CHECK</code> style, return false.
639  *
640  * @return the grayed state of the checkbox
641  *
642  * @exception SWTException <ul>
643  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
644  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
645  * </ul>
646  */
getGrayed()647 public boolean getGrayed () {
648 	checkWidget ();
649 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
650 	if ((parent.style & SWT.CHECK) == 0) return false;
651 	return grayed;
652 }
653 
654 @Override
getImage()655 public Image getImage () {
656 	checkWidget ();
657 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
658 	return getImage (0);
659 }
660 
661 /**
662  * Returns the image stored at the given column index in the receiver,
663  * or null if the image has not been set or if the column does not exist.
664  *
665  * @param index the column index
666  * @return the image stored at the given column index in the receiver
667  *
668  * @exception SWTException <ul>
669  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
670  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
671  * </ul>
672  *
673  * @since 3.1
674  */
getImage(int index)675 public Image getImage (int index) {
676 	checkWidget ();
677 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
678 	return _getImage (index);
679 }
680 
681 /**
682  * Returns a rectangle describing the size and location
683  * relative to its parent of an image at a column in the
684  * tree.
685  *
686  * @param index the index that specifies the column
687  * @return the receiver's bounding image rectangle
688  *
689  * @exception SWTException <ul>
690  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
691  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
692  * </ul>
693  *
694  * @since 3.1
695  */
getImageBounds(int index)696 public Rectangle getImageBounds (int index) {
697 	checkWidget ();
698 	return DPIUtil.autoScaleDown(getImageBoundsInPixels(index));
699 }
700 
getImageBoundsInPixels(int index)701 Rectangle getImageBoundsInPixels (int index) {
702 	// TODO fully test on early and later versions of GTK
703 	checkWidget ();
704 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
705 	long parentHandle = parent.handle;
706 	long column = 0;
707 	if (index >= 0 && index < parent.getColumnCount ()) {
708 		column = parent.columns [index].handle;
709 	} else {
710 		column = GTK.gtk_tree_view_get_column (parentHandle, index);
711 	}
712 	if (column == 0) return new Rectangle (0, 0, 0, 0);
713 	long pixbufRenderer = parent.getPixbufRenderer (column);
714 	if (pixbufRenderer == 0)  return new Rectangle (0, 0, 0, 0);
715 	GdkRectangle rect = new GdkRectangle ();
716 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
717 	GTK.gtk_widget_realize (parentHandle);
718 	GTK.gtk_tree_view_get_cell_area (parentHandle, path, column, rect);
719 	if ((parent.getStyle () & SWT.MIRRORED) != 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
720 	GTK.gtk_tree_path_free (path);
721 	/*
722 	 * Feature in GTK. When a pixbufRenderer has size of 0x0, gtk_tree_view_column_cell_get_position
723 	 * returns a position of 0 as well. This causes offset issues meaning that images/widgets/etc.
724 	 * can be placed over the text. We need to account for the base case of a pixbufRenderer that has
725 	 * yet to be sized, as per Bug 469277 & 476419. NOTE: this change has been ported to Tables since Tables/Trees both
726 	 * use the same underlying GTK structure.
727 	 */
728 	int [] x = new int [1], w = new int [1];
729 	gtk_tree_view_column_cell_get_position (column, pixbufRenderer, x, w);
730 	if (parent.pixbufSizeSet) {
731 		if (x [0] > 0) {
732 			rect.x += x [0];
733 		}
734 	} else {
735 		/*
736 		 * If the size of the pixbufRenderer hasn't been set, we need to take into account the
737 		 * position of the textRenderer, to ensure images/widgets/etc. aren't placed over the TreeItem's
738 		 * text.
739 		 */
740 		long textRenderer = parent.getTextRenderer (column);
741 		if (textRenderer == 0)  return new Rectangle (0, 0, 0, 0);
742 		int [] xText = new int [1], wText = new int [1];
743 		gtk_tree_view_column_cell_get_position (column, textRenderer, xText, wText);
744 		rect.x += xText [0];
745 	}
746 	rect.width = w [0];
747 	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
748 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
749 	/*
750 	 * On GTK4 the header is included in the entire widget's surface, so we must subtract
751 	 * its size from the y-coordinate. This does not apply on GTK3 as the header and
752 	 * "main-widget" have separate GdkWindows.
753 	 */
754 	if (parent!= null && parent.getHeaderVisible () && GTK.GTK4) {
755 		r.y += parent.getHeaderHeight();
756 	}
757 	return r;
758 }
759 
760 /**
761  * Returns the number of items contained in the receiver
762  * that are direct item children of the receiver.
763  *
764  * @return the number of items
765  *
766  * @exception SWTException <ul>
767  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
768  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
769  * </ul>
770  */
getItemCount()771 public int getItemCount () {
772 	checkWidget();
773 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
774 	return GTK.gtk_tree_model_iter_n_children (parent.modelHandle, handle);
775 }
776 
777 /**
778  * Returns the item at the given, zero-relative index in the
779  * receiver. Throws an exception if the index is out of range.
780  *
781  * @param index the index of the item to return
782  * @return the item at the given index
783  *
784  * @exception IllegalArgumentException <ul>
785  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
786  * </ul>
787  * @exception SWTException <ul>
788  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
789  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
790  * </ul>
791  *
792  * @since 3.1
793  */
getItem(int index)794 public TreeItem getItem (int index) {
795 	checkWidget();
796 	if (index < 0) error (SWT.ERROR_INVALID_RANGE);
797 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
798 	int itemCount = GTK.gtk_tree_model_iter_n_children (parent.modelHandle, handle);
799 	if (index >= itemCount)  error (SWT.ERROR_INVALID_RANGE);
800 	return  parent._getItem (handle, index);
801 }
802 
803 /**
804  * Returns a (possibly empty) array of <code>TreeItem</code>s which
805  * are the direct item children of the receiver.
806  * <p>
807  * Note: This is not the actual structure used by the receiver
808  * to maintain its list of items, so modifying the array will
809  * not affect the receiver.
810  * </p>
811  *
812  * @return the receiver's items
813  *
814  * @exception SWTException <ul>
815  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
816  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
817  * </ul>
818  */
getItems()819 public TreeItem [] getItems () {
820 	checkWidget();
821 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
822 	return parent.getItems (handle);
823 }
824 
825 @Override
getNameText()826 String getNameText () {
827 	if ((parent.style & SWT.VIRTUAL) != 0) {
828 		if (!cached) return "*virtual*"; //$NON-NLS-1$
829 	}
830 	return super.getNameText ();
831 }
832 
833 /**
834  * Returns the receiver's parent, which must be a <code>Tree</code>.
835  *
836  * @return the receiver's parent
837  *
838  * @exception SWTException <ul>
839  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
840  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
841  * </ul>
842  */
getParent()843 public Tree getParent () {
844 	checkWidget ();
845 	return parent;
846 }
847 
848 /**
849  * Returns the receiver's parent item, which must be a
850  * <code>TreeItem</code> or null when the receiver is a
851  * root.
852  *
853  * @return the receiver's parent item
854  *
855  * @exception SWTException <ul>
856  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
857  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
858  * </ul>
859  */
getParentItem()860 public TreeItem getParentItem () {
861 	checkWidget();
862 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
863 	TreeItem item = null;
864 	int depth = GTK.gtk_tree_path_get_depth (path);
865 	if (depth > 1) {
866 		GTK.gtk_tree_path_up (path);
867 		long iter = OS.g_malloc (GTK.GtkTreeIter_sizeof ());
868 		if (GTK.gtk_tree_model_get_iter (parent.modelHandle, iter, path)) {
869 			item = parent._getItem (iter);
870 		}
871 		OS.g_free (iter);
872 	}
873 	GTK.gtk_tree_path_free (path);
874 	return item;
875 }
876 
877 @Override
getText()878 public String getText () {
879 	checkWidget ();
880 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
881 	return getText (0);
882 }
883 
884 /**
885  * Returns the text stored at the given column index in the receiver,
886  * or empty string if the text has not been set.
887  *
888  * @param index the column index
889  * @return the text stored at the given column index in the receiver
890  *
891  * @exception SWTException <ul>
892  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
893  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
894  * </ul>
895  *
896  * @since 3.1
897  */
getText(int index)898 public String getText (int index) {
899 	checkWidget ();
900 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
901 	if (strings != null) {
902 		if (0 <= index && index < strings.length) {
903 			String string = strings [index];
904 			return string != null ? string : "";
905 		}
906 	}
907 	return _getText (index);
908 }
909 
910 /**
911  * Returns a rectangle describing the size and location
912  * relative to its parent of the text at a column in the
913  * tree.
914  *
915  * @param index the index that specifies the column
916  * @return the receiver's bounding text rectangle
917  *
918  * @exception SWTException <ul>
919  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
920  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
921  * </ul>
922  *
923  * @since 3.3
924  */
getTextBounds(int index)925 public Rectangle getTextBounds (int index) {
926 	checkWidget ();
927 	return DPIUtil.autoScaleDown(getTextBoundsInPixels(index));
928 }
929 
getTextBoundsInPixels(int index)930 Rectangle getTextBoundsInPixels (int index) {
931 	checkWidget ();
932 	if (!parent.checkData (this)) error (SWT.ERROR_WIDGET_DISPOSED);
933 	int count = Math.max (1, parent.getColumnCount ());
934 	if (0 > index || index > count - 1) return new Rectangle (0, 0, 0, 0);
935 	// TODO fully test on early and later versions of GTK
936 	// shifted a bit too far right on later versions of GTK - however, old Tree also had this problem
937 	long parentHandle = parent.handle;
938 	long column = 0;
939 	if (index >= 0 && index < parent.columnCount) {
940 		column = parent.columns [index].handle;
941 	} else {
942 		column = GTK.gtk_tree_view_get_column (parentHandle, index);
943 	}
944 	if (column == 0) return new Rectangle (0, 0, 0, 0);
945 	long textRenderer = parent.getTextRenderer (column);
946 	long pixbufRenderer = parent.getPixbufRenderer (column);
947 	if (textRenderer == 0 || pixbufRenderer == 0)  return new Rectangle (0, 0, 0, 0);
948 
949 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
950 	GTK.gtk_widget_realize (parentHandle);
951 
952 	boolean isExpander = GTK.gtk_tree_model_iter_n_children (parent.modelHandle, handle) > 0;
953 	boolean isExpanded = GTK.gtk_tree_view_row_expanded (parentHandle, path);
954 	GTK.gtk_tree_view_column_cell_set_cell_data (column, parent.modelHandle, handle, isExpander, isExpanded);
955 
956 	GdkRectangle rect = new GdkRectangle ();
957 	GTK.gtk_tree_view_get_cell_area (parentHandle, path, column, rect);
958 	if ((parent.getStyle () & SWT.MIRRORED) != 0) rect.x = parent.getClientWidth () - rect.width - rect.x;
959 	int right = rect.x + rect.width;
960 
961 	int [] x = new int [1], w = new int [1];
962 	parent.ignoreSize = true;
963 	gtk_cell_renderer_get_preferred_size (textRenderer, parentHandle, w, null);
964 	parent.ignoreSize = false;
965 	int [] buffer = new int [1];
966 	GTK.gtk_tree_path_free (path);
967 
968 	int horizontalSeparator;
969 	if (GTK.GTK4) {
970 		long separator = GTK.gtk_separator_new(GTK.GTK_ORIENTATION_HORIZONTAL);
971 		GtkAllocation allocation = new GtkAllocation ();
972 		GTK.gtk_widget_get_allocation(separator, allocation);
973 		horizontalSeparator = allocation.height;
974 	} else {
975 		GTK3.gtk_widget_style_get (parentHandle, OS.horizontal_separator, buffer, 0);
976 		horizontalSeparator = buffer[0];
977 	}
978 	rect.x += horizontalSeparator;
979 	gtk_tree_view_column_cell_get_position (column, textRenderer, x, null);
980 	/*
981 	 * Fix for Eclipse bug 476562, we need to re-adjust the bounds for the text
982 	 * when the separator value is less than the width of the image. Previously
983 	 * images larger than 16px in width would be cut off on the right side.
984 	 * NOTE: this change has been ported to Tables since Tables/Trees both use the
985 	 * same underlying GTK structure.
986 	 */
987 	Image image = _getImage(index);
988 	int imageWidth = 0;
989 	if (image != null) {
990 		if (DPIUtil.useCairoAutoScale()) {
991 			imageWidth = image.getBounds ().width;
992 		} else {
993 			imageWidth = image.getBoundsInPixels ().width;
994 		}
995 	}
996 	if (x [0] < imageWidth) {
997 		rect.x += imageWidth;
998 	} else {
999 		rect.x += x [0];
1000 	}
1001 	if (parent.columnCount > 0) {
1002 		if (rect.x + rect.width > right) {
1003 			rect.width = Math.max (0, right - rect.x);
1004 		}
1005 	}
1006 	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
1007 	return new Rectangle (rect.x, rect.y, width, rect.height + 1);
1008 }
1009 
1010 /**
1011  * Searches the receiver's list starting at the first item
1012  * (index 0) until an item is found that is equal to the
1013  * argument, and returns the index of that item. If no item
1014  * is found, returns -1.
1015  *
1016  * @param item the search item
1017  * @return the index of the item
1018  *
1019  * @exception IllegalArgumentException <ul>
1020  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
1021  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
1022  * </ul>
1023  * @exception SWTException <ul>
1024  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1025  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1026  * </ul>
1027  *
1028  * @since 3.1
1029  */
indexOf(TreeItem item)1030 public int indexOf (TreeItem item) {
1031 	checkWidget();
1032 	if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
1033 	if (item.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
1034 	int index = -1;
1035 	boolean isParent = false;
1036 	long currentPath = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
1037 	long parentPath = GTK.gtk_tree_model_get_path (parent.modelHandle, item.handle);
1038 	int depth = GTK.gtk_tree_path_get_depth (parentPath);
1039 	if (depth > 1 && GTK.gtk_tree_path_up(parentPath)) {
1040 		if (GTK.gtk_tree_path_compare(currentPath, parentPath) == 0) isParent = true;
1041 	}
1042 	GTK.gtk_tree_path_free (currentPath);
1043 	GTK.gtk_tree_path_free (parentPath);
1044 	if (!isParent) return index;
1045 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, item.handle);
1046 	if (depth > 1) {
1047 		long indices = GTK.gtk_tree_path_get_indices (path);
1048 		if (indices != 0) {
1049 			int[] temp = new int[depth];
1050 			C.memmove (temp, indices, 4 * temp.length);
1051 			index = temp[temp.length - 1];
1052 		}
1053 	}
1054 	GTK.gtk_tree_path_free (path);
1055 	return index;
1056 }
1057 
1058 @Override
releaseChildren(boolean destroy)1059 void releaseChildren (boolean destroy) {
1060 	if (destroy) {
1061 		parent.releaseItems (handle);
1062 	}
1063 	super.releaseChildren (destroy);
1064 }
1065 
1066 @Override
releaseHandle()1067 void releaseHandle () {
1068 	if (handle != 0) OS.g_free (handle);
1069 	handle = 0;
1070 	super.releaseHandle ();
1071 	parent = null;
1072 }
1073 
1074 @Override
releaseWidget()1075 void releaseWidget () {
1076 	super.releaseWidget ();
1077 	font = null;
1078 	cellFont = null;
1079 	strings = null;
1080 }
1081 
1082 @Override
dispose()1083 public void dispose () {
1084 	// Workaround to Bug489751, avoid selecting next node when selected node is disposed.
1085 	Tree tmpParent = null;
1086 	if (parent != null && parent.getItemCount() > 0 && parent.getSelectionCount() == 0) {
1087 		tmpParent = parent;
1088 	}
1089 	super.dispose();
1090 	if (tmpParent != null && !tmpParent.isDisposed()) tmpParent.deselectAll();
1091 }
1092 
1093 /**
1094  * Removes all of the items from the receiver.
1095  *
1096  * @exception SWTException <ul>
1097  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1098  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1099  * </ul>
1100  *
1101  * @since 3.1
1102  */
removeAll()1103 public void removeAll () {
1104 	checkWidget ();
1105 	long modelHandle = parent.modelHandle;
1106 	int length = GTK.gtk_tree_model_iter_n_children (modelHandle, handle);
1107 	if (length == 0) return;
1108 	long iter = OS.g_malloc (GTK.GtkTreeIter_sizeof ());
1109 	if (iter == 0) error (SWT.ERROR_NO_HANDLES);
1110 	if (parent.fixAccessibility ()) {
1111 		parent.ignoreAccessibility = true;
1112 	}
1113 	long selection = GTK.gtk_tree_view_get_selection (parent.handle);
1114 	int [] value = new int [1];
1115 	while (GTK.gtk_tree_model_iter_children (modelHandle, iter, handle)) {
1116 		GTK.gtk_tree_model_get (modelHandle, iter, Tree.ID_COLUMN, value, -1);
1117 		TreeItem item = value [0] != -1 ? parent.items [value [0]] : null;
1118 		if (item != null && !item.isDisposed ()) {
1119 			item.dispose ();
1120 		} else {
1121 			OS.g_signal_handlers_block_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1122 			GTK.gtk_tree_store_remove (modelHandle, iter);
1123 			OS.g_signal_handlers_unblock_matched (selection, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, CHANGED);
1124 		}
1125 	}
1126 	if (parent.fixAccessibility ()) {
1127 		parent.ignoreAccessibility = false;
1128 		OS.g_object_notify (parent.handle, OS.model);
1129 	}
1130 	OS.g_free (iter);
1131 }
1132 
1133 /**
1134  * Sets the receiver's background color to the color specified
1135  * by the argument, or to the default system color for the item
1136  * if the argument is null.
1137  *
1138  * @param color the new color (or null)
1139  *
1140  * @exception IllegalArgumentException <ul>
1141  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1142  * </ul>
1143  * @exception SWTException <ul>
1144  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1145  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1146  * </ul>
1147  *
1148  * @since 2.0
1149  *
1150  */
setBackground(Color color)1151 public void setBackground (Color color) {
1152 	checkWidget ();
1153 	if (color != null && color.isDisposed ()) {
1154 		error (SWT.ERROR_INVALID_ARGUMENT);
1155 	}
1156 	if (_getBackground ().equals (color)) return;
1157 	GdkRGBA gdkRGBA = color != null ? color.handle : null;
1158 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.BACKGROUND_COLUMN, gdkRGBA, -1);
1159 	cached = true;
1160 }
1161 
1162 /**
1163  * Sets the background color at the given column index in the receiver
1164  * to the color specified by the argument, or to the default system color for the item
1165  * if the argument is null.
1166  *
1167  * @param index the column index
1168  * @param color the new color (or null)
1169  *
1170  * @exception IllegalArgumentException <ul>
1171  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1172  * </ul>
1173  * @exception SWTException <ul>
1174  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1175  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1176  * </ul>
1177  *
1178  * @since 3.1
1179  *
1180  */
setBackground(int index, Color color)1181 public void setBackground (int index, Color color) {
1182 	checkWidget ();
1183 	if (color != null && color.isDisposed ()) {
1184 		error (SWT.ERROR_INVALID_ARGUMENT);
1185 	}
1186 	if (_getBackground (index).equals (color)) return;
1187 	int count = Math.max (1, parent.getColumnCount ());
1188 	if (0 > index || index > count - 1) return;
1189 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
1190 	GdkRGBA gdkRGBA = color != null ? color.handle : null;
1191 	GTK.gtk_tree_store_set (parent.modelHandle, handle, modelIndex + Tree.CELL_BACKGROUND, gdkRGBA, -1);
1192 	cached = true;
1193 	updated = true;
1194 
1195 	if (color != null) {
1196 		boolean customDraw = (parent.columnCount == 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
1197 		if (!customDraw) {
1198 			if ((parent.style & SWT.VIRTUAL) == 0) {
1199 				long parentHandle = parent.handle;
1200 				long column = 0;
1201 				if (parent.columnCount > 0) {
1202 					column = parent.columns [index].handle;
1203 				} else {
1204 					column = GTK.gtk_tree_view_get_column (parentHandle, index);
1205 				}
1206 				if (column == 0) return;
1207 				long textRenderer = parent.getTextRenderer (column);
1208 				long imageRenderer = parent.getPixbufRenderer (column);
1209 				GTK.gtk_tree_view_column_set_cell_data_func (column, textRenderer, display.cellDataProc, parentHandle, 0);
1210 				GTK.gtk_tree_view_column_set_cell_data_func (column, imageRenderer, display.cellDataProc, parentHandle, 0);
1211 			}
1212 			if (parent.columnCount == 0) {
1213 				parent.firstCustomDraw = true;
1214 			} else {
1215 				parent.columns [index].customDraw = true;
1216 			}
1217 		}
1218 	}
1219 }
1220 
1221 /**
1222  * Sets the checked state of the receiver.
1223  * <p>
1224  *
1225  * @param checked the new checked state
1226  *
1227  * @exception SWTException <ul>
1228  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1229  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1230  * </ul>
1231  */
setChecked(boolean checked)1232 public void setChecked (boolean checked) {
1233 	checkWidget();
1234 	if ((parent.style & SWT.CHECK) == 0) return;
1235 	if (_getChecked () == checked) return;
1236 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.CHECKED_COLUMN, checked, -1);
1237 	/*
1238 	* GTK+'s "inconsistent" state does not match SWT's concept of grayed.  To
1239 	* show checked+grayed differently from unchecked+grayed, we must toggle the
1240 	* grayed state on check and uncheck.
1241 	*/
1242 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.GRAYED_COLUMN, !checked ? false : grayed, -1);
1243 	cached = true;
1244 }
1245 
1246 /**
1247  * Sets the expanded state of the receiver.
1248  * <p>
1249  *
1250  * @param expanded the new expanded state
1251  *
1252  * @exception SWTException <ul>
1253  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1254  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1255  * </ul>
1256  */
setExpanded(boolean expanded)1257 public void setExpanded (boolean expanded) {
1258 	checkWidget();
1259 	long path = GTK.gtk_tree_model_get_path (parent.modelHandle, handle);
1260 	if (expanded != GTK.gtk_tree_view_row_expanded (parent.handle, path)) {
1261 		if (expanded) {
1262 			OS.g_signal_handlers_block_matched (parent.handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_EXPAND_ROW);
1263 			GTK.gtk_tree_view_expand_row (parent.handle, path, false);
1264 			OS.g_signal_handlers_unblock_matched (parent.handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_EXPAND_ROW);
1265 		} else {
1266 			OS.g_signal_handlers_block_matched (parent.handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_COLLAPSE_ROW);
1267 			GTK.gtk_widget_realize (parent.handle);
1268 			GTK.gtk_tree_view_collapse_row (parent.handle, path);
1269 			OS.g_signal_handlers_unblock_matched (parent.handle, OS.G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, TEST_COLLAPSE_ROW);
1270 		}
1271 	}
1272 	GTK.gtk_tree_path_free (path);
1273 	isExpanded = expanded;
1274 }
1275 
1276 
1277 /**
1278  * Sets the font that the receiver will use to paint textual information
1279  * for this item to the font specified by the argument, or to the default font
1280  * for that kind of control if the argument is null.
1281  *
1282  * @param font the new font (or null)
1283  *
1284  * @exception IllegalArgumentException <ul>
1285  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1286  * </ul>
1287  * @exception SWTException <ul>
1288  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1289  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1290  * </ul>
1291  *
1292  * @since 3.0
1293  */
setFont(Font font)1294 public void setFont (Font font){
1295 	checkWidget ();
1296 	if (font != null && font.isDisposed ()) {
1297 		error (SWT.ERROR_INVALID_ARGUMENT);
1298 	}
1299 	Font oldFont = this.font;
1300 	if (oldFont == font) return;
1301 	this.font = font;
1302 	if (oldFont != null && oldFont.equals (font)) return;
1303 	long fontHandle = font != null ? font.handle : 0;
1304 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.FONT_COLUMN, fontHandle, -1);
1305 	cached = true;
1306 }
1307 
1308 /**
1309  * Sets the font that the receiver will use to paint textual information
1310  * for the specified cell in this item to the font specified by the
1311  * argument, or to the default font for that kind of control if the
1312  * argument is null.
1313  *
1314  * @param index the column index
1315  * @param font the new font (or null)
1316  *
1317  * @exception IllegalArgumentException <ul>
1318  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1319  * </ul>
1320  * @exception SWTException <ul>
1321  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1322  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1323  * </ul>
1324  *
1325  * @since 3.1
1326  */
setFont(int index, Font font)1327 public void setFont (int index, Font font) {
1328 	checkWidget ();
1329 	if (font != null && font.isDisposed ()) {
1330 		error (SWT.ERROR_INVALID_ARGUMENT);
1331 	}
1332 	int count = Math.max (1, parent.getColumnCount ());
1333 	if (0 > index || index > count - 1) return;
1334 	if (cellFont == null) {
1335 		if (font == null) return;
1336 		cellFont = new Font [count];
1337 	}
1338 	Font oldFont = cellFont [index];
1339 	if (oldFont == font) return;
1340 	cellFont [index] = font;
1341 	if (oldFont != null && oldFont.equals (font)) return;
1342 
1343 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
1344 	long fontHandle  = font != null ? font.handle : 0;
1345 	GTK.gtk_tree_store_set (parent.modelHandle, handle, modelIndex + Tree.CELL_FONT, fontHandle, -1);
1346 	cached = true;
1347 
1348 	if (font != null) {
1349 		boolean customDraw = (parent.columnCount == 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
1350 		if (!customDraw) {
1351 			if ((parent.style & SWT.VIRTUAL) == 0) {
1352 				long parentHandle = parent.handle;
1353 				long column = 0;
1354 				if (parent.columnCount > 0) {
1355 					column = parent.columns [index].handle;
1356 				} else {
1357 					column = GTK.gtk_tree_view_get_column (parentHandle, index);
1358 				}
1359 				if (column == 0) return;
1360 				long textRenderer = parent.getTextRenderer (column);
1361 				long imageRenderer = parent.getPixbufRenderer (column);
1362 				GTK.gtk_tree_view_column_set_cell_data_func (column, textRenderer, display.cellDataProc, parentHandle, 0);
1363 				GTK.gtk_tree_view_column_set_cell_data_func (column, imageRenderer, display.cellDataProc, parentHandle, 0);
1364 			}
1365 			if (parent.columnCount == 0) {
1366 				parent.firstCustomDraw = true;
1367 			} else {
1368 				parent.columns [index].customDraw = true;
1369 			}
1370 		}
1371 	}
1372 }
1373 
1374 /**
1375  * Sets the receiver's foreground color to the color specified
1376  * by the argument, or to the default system color for the item
1377  * if the argument is null.
1378  *
1379  * @param color the new color (or null)
1380  *
1381  * @exception IllegalArgumentException <ul>
1382  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1383  * </ul>
1384  * @exception SWTException <ul>
1385  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1386  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1387  * </ul>
1388  *
1389  * @since 2.0
1390  *
1391  */
setForeground(Color color)1392 public void setForeground (Color color){
1393 	checkWidget ();
1394 	if (color != null && color.isDisposed ()) {
1395 		error (SWT.ERROR_INVALID_ARGUMENT);
1396 	}
1397 	if (_getForeground ().equals (color)) return;
1398 	GdkRGBA gdkRGBA = color != null ? color.handle : null;
1399 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.FOREGROUND_COLUMN, gdkRGBA, -1);
1400 	cached = true;
1401 }
1402 
1403 /**
1404  * Sets the foreground color at the given column index in the receiver
1405  * to the color specified by the argument, or to the default system color for the item
1406  * if the argument is null.
1407  *
1408  * @param index the column index
1409  * @param color the new color (or null)
1410  *
1411  * @exception IllegalArgumentException <ul>
1412  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1413  * </ul>
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  * @since 3.1
1420  *
1421  */
setForeground(int index, Color color)1422 public void setForeground (int index, Color color){
1423 	checkWidget ();
1424 	if (color != null && color.isDisposed ()) {
1425 		error (SWT.ERROR_INVALID_ARGUMENT);
1426 	}
1427 	if (_getForeground (index).equals (color)) return;
1428 	int count = Math.max (1, parent.getColumnCount ());
1429 	if (0 > index || index > count - 1) return;
1430 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
1431 	GdkRGBA gdkRGBA = color != null ? color.handle : null;
1432 	GTK.gtk_tree_store_set (parent.modelHandle, handle, modelIndex + Tree.CELL_FOREGROUND, gdkRGBA, -1);
1433 	cached = true;
1434 	updated = true;
1435 
1436 	if (color != null) {
1437 		boolean customDraw = (parent.columnCount == 0)  ? parent.firstCustomDraw : parent.columns [index].customDraw;
1438 		if (!customDraw) {
1439 			if ((parent.style & SWT.VIRTUAL) == 0) {
1440 				long parentHandle = parent.handle;
1441 				long column = 0;
1442 				if (parent.columnCount > 0) {
1443 					column = parent.columns [index].handle;
1444 				} else {
1445 					column = GTK.gtk_tree_view_get_column (parentHandle, index);
1446 				}
1447 				if (column == 0) return;
1448 				long textRenderer = parent.getTextRenderer (column);
1449 				long imageRenderer = parent.getPixbufRenderer (column);
1450 				GTK.gtk_tree_view_column_set_cell_data_func (column, textRenderer, display.cellDataProc, parentHandle, 0);
1451 				GTK.gtk_tree_view_column_set_cell_data_func (column, imageRenderer, display.cellDataProc, parentHandle, 0);
1452 			}
1453 			if (parent.columnCount == 0) {
1454 				parent.firstCustomDraw = true;
1455 			} else {
1456 				parent.columns [index].customDraw = true;
1457 			}
1458 		}
1459 	}
1460 }
1461 
1462 /**
1463  * Sets the grayed state of the checkbox for this item.  This state change
1464  * only applies if the Tree was created with the SWT.CHECK style.
1465  *
1466  * @param grayed the new grayed state of the checkbox
1467  *
1468  * @exception SWTException <ul>
1469  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1470  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1471  * </ul>
1472  */
setGrayed(boolean grayed)1473 public void setGrayed (boolean grayed) {
1474 	checkWidget();
1475 	if ((parent.style & SWT.CHECK) == 0) return;
1476 	if (this.grayed == grayed) return;
1477 	this.grayed = grayed;
1478 	/*
1479 	* GTK+'s "inconsistent" state does not match SWT's concept of grayed.
1480 	* Render checked+grayed as "inconsistent", unchecked+grayed as blank.
1481 	*/
1482 	int [] ptr = new int [1];
1483 	GTK.gtk_tree_model_get (parent.modelHandle, handle, Tree.CHECKED_COLUMN, ptr, -1);
1484 	GTK.gtk_tree_store_set (parent.modelHandle, handle, Tree.GRAYED_COLUMN, ptr [0] == 0 ? false : grayed, -1);
1485 	cached = true;
1486 }
1487 
1488 /**
1489  * Sets the receiver's image at a column.
1490  *
1491  * @param index the column index
1492  * @param image the new image
1493  *
1494  * @exception IllegalArgumentException <ul>
1495  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
1496  * </ul>
1497  * @exception SWTException <ul>
1498  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1499  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1500  * </ul>
1501  *
1502  * @since 3.1
1503  */
setImage(int index, Image image)1504 public void setImage(int index, Image image) {
1505 	checkWidget ();
1506 	if (image != null && image.isDisposed()) {
1507 		error(SWT.ERROR_INVALID_ARGUMENT);
1508 	}
1509 	if (image != null && image.type == SWT.ICON) {
1510 		if (image.equals(_getImage(index))) return;
1511 	}
1512 	int count = Math.max(1, parent.getColumnCount());
1513 	if (0 > index || index > count - 1) return;
1514 
1515 	long pixbuf = 0, surface = 0;
1516 	if (image != null) {
1517 		ImageList imageList = parent.imageList;
1518 		if (imageList == null) imageList = parent.imageList = new ImageList();
1519 		int imageIndex = imageList.indexOf(image);
1520 		// When we create a blank image surface gets created with dimensions 0, 0.
1521         // This call recreates the surface with correct dimensions
1522 		surface = ImageList.convertSurface(image);
1523 		if (imageIndex == -1) {
1524 			imageIndex = imageList.add(image);
1525 		}
1526 		surface = imageList.getSurface(imageIndex);
1527 		pixbuf = ImageList.createPixbuf(surface);
1528 	}
1529 
1530 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
1531 	long parentHandle = parent.handle;
1532 	long column = GTK.gtk_tree_view_get_column (parentHandle, index);
1533 	long pixbufRenderer = parent.getPixbufRenderer (column);
1534 	int [] currentWidth = new int [1];
1535 	int [] currentHeight= new int [1];
1536 	GTK.gtk_cell_renderer_get_fixed_size (pixbufRenderer, currentWidth, currentHeight);
1537 	if (!parent.pixbufSizeSet) {
1538 		if (image != null) {
1539 			int iWidth, iHeight;
1540 			if (DPIUtil.useCairoAutoScale()) {
1541 				iWidth = image.getBounds ().width;
1542 				iHeight = image.getBounds ().height;
1543 			} else {
1544 				iWidth = image.getBoundsInPixels ().width;
1545 				iHeight = image.getBoundsInPixels ().height;
1546 			}
1547 			if (iWidth > currentWidth [0] || iHeight > currentHeight [0]) {
1548 				GTK.gtk_cell_renderer_set_fixed_size (pixbufRenderer, iWidth, iHeight);
1549 				parent.pixbufSizeSet = true;
1550 				parent.pixbufHeight = iHeight;
1551 				parent.pixbufWidth = iWidth;
1552 				/*
1553 				 * Feature in GTK: a Tree with the style SWT.VIRTUAL has
1554 				 * fixed-height-mode enabled. This will limit the size of
1555 				 * any cells, including renderers. In order to prevent
1556 				 * images from disappearing/being cropped, we re-create
1557 				 * the renderers when the first image is set. Fix for
1558 				 * bug 480261.
1559 				 */
1560 				if ((parent.style & SWT.VIRTUAL) != 0) {
1561 					/*
1562 					 * Only re-create SWT.CHECK renderers if this is the first column.
1563 					 * Otherwise check-boxes will be rendered in columns they are not
1564 					 * supposed to be rendered in. See bug 513761.
1565 					 */
1566 					boolean check = modelIndex == Tree.FIRST_COLUMN && (parent.style & SWT.CHECK) != 0;
1567 					parent.createRenderers(column, modelIndex, check, parent.style);
1568 				}
1569 			}
1570 		}
1571 	} else {
1572 		/*
1573 		 * Bug 483112: We check to see if the cached value is greater than the size of the pixbufRenderer.
1574 		 * If it is, then we change the size of the pixbufRenderer accordingly.
1575 		 * Bug 489025: There is a corner case where the below is triggered when current(Width|Height) is -1,
1576 		 * which results in icons being set to 0. Fix is to compare only positive sizes.
1577 		 */
1578 		if (parent.pixbufWidth > Math.max(currentWidth [0], 0) || parent.pixbufHeight > Math.max(currentHeight [0], 0)) {
1579 			GTK.gtk_cell_renderer_set_fixed_size (pixbufRenderer, parent.pixbufWidth, parent.pixbufHeight);
1580 		}
1581 	}
1582 
1583 	GTK.gtk_tree_store_set(parent.modelHandle, handle, modelIndex + Tree.CELL_PIXBUF, pixbuf, -1);
1584 	GTK.gtk_tree_store_set(parent.modelHandle, handle, modelIndex + Tree.CELL_SURFACE, surface, -1);
1585 	cached = true;
1586 	updated = true;
1587 }
1588 
1589 @Override
setImage(Image image)1590 public void setImage (Image image) {
1591 	checkWidget ();
1592 	setImage (0, image);
1593 }
1594 
1595 /**
1596  * Sets the image for multiple columns in the tree.
1597  *
1598  * @param images the array of new images
1599  *
1600  * @exception IllegalArgumentException <ul>
1601  *    <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
1602  *    <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
1603  * </ul>
1604  * @exception SWTException <ul>
1605  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1606  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1607  * </ul>
1608  *
1609  * @since 3.1
1610  */
setImage(Image [] images)1611 public void setImage (Image [] images) {
1612 	checkWidget ();
1613 	if (images == null) error (SWT.ERROR_NULL_ARGUMENT);
1614 	for (int i=0; i<images.length; i++) {
1615 		setImage (i, images [i]);
1616 	}
1617 }
1618 
1619 /**
1620  * Sets the number of child items contained in the receiver.
1621  *
1622  * @param count the number of items
1623  *
1624  * @exception SWTException <ul>
1625  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1626  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1627  * </ul>
1628  *
1629  * @since 3.2
1630  */
setItemCount(int count)1631 public void setItemCount (int count) {
1632 	checkWidget ();
1633 	count = Math.max (0, count);
1634 	parent.setItemCount (handle, count);
1635 }
1636 
1637 /**
1638  * Sets the receiver's text at a column
1639  * <p>
1640  * Note: If control characters like '\n', '\t' etc. are used
1641  * in the string, then the behavior is platform dependent.
1642  * </p>
1643  * @param index the column index
1644  * @param string the new text
1645  *
1646  * @exception IllegalArgumentException <ul>
1647  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1648  * </ul>
1649  * @exception SWTException <ul>
1650  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1651  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1652  * </ul>
1653  *
1654  * @since 3.1
1655  */
setText(int index, String string)1656 public void setText (int index, String string) {
1657 	checkWidget ();
1658 	if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1659 	if (strings == null) {
1660 		if (_getText (index).equals (string)) return;
1661 	}
1662 	else if ( getText (index).equals (string)) return;
1663 
1664 	int count = Math.max (1, parent.getColumnCount ());
1665 	if (0 > index || index > count - 1) return;
1666 	if (0 <= index && index < count) {
1667 		if (strings == null) strings = new String [count];
1668 		if (string.equals (strings [index])) return;
1669 		strings [index] = string;
1670 	}
1671 	if ((string != null) && (string.length() > TEXT_LIMIT)) {
1672 		string = string.substring(0, TEXT_LIMIT - ELLIPSIS.length()) + ELLIPSIS;
1673 	}
1674 	byte[] buffer = Converter.wcsToMbcs (string, true);
1675 	int modelIndex = parent.columnCount == 0 ? Tree.FIRST_COLUMN : parent.columns [index].modelIndex;
1676 	GTK.gtk_tree_store_set (parent.modelHandle, handle, modelIndex + Tree.CELL_TEXT, buffer, -1);
1677 	cached = true;
1678 	updated = true;
1679 }
1680 
1681 @Override
setText(String string)1682 public void setText (String string) {
1683 	checkWidget ();
1684 	setText (0, string);
1685 }
1686 
1687 /**
1688  * Sets the text for multiple columns in the tree.
1689  * <p>
1690  * Note: If control characters like '\n', '\t' etc. are used
1691  * in the string, then the behavior is platform dependent.
1692  * </p>
1693  * @param strings the array of new strings
1694  *
1695  * @exception IllegalArgumentException <ul>
1696  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1697  * </ul>
1698  * @exception SWTException <ul>
1699  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1700  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1701  * </ul>
1702  *
1703  * @since 3.1
1704  */
setText(String [] strings)1705 public void setText (String [] strings) {
1706 	checkWidget ();
1707 	if (strings == null) error (SWT.ERROR_NULL_ARGUMENT);
1708 	for (int i=0; i<strings.length; i++) {
1709 		String string = strings [i];
1710 		if (string != null) setText (i, string);
1711 	}
1712 }
1713 }
1714