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