]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/TreeItem.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / TreeItem.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 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.win32.*;
21
22 /**
23  * Instances of this class represent a selectable user interface object
24  * that represents a hierarchy of tree items in a tree widget.
25  *
26  * <dl>
27  * <dt><b>Styles:</b></dt>
28  * <dd>(none)</dd>
29  * <dt><b>Events:</b></dt>
30  * <dd>(none)</dd>
31  * </dl>
32  * <p>
33  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
34  * </p>
35  *
36  * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
37  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
38  * @noextend This class is not intended to be subclassed by clients.
39  */
40 public class TreeItem extends Item {
41         /**
42          * the handle to the OS resource
43          * (Warning: This field is platform dependent)
44          * <p>
45          * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
46          * public API. It is marked public only so that it can be shared
47          * within the packages provided by SWT. It is not available on all
48          * platforms and should never be accessed from application code.
49          * </p>
50          *
51          * @noreference This field is not intended to be referenced by clients.
52          */
53         public long handle;
54         Tree parent;
55         String [] strings;
56         Image [] images;
57         Font font;
58         Font [] cellFont;
59         boolean cached;
60         int background = -1, foreground = -1;
61         int [] cellBackground, cellForeground;
62
63 /**
64  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
65  * Item is inserted as last direct child of the tree.
66  * <p>
67  * For bulk insert scenarios, see TreeItem#TreeItem(Tree,int,int)
68  *
69  * @param parent a tree control which will be the parent of the new instance (cannot be null)
70  * @param style no styles are currently supported, pass SWT.NONE
71  *
72  * @exception IllegalArgumentException <ul>
73  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
74  * </ul>
75  * @exception SWTException <ul>
76  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
77  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
78  * </ul>
79  *
80  * @see SWT
81  * @see Widget#checkSubclass
82  * @see Widget#getStyle
83  */
84 public TreeItem (Tree parent, int style) {
85         this (parent, style, OS.TVGN_ROOT, OS.TVI_LAST, 0);
86 }
87
88 /**
89  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
90  * Item is inserted as <code>index</code> direct child of the tree.
91  * <p>
92  * The fastest way to insert many items is:
93  * <ol>
94  * <li>Use {@link Tree#setRedraw} to disable drawing during bulk insert</li>
95  * <li>Insert every item at index 0 (insert them in reverse to get the same result)</li>
96  * </ol>
97  *
98  * @param parent a tree control which will be the parent of the new instance (cannot be null)
99  * @param style no styles are currently supported, pass SWT.NONE
100  * @param index the zero-relative index to store the receiver in its parent
101  *
102  * @exception IllegalArgumentException <ul>
103  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
104  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
105  * </ul>
106  * @exception SWTException <ul>
107  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
108  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
109  * </ul>
110  *
111  * @see SWT
112  * @see Widget#checkSubclass
113  * @see Widget#getStyle
114  * @see Tree#setRedraw
115  */
116 public TreeItem (Tree parent, int style, int index) {
117         this (parent, style, OS.TVGN_ROOT, findPrevious (parent, index), 0);
118 }
119
120 /**
121  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
122  * Item is inserted as last direct child of the specified <code>TreeItem</code>.
123  * <p>
124  * For bulk insert scenarios, see TreeItem#TreeItem(TreeItem,int,int)
125  *
126  * @param parentItem a tree control which will be the parent of the new instance (cannot be null)
127  * @param style no styles are currently supported, pass SWT.NONE
128  *
129  * @exception IllegalArgumentException <ul>
130  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
131  * </ul>
132  * @exception SWTException <ul>
133  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
134  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
135  * </ul>
136  *
137  * @see SWT
138  * @see Widget#checkSubclass
139  * @see Widget#getStyle
140  */
141 public TreeItem (TreeItem parentItem, int style) {
142         this (checkNull (parentItem).parent, style, parentItem.handle, OS.TVI_LAST, 0);
143 }
144
145 /**
146  * Constructs <code>TreeItem</code> and <em>inserts</em> it into <code>Tree</code>.
147  * Item is inserted as <code>index</code> direct child of the specified <code>TreeItem</code>.
148  * <p>
149  * The fastest way to insert many items is:
150  * <ol>
151  * <li>Use {@link Tree#setRedraw} to disable drawing during bulk insert</li>
152  * <li>Insert child items while parent item is collapsed</li>
153  * <li>Insert every item at index 0 (insert them in reverse to get the same result)</li>
154  * </ol>
155  *
156  * @param parentItem a tree control which will be the parent of the new instance (cannot be null)
157  * @param style no styles are currently supported, pass SWT.NONE
158  * @param index the zero-relative index to store the receiver in its parent
159  *
160  * @exception IllegalArgumentException <ul>
161  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
162  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
163  * </ul>
164  * @exception SWTException <ul>
165  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
166  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
167  * </ul>
168  *
169  * @see SWT
170  * @see Widget#checkSubclass
171  * @see Widget#getStyle
172  * @see Tree#setRedraw
173  */
174 public TreeItem (TreeItem parentItem, int style, int index) {
175         this (checkNull (parentItem).parent, style, parentItem.handle, findPrevious (parentItem, index), 0);
176 }
177
178 TreeItem (Tree parent, int style, long hParent, long hInsertAfter, long hItem) {
179         super (parent, style);
180         this.parent = parent;
181         parent.createItem (this, hParent, hInsertAfter, hItem);
182 }
183
184 static TreeItem checkNull (TreeItem item) {
185         if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
186         return item;
187 }
188
189 static long findPrevious (Tree parent, int index) {
190         if (parent == null) return 0;
191         if (index < 0) SWT.error (SWT.ERROR_INVALID_RANGE);
192         if (index == 0) return OS.TVI_FIRST;
193         long hwnd = parent.handle;
194         long hFirstItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
195         long hItem = parent.findItem (hFirstItem, index - 1);
196         if (hItem == 0) SWT.error (SWT.ERROR_INVALID_RANGE);
197         return hItem;
198 }
199
200 static long findPrevious (TreeItem parentItem, int index) {
201         if (parentItem == null) return 0;
202         if (index < 0) SWT.error (SWT.ERROR_INVALID_RANGE);
203         if (index == 0) return OS.TVI_FIRST;
204         Tree parent = parentItem.parent;
205         long hwnd = parent.handle, hParent = parentItem.handle;
206         long hFirstItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
207         long hItem = parent.findItem (hFirstItem, index - 1);
208         if (hItem == 0) SWT.error (SWT.ERROR_INVALID_RANGE);
209         return hItem;
210 }
211
212 @Override
213 protected void checkSubclass () {
214         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
215 }
216
217 void clear () {
218         text = "";
219         image = null;
220         strings = null;
221         images = null;
222         if ((parent.style & SWT.CHECK) != 0) {
223                 long hwnd = parent.handle;
224                 TVITEM tvItem = new TVITEM ();
225                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
226                 tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
227                 tvItem.state = 1 << 12;
228                 tvItem.hItem = handle;
229                 OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
230         }
231         background = foreground = -1;
232         font = null;
233         cellBackground = cellForeground = null;
234         cellFont = null;
235         if ((parent.style & SWT.VIRTUAL) != 0) cached = false;
236 }
237
238 /**
239  * Clears the item at the given zero-relative index in the receiver.
240  * The text, icon and other attributes of the item are set to the default
241  * value.  If the tree was created with the <code>SWT.VIRTUAL</code> style,
242  * these attributes are requested again as needed.
243  *
244  * @param index the index of the item to clear
245  * @param all <code>true</code> if all child items of the indexed item should be
246  * cleared recursively, and <code>false</code> otherwise
247  *
248  * @exception IllegalArgumentException <ul>
249  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
250  * </ul>
251  * @exception SWTException <ul>
252  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
253  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
254  * </ul>
255  *
256  * @see SWT#VIRTUAL
257  * @see SWT#SetData
258  *
259  * @since 3.2
260  */
261 public void clear (int index, boolean all) {
262         checkWidget ();
263         long hwnd = parent.handle;
264         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
265         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
266         hItem = parent.findItem (hItem, index);
267         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
268         TVITEM tvItem = new TVITEM ();
269         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
270         parent.clear (hItem, tvItem);
271         if (all) {
272                 hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
273                 parent.clearAll (hItem, tvItem, all);
274         }
275 }
276
277 /**
278  * Clears all the items in the receiver. The text, icon and other
279  * attributes of the items are set to their default values. If the
280  * tree was created with the <code>SWT.VIRTUAL</code> style, these
281  * attributes are requested again as needed.
282  *
283  * @param all <code>true</code> if all child items should be cleared
284  * recursively, and <code>false</code> otherwise
285  *
286  * @exception SWTException <ul>
287  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
288  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
289  * </ul>
290  *
291  * @see SWT#VIRTUAL
292  * @see SWT#SetData
293  *
294  * @since 3.2
295  */
296 public void clearAll (boolean all) {
297         checkWidget ();
298         long hwnd = parent.handle;
299         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
300         if (hItem == 0) return;
301         TVITEM tvItem = new TVITEM ();
302         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
303         parent.clearAll (hItem, tvItem, all);
304 }
305
306 @Override
307 void destroyWidget () {
308         TVITEM tvItem = new TVITEM ();
309         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
310         parent.releaseItem (handle, tvItem, false);
311         parent.destroyItem (this, handle);
312         releaseHandle ();
313 }
314
315 long fontHandle (int index) {
316         if (cellFont != null && cellFont [index] != null) return cellFont [index].handle;
317         if (font != null) return font.handle;
318         return -1;
319 }
320
321 /**
322  * Returns the receiver's background color.
323  *
324  * @return the background color
325  *
326  * @exception SWTException <ul>
327  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
328  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
329  * </ul>
330  *
331  * @since 2.0
332  *
333  */
334 public Color getBackground () {
335         checkWidget ();
336         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
337         if (background == -1) return parent.getBackground ();
338         return Color.win32_new (display, background);
339 }
340
341 /**
342  * Returns the background color at the given column index in the receiver.
343  *
344  * @param index the column index
345  * @return the background color
346  *
347  * @exception SWTException <ul>
348  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
349  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
350  * </ul>
351  *
352  * @since 3.1
353  */
354 public Color getBackground (int index) {
355         checkWidget ();
356         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
357         int count = Math.max (1, parent.getColumnCount ());
358         if (0 > index || index > count - 1) return getBackground ();
359         int pixel = cellBackground != null ? cellBackground [index] : -1;
360         return pixel == -1 ? getBackground () : Color.win32_new (display, pixel);
361 }
362
363 /**
364  * Returns a rectangle describing the size and location of the receiver's
365  * text relative to its parent.
366  *
367  * @return the bounding rectangle of the receiver's text
368  *
369  * @exception SWTException <ul>
370  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
371  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
372  * </ul>
373  */
374 public Rectangle getBounds () {
375         checkWidget ();
376         return DPIUtil.autoScaleDown(getBoundsInPixels());
377 }
378
379 Rectangle getBoundsInPixels () {
380         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
381         RECT rect = getBounds (0, true, false, false);
382         int width = rect.right - rect.left, height = rect.bottom - rect.top;
383         return new Rectangle (rect.left, rect.top, width, height);
384 }
385
386 /**
387  * Returns a rectangle describing the receiver's size and location
388  * relative to its parent at a column in the tree.
389  *
390  * @param index the index that specifies the column
391  * @return the receiver's bounding column rectangle
392  *
393  * @exception SWTException <ul>
394  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
395  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
396  * </ul>
397  *
398  * @since 3.1
399  */
400 public Rectangle getBounds (int index) {
401         checkWidget();
402         return DPIUtil.autoScaleDown(getBoundsInPixels(index));
403 }
404
405 Rectangle getBoundsInPixels (int index) {
406         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
407         RECT rect = getBounds (index, true, true, true);
408         int width = rect.right - rect.left, height = rect.bottom - rect.top;
409         return new Rectangle (rect.left, rect.top, width, height);
410 }
411
412 RECT getBounds (int index, boolean getText, boolean getImage, boolean fullText) {
413         return getBounds (index, getText, getImage, fullText, false, true, 0);
414 }
415
416 //TODO - take into account grid (add boolean arg) to damage less during redraw
417 RECT getBounds (int index, boolean getText, boolean getImage, boolean fullText, boolean fullImage, boolean clip, long hDC) {
418         if (!getText && !getImage) return new RECT ();
419         long hwnd = parent.handle;
420         if ((parent.style & SWT.VIRTUAL) == 0 && !cached && !parent.painted) {
421                 TVITEM tvItem = new TVITEM ();
422                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
423                 tvItem.hItem = handle;
424                 tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
425                 parent.ignoreCustomDraw = true;
426                 OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
427                 parent.ignoreCustomDraw = false;
428         }
429         boolean firstColumn = index == 0;
430         int columnCount = 0;
431         long hwndHeader = parent.hwndHeader;
432         if (hwndHeader != 0) {
433                 columnCount = parent.columnCount;
434                 firstColumn = index == OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
435         }
436         RECT rect = new RECT ();
437         if (firstColumn) {
438                 boolean full = columnCount == 0 && getText && getImage && fullText && fullImage;
439                 if (!OS.TreeView_GetItemRect (hwnd, handle, rect, !full)) {
440                         return new RECT ();
441                 }
442                 if (getImage && !fullImage) {
443                         if (OS.SendMessage (hwnd, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) != 0) {
444                                 Point size = parent.getImageSize ();
445                                 rect.left -= size.x + Tree.INSET;
446                                 if (!getText) rect.right = rect.left + size.x;
447                         } else {
448                                 if (!getText) rect.right = rect.left;
449                         }
450                 }
451                 if (fullText || fullImage || clip) {
452                         if (hwndHeader != 0) {
453                                 RECT headerRect = new RECT ();
454                                 if (columnCount != 0) {
455                                         if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect) == 0) {
456                                                 return new RECT ();
457                                         }
458                                 } else {
459                                         headerRect.right = parent.scrollWidth;
460                                         if (headerRect.right == 0) headerRect = rect;
461                                 }
462                                 if (fullText && clip) rect.right = headerRect.right;
463                                 if (fullImage) rect.left = headerRect.left;
464                                 if (clip && headerRect.right < rect.right) {
465                                         rect.right = headerRect.right;
466                                 }
467                         }
468                 }
469         } else {
470                 if (!(0 <= index && index < columnCount)) return new RECT ();
471                 RECT headerRect = new RECT ();
472                 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect) == 0) {
473                         return new RECT ();
474                 }
475                 if (!OS.TreeView_GetItemRect (hwnd, handle, rect, false)) {
476                         return new RECT ();
477                 }
478                 rect.left = headerRect.left;
479                 if (fullText && getImage && clip) {
480                         rect.right = headerRect.right;
481                 } else {
482                         rect.right = headerRect.left;
483                         Image image = null;
484                         if (index == 0) {
485                                 image = this.image;
486                         } else {
487                                 if (images != null) image = images [index];
488                         }
489                         if (image != null) {
490                                 Point size = parent.getImageSize ();
491                                 rect.right += size.x;
492                         }
493                         if (getText) {
494                                 if (fullText && clip) {
495                                         rect.left = rect.right + Tree.INSET;
496                                         rect.right = headerRect.right;
497                                 } else {
498                                         String string = index == 0 ? text : strings != null ? strings [index] : null;
499                                         if (string != null) {
500                                                 RECT textRect = new RECT ();
501                                                 char [] buffer = string.toCharArray ();
502                                                 int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_CALCRECT;
503                                                 long hNewDC = hDC, hFont = 0;
504                                                 if (hDC == 0) {
505                                                         hNewDC = OS.GetDC (hwnd);
506                                                         hFont = fontHandle (index);
507                                                         if (hFont == -1) hFont = OS.SendMessage (hwnd, OS.WM_GETFONT, 0, 0);
508                                                         hFont = OS.SelectObject (hNewDC, hFont);
509                                                 }
510                                                 OS.DrawText (hNewDC, buffer, buffer.length, textRect, flags);
511                                                 if (hDC == 0) {
512                                                         OS.SelectObject (hNewDC, hFont);
513                                                         OS.ReleaseDC (hwnd, hNewDC);
514                                                 }
515                                                 if (getImage) {
516                                                         rect.right += textRect.right - textRect.left + Tree.INSET * 3;
517                                                 } else {
518                                                         rect.left = rect.right + Tree.INSET;
519                                                         rect.right = rect.left + (textRect.right - textRect.left) + Tree.INSET;
520                                                 }
521                                         }
522                                 }
523                         }
524                         if (clip && headerRect.right < rect.right) {
525                                 rect.right = headerRect.right;
526                         }
527                 }
528         }
529         int gridWidth = parent.linesVisible && columnCount != 0 ? Tree.GRID_WIDTH : 0;
530         if (getText || !getImage) {
531                 rect.right = Math.max (rect.left, rect.right - gridWidth);
532         }
533         rect.bottom = Math.max (rect.top, rect.bottom - gridWidth);
534         return rect;
535 }
536
537 /**
538  * Returns <code>true</code> if the receiver is checked,
539  * and false otherwise.  When the parent does not have
540  * the <code>CHECK</code> style, return false.
541  *
542  * @return the checked state
543  *
544  * @exception SWTException <ul>
545  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
546  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
547  * </ul>
548  */
549 public boolean getChecked () {
550         checkWidget ();
551         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
552         if ((parent.style & SWT.CHECK) == 0) return false;
553         long hwnd = parent.handle;
554         TVITEM tvItem = new TVITEM ();
555         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
556         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
557         tvItem.hItem = handle;
558         long result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
559         return (result != 0) && (((tvItem.state >> 12) & 1) == 0);
560 }
561
562 /**
563  * Returns <code>true</code> if the receiver is expanded,
564  * and false otherwise.
565  * <p>
566  *
567  * @return the expanded state
568  *
569  * @exception SWTException <ul>
570  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
571  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
572  * </ul>
573  */
574 public boolean getExpanded () {
575         checkWidget ();
576         long hwnd = parent.handle;
577         /*
578         * Bug in Windows.  Despite the fact that TVM_GETITEMSTATE claims
579         * to return only the bits specified by the stateMask, when called
580         * with TVIS_EXPANDED, the entire state is returned.  The fix is
581         * to explicitly check for the TVIS_EXPANDED bit.
582         */
583         int state = (int)OS.SendMessage (hwnd, OS.TVM_GETITEMSTATE, handle, OS.TVIS_EXPANDED);
584         return (state & OS.TVIS_EXPANDED) != 0;
585 }
586
587 /**
588  * Returns the font that the receiver will use to paint textual information for this item.
589  *
590  * @return the receiver's font
591  *
592  * @exception SWTException <ul>
593  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
594  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
595  * </ul>
596  *
597  * @since 3.0
598  */
599 public Font getFont () {
600         checkWidget ();
601         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
602         return font != null ? font : parent.getFont ();
603 }
604
605 /**
606  * Returns the font that the receiver will use to paint textual information
607  * for the specified cell in this item.
608  *
609  * @param index the column index
610  * @return the receiver's font
611  *
612  * @exception SWTException <ul>
613  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
614  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
615  * </ul>
616  *
617  * @since 3.1
618  */
619 public Font getFont (int index) {
620         checkWidget ();
621         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
622         int count = Math.max (1, parent.getColumnCount ());
623         if (0 > index || index > count -1) return getFont ();
624         if (cellFont == null || cellFont [index] == null) return getFont ();
625         return cellFont [index];
626 }
627
628 /**
629  * Returns the foreground color that the receiver will use to draw.
630  *
631  * @return the receiver's foreground color
632  *
633  * @exception SWTException <ul>
634  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
635  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
636  * </ul>
637  *
638  * @since 2.0
639  *
640  */
641 public Color getForeground () {
642         checkWidget ();
643         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
644         if (foreground == -1) return parent.getForeground ();
645         return Color.win32_new (display, foreground);
646 }
647
648 /**
649  *
650  * Returns the foreground color at the given column index in the receiver.
651  *
652  * @param index the column index
653  * @return the foreground color
654  *
655  * @exception SWTException <ul>
656  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
657  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
658  * </ul>
659  *
660  * @since 3.1
661  */
662 public Color getForeground (int index) {
663         checkWidget ();
664         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
665         int count = Math.max (1, parent.getColumnCount ());
666         if (0 > index || index > count -1) return getForeground ();
667         int pixel = cellForeground != null ? cellForeground [index] : -1;
668         return pixel == -1 ? getForeground () : Color.win32_new (display, pixel);
669 }
670
671 /**
672  * Returns <code>true</code> if the receiver is grayed,
673  * and false otherwise. When the parent does not have
674  * the <code>CHECK</code> style, return false.
675  *
676  * @return the grayed state of the checkbox
677  *
678  * @exception SWTException <ul>
679  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
680  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
681  * </ul>
682  */
683 public boolean getGrayed () {
684         checkWidget ();
685         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
686         if ((parent.style & SWT.CHECK) == 0) return false;
687         long hwnd = parent.handle;
688         TVITEM tvItem = new TVITEM ();
689         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
690         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
691         tvItem.hItem = handle;
692         long result = OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
693         return (result != 0) && ((tvItem.state >> 12) > 2);
694 }
695
696 /**
697  * Returns the item at the given, zero-relative index in the
698  * receiver. Throws an exception if the index is out of range.
699  *
700  * @param index the index of the item to return
701  * @return the item at the given index
702  *
703  * @exception IllegalArgumentException <ul>
704  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
705  * </ul>
706  * @exception SWTException <ul>
707  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
708  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
709  * </ul>
710  *
711  * @since 3.1
712  */
713 public TreeItem getItem (int index) {
714         checkWidget ();
715         if (index < 0) error (SWT.ERROR_INVALID_RANGE);
716         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
717         long hwnd = parent.handle;
718         long hFirstItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
719         if (hFirstItem == 0) error (SWT.ERROR_INVALID_RANGE);
720         long hItem = parent.findItem (hFirstItem, index);
721         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
722         return parent._getItem (hItem);
723 }
724
725 /**
726  * Returns the number of items contained in the receiver
727  * that are direct item children of the receiver.
728  *
729  * @return the number of items
730  *
731  * @exception SWTException <ul>
732  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
733  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
734  * </ul>
735  */
736 public int getItemCount () {
737         checkWidget ();
738         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
739         long hwnd = parent.handle;
740         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
741         if (hItem == 0) return 0;
742         return parent.getItemCount (hItem);
743 }
744
745 /**
746  * Returns a (possibly empty) array of <code>TreeItem</code>s which
747  * are the direct item children of the receiver.
748  * <p>
749  * Note: This is not the actual structure used by the receiver
750  * to maintain its list of items, so modifying the array will
751  * not affect the receiver.
752  * </p>
753  *
754  * @return the receiver's items
755  *
756  * @exception SWTException <ul>
757  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
758  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
759  * </ul>
760  */
761 public TreeItem [] getItems () {
762         checkWidget ();
763         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
764         long hwnd = parent.handle;
765         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
766         if (hItem == 0) return new TreeItem [0];
767         return parent.getItems (hItem);
768 }
769
770 @Override
771 public Image getImage () {
772         checkWidget();
773         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
774         return super.getImage ();
775 }
776
777 /**
778  * Returns the image stored at the given column index in the receiver,
779  * or null if the image has not been set or if the column does not exist.
780  *
781  * @param index the column index
782  * @return the image stored at the given column index in the receiver
783  *
784  * @exception SWTException <ul>
785  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
786  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
787  * </ul>
788  *
789  * @since 3.1
790  */
791 public Image getImage (int index) {
792         checkWidget();
793         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
794         if (index == 0) return getImage ();
795         if (images != null) {
796                 if (0 <= index && index < images.length) return images [index];
797         }
798         return null;
799 }
800
801 /**
802  * Returns a rectangle describing the size and location
803  * relative to its parent of an image at a column in the
804  * tree.
805  *
806  * @param index the index that specifies the column
807  * @return the receiver's bounding image rectangle
808  *
809  * @exception SWTException <ul>
810  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
811  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
812  * </ul>
813  *
814  * @since 3.1
815  */
816 public Rectangle getImageBounds (int index) {
817         checkWidget();
818         return DPIUtil.autoScaleDown(getImageBoundsInPixels(index));
819 }
820
821 Rectangle getImageBoundsInPixels (int index) {
822         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
823         RECT rect = getBounds (index, false, true, false);
824         int width = rect.right - rect.left, height = rect.bottom - rect.top;
825         return new Rectangle (rect.left, rect.top, width, height);
826 }
827
828 /**
829  * Returns the receiver's parent, which must be a <code>Tree</code>.
830  *
831  * @return the receiver's parent
832  *
833  * @exception SWTException <ul>
834  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
835  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
836  * </ul>
837  */
838 public Tree getParent () {
839         checkWidget ();
840         return parent;
841 }
842
843 /**
844  * Returns the receiver's parent item, which must be a
845  * <code>TreeItem</code> or null when the receiver is a
846  * root.
847  *
848  * @return the receiver's parent item
849  *
850  * @exception SWTException <ul>
851  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
852  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
853  * </ul>
854  */
855 public TreeItem getParentItem () {
856         checkWidget ();
857         long hwnd = parent.handle;
858         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, handle);
859         return hItem != 0 ? parent._getItem (hItem) : null;
860 }
861
862 @Override
863 public String getText () {
864         checkWidget();
865         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
866         return super.getText ();
867 }
868
869 /**
870  * Returns the text stored at the given column index in the receiver,
871  * or empty string if the text has not been set.
872  *
873  * @param index the column index
874  * @return the text stored at the given column index in the receiver
875  *
876  * @exception SWTException <ul>
877  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
878  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
879  * </ul>
880  *
881  * @since 3.1
882  */
883 public String getText (int index) {
884         checkWidget();
885         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
886         if (index == 0) return getText ();
887         if (strings != null) {
888                 if (0 <= index && index < strings.length) {
889                         String string = strings [index];
890                         return string != null ? string : "";
891                 }
892         }
893         return "";
894 }
895
896 /**
897  * Returns a rectangle describing the size and location
898  * relative to its parent of the text at a column in the
899  * tree.
900  *
901  * @param index the index that specifies the column
902  * @return the receiver's bounding text rectangle
903  *
904  * @exception SWTException <ul>
905  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
906  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
907  * </ul>
908  *
909  * @since 3.3
910  */
911 public Rectangle getTextBounds (int index) {
912         checkWidget();
913         return DPIUtil.autoScaleDown(getTextBoundsInPixels(index));
914 }
915
916 Rectangle getTextBoundsInPixels (int index) {
917         if (!parent.checkData (this, true)) error (SWT.ERROR_WIDGET_DISPOSED);
918         RECT rect = getBounds (index, true, false, true);
919         if (index == 0) rect.left += Tree.INSET - 1;
920         rect.left = Math.min (rect.left, rect.right);
921         rect.right = rect.right - Tree.INSET;
922         int width = Math.max (0, rect.right - rect.left);
923         int height = Math.max (0, rect.bottom - rect.top);
924         return new Rectangle (rect.left, rect.top, width, height);
925 }
926
927 /**
928  * Searches the receiver's list starting at the first item
929  * (index 0) until an item is found that is equal to the
930  * argument, and returns the index of that item. If no item
931  * is found, returns -1.
932  *
933  * @param item the search item
934  * @return the index of the item
935  *
936  * @exception IllegalArgumentException <ul>
937  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
938  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
939  * </ul>
940  * @exception SWTException <ul>
941  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
942  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
943  * </ul>
944  *
945  * @since 3.1
946  */
947 public int indexOf (TreeItem item) {
948         checkWidget ();
949         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
950         if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
951         long hwnd = parent.handle;
952         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
953         return hItem == 0 ? -1 : parent.findIndex (hItem, item.handle);
954 }
955
956 void redraw () {
957         if (parent.currentItem == this || !parent.getDrawing ()) return;
958         long hwnd = parent.handle;
959         if (!OS.IsWindowVisible (hwnd)) return;
960         /*
961         * When there are no columns and the tree is not
962         * full selection, redraw only the text.  This is
963         * an optimization to reduce flashing.
964         */
965         boolean full = (parent.style & (SWT.FULL_SELECTION | SWT.VIRTUAL)) != 0;
966         if (!full) {
967                 full = parent.columnCount != 0;
968                 if (!full) {
969                         if (parent.hooks (SWT.EraseItem) || parent.hooks (SWT.PaintItem)) {
970                                 full = true;
971                         }
972                 }
973         }
974         RECT rect = new RECT ();
975         if (OS.TreeView_GetItemRect (hwnd, handle, rect, !full)) {
976                 OS.InvalidateRect (hwnd, rect, true);
977         }
978 }
979
980 void redraw (int column, boolean drawText, boolean drawImage) {
981         if (parent.currentItem == this || !parent.getDrawing ()) return;
982         long hwnd = parent.handle;
983         if (!OS.IsWindowVisible (hwnd)) return;
984         boolean fullImage = column == 0 && drawText && drawImage;
985         RECT rect = getBounds (column, drawText, drawImage, true, fullImage, true, 0);
986         OS.InvalidateRect (hwnd, rect, true);
987 }
988
989 @Override
990 void releaseChildren (boolean destroy) {
991         if (destroy) {
992                 TVITEM tvItem = new TVITEM ();
993                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
994                 parent.releaseItems (handle, tvItem);
995         }
996         super.releaseChildren (destroy);
997 }
998
999 @Override
1000 void releaseHandle () {
1001         super.releaseHandle ();
1002         handle = 0;
1003         parent = null;
1004 }
1005
1006 @Override
1007 void releaseWidget () {
1008         super.releaseWidget ();
1009         strings = null;
1010         images = null;
1011         cellBackground = cellForeground = null;
1012         cellFont = null;
1013 }
1014
1015 /**
1016  * Removes all of the items from the receiver.
1017  *
1018  * @exception SWTException <ul>
1019  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1020  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1021  * </ul>
1022  *
1023  * @since 3.1
1024  */
1025 public void removeAll () {
1026         checkWidget ();
1027         long hwnd = parent.handle;
1028         TVITEM tvItem = new TVITEM ();
1029         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1030         tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
1031         while (tvItem.hItem != 0) {
1032                 OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
1033                 TreeItem item = tvItem.lParam != -1 ? parent.items [(int)tvItem.lParam] : null;
1034                 if (item != null && !item.isDisposed ()) {
1035                         item.dispose ();
1036                 } else {
1037                         parent.releaseItem (tvItem.hItem, tvItem, false);
1038                         parent.destroyItem (null, tvItem.hItem);
1039                 }
1040                 tvItem.hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
1041         }
1042 }
1043
1044 /**
1045  * Sets the receiver's background color to the color specified
1046  * by the argument, or to the default system color for the item
1047  * if the argument is null.
1048  *
1049  * @param color the new color (or null)
1050  *
1051  * @exception IllegalArgumentException <ul>
1052  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1053  * </ul>
1054  * @exception SWTException <ul>
1055  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1056  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1057  * </ul>
1058  *
1059  * @since 2.0
1060  *
1061  */
1062 public void setBackground (Color color) {
1063         checkWidget ();
1064         if (color != null && color.isDisposed ()) {
1065                 error (SWT.ERROR_INVALID_ARGUMENT);
1066         }
1067         int pixel = -1;
1068         if (color != null) {
1069                 parent.customDraw = true;
1070                 pixel = color.handle;
1071         }
1072         if (background == pixel) return;
1073         background = pixel;
1074         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1075         redraw ();
1076 }
1077
1078 /**
1079  * Sets the background color at the given column index in the receiver
1080  * to the color specified by the argument, or to the default system color for the item
1081  * if the argument is null.
1082  *
1083  * @param index the column index
1084  * @param color the new color (or null)
1085  *
1086  * @exception IllegalArgumentException <ul>
1087  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1088  * </ul>
1089  * @exception SWTException <ul>
1090  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1091  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1092  * </ul>
1093  *
1094  * @since 3.1
1095  *
1096  */
1097 public void setBackground (int index, Color color) {
1098         checkWidget ();
1099         if (color != null && color.isDisposed ()) {
1100                 error (SWT.ERROR_INVALID_ARGUMENT);
1101         }
1102         int count = Math.max (1, parent.getColumnCount ());
1103         if (0 > index || index > count - 1) return;
1104         int pixel = -1;
1105         if (color != null) {
1106                 parent.customDraw = true;
1107                 pixel = color.handle;
1108         }
1109         if (cellBackground == null) {
1110                 cellBackground = new int [count];
1111                 for (int i = 0; i < count; i++) {
1112                         cellBackground [i] = -1;
1113                 }
1114         }
1115         if (cellBackground [index] == pixel) return;
1116         cellBackground [index] = pixel;
1117         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1118         redraw (index, true, true);
1119 }
1120
1121 /**
1122  * Sets the checked state of the receiver.
1123  * <p>
1124  *
1125  * @param checked the new checked state
1126  *
1127  * @exception SWTException <ul>
1128  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1129  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1130  * </ul>
1131  */
1132 public void setChecked (boolean checked) {
1133         checkWidget ();
1134         if ((parent.style & SWT.CHECK) == 0) return;
1135         long hwnd = parent.handle;
1136         TVITEM tvItem = new TVITEM ();
1137         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
1138         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
1139         tvItem.hItem = handle;
1140         OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
1141         int state = tvItem.state >> 12;
1142         if (checked) {
1143                 if ((state & 0x1) != 0) state++;
1144         } else {
1145                 if ((state & 0x1) == 0) --state;
1146         }
1147         state <<= 12;
1148         if (tvItem.state == state) return;
1149         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1150         tvItem.state = state;
1151         OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1152         /*
1153         * Bug in Windows.  When TVM_SETITEM is used to set
1154         * the state image of an item inside TVN_GETDISPINFO,
1155         * the new state is not redrawn.  The fix is to force
1156         * a redraw.
1157         */
1158         if ((parent.style & SWT.VIRTUAL) != 0) {
1159                 if (parent.currentItem == this && OS.IsWindowVisible (hwnd)) {
1160                         RECT rect = new RECT ();
1161                         if (OS.TreeView_GetItemRect (hwnd, handle, rect, false)) {
1162                                 OS.InvalidateRect (hwnd, rect, true);
1163                         }
1164                 }
1165         }
1166 }
1167
1168 /**
1169  * Sets the expanded state of the receiver.
1170  * <p>
1171  *
1172  * @param expanded the new expanded state
1173  *
1174  * @exception SWTException <ul>
1175  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1176  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1177  * </ul>
1178  */
1179 public void setExpanded (boolean expanded) {
1180         checkWidget ();
1181
1182         /* Do nothing when the item is a leaf or already expanded */
1183         long hwnd = parent.handle;
1184         if (OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle) == 0) {
1185                 return;
1186         }
1187         /*
1188         * Bug in Windows.  Despite the fact that TVM_GETITEMSTATE claims
1189         * to return only the bits specified by the stateMask, when called
1190         * with TVIS_EXPANDED, the entire state is returned.  The fix is
1191         * to explicitly check for the TVIS_EXPANDED bit.
1192         */
1193         int state = (int)OS.SendMessage (hwnd, OS.TVM_GETITEMSTATE, handle, OS.TVIS_EXPANDED);
1194         if (((state & OS.TVIS_EXPANDED) != 0) == expanded) return;
1195
1196         /*
1197         * Feature in Windows.  When TVM_EXPAND is used to expand
1198         * an item, the widget scrolls to show the item and the
1199         * newly expanded items.  While not strictly incorrect,
1200         * this means that application code that expands tree items
1201         * in a background thread can scroll the widget while the
1202         * user is interacting with it.  The fix is to remember
1203         * the top item and the bounds of every tree item, turn
1204         * redraw off, expand the item, scroll back to the top
1205         * item.  If none of the rectangles have moved, then
1206         * it is safe to turn redraw back on without redrawing
1207         * the control.
1208         */
1209         RECT oldRect = null;
1210         RECT [] rects = null;
1211         SCROLLINFO oldInfo = null;
1212         int count = 0;
1213         long hBottomItem = 0;
1214         boolean redraw = false, noScroll = true;
1215         long hTopItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1216         if (noScroll && hTopItem != 0) {
1217                 oldInfo = new SCROLLINFO ();
1218                 oldInfo.cbSize = SCROLLINFO.sizeof;
1219                 oldInfo.fMask = OS.SIF_ALL;
1220                 if (!OS.GetScrollInfo (hwnd, OS.SB_HORZ, oldInfo)) {
1221                         oldInfo = null;
1222                 }
1223                 if (parent.getDrawing () && OS.IsWindowVisible (hwnd)) {
1224                         boolean noAnimate = true;
1225                         count = (int)OS.SendMessage (hwnd, OS.TVM_GETVISIBLECOUNT, 0, 0);
1226                         rects = new RECT [count + 1];
1227                         long hItem = hTopItem;
1228                         int index = 0;
1229                         while (hItem != 0 && (noAnimate || hItem != handle) && index < count) {
1230                                 RECT rect = new RECT ();
1231                                 if (OS.TreeView_GetItemRect (hwnd, hItem, rect, true)) {
1232                                         rects [index++] = rect;
1233                                 }
1234                                 hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
1235                         }
1236                         if (noAnimate || hItem != handle) {
1237                                 redraw = true;
1238                                 count = index;
1239                                 hBottomItem = hItem;
1240                                 oldRect = new RECT ();
1241                                 OS.GetClientRect (hwnd, oldRect);
1242                                 long topHandle = parent.topHandle ();
1243                                 OS.UpdateWindow (topHandle);
1244                                 OS.DefWindowProc (topHandle, OS.WM_SETREDRAW, 0, 0);
1245                                 if (hwnd != topHandle) {
1246                                         OS.UpdateWindow (hwnd);
1247                                         OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 0, 0);
1248                                 }
1249                                 /*
1250                                 * This code is intentionally commented.
1251                                 */
1252 //                              OS.SendMessage (hwnd, OS.WM_SETREDRAW, 0, 0);
1253                         }
1254                 }
1255         }
1256
1257         /*
1258         * Feature in Windows.  When the user collapses the root
1259         * of a subtree that has the focus item, Windows moves
1260         * the selection to the root of the subtree and issues
1261         * a TVN_SELCHANGED to inform the programmer that the
1262         * selection has changed.  When the programmer collapses
1263         * the same subtree using TVM_EXPAND, Windows does not
1264         * send the selection changed notification.  This is not
1265         * strictly wrong but is inconsistent.  The fix is to
1266         * check whether the selection has changed and issue
1267         * the event.
1268         */
1269         long hOldItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
1270
1271         /* Expand or collapse the item */
1272         parent.ignoreExpand = true;
1273         OS.SendMessage (hwnd, OS.TVM_EXPAND, expanded ? OS.TVE_EXPAND : OS.TVE_COLLAPSE, handle);
1274         parent.ignoreExpand = false;
1275
1276         /* Scroll back to the top item */
1277         if (noScroll && hTopItem != 0) {
1278                 boolean collapsed = false;
1279                 if (!expanded) {
1280                         RECT rect = new RECT ();
1281                         while (hTopItem != 0 && !OS.TreeView_GetItemRect (hwnd, hTopItem, rect, false)) {
1282                                 hTopItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hTopItem);
1283                                 collapsed = true;
1284                         }
1285                 }
1286                 boolean scrolled = true;
1287                 if (hTopItem != 0) {
1288                         OS.SendMessage (hwnd, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hTopItem);
1289                         scrolled = hTopItem != OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1290                 }
1291                 if (!collapsed && !scrolled && oldInfo != null) {
1292                         SCROLLINFO newInfo = new SCROLLINFO ();
1293                         newInfo.cbSize = SCROLLINFO.sizeof;
1294                         newInfo.fMask = OS.SIF_ALL;
1295                         if (OS.GetScrollInfo (hwnd, OS.SB_HORZ, newInfo)) {
1296                                 if (oldInfo.nPos != newInfo.nPos) {
1297                                         long lParam = OS.MAKELPARAM (OS.SB_THUMBPOSITION, oldInfo.nPos);
1298                                         OS.SendMessage (hwnd, OS.WM_HSCROLL, lParam, 0);
1299                                 }
1300                         }
1301                 }
1302                 if (redraw) {
1303                         boolean fixScroll = false;
1304                         if (!collapsed && !scrolled) {
1305                                 RECT newRect = new RECT ();
1306                                 OS.GetClientRect (hwnd, newRect);
1307                                 if (OS.EqualRect (oldRect, newRect)) {
1308                                         long hItem = hTopItem;
1309                                         int index = 0;
1310                                         while (hItem != 0 && index < count) {
1311                                                 RECT rect = new RECT ();
1312                                                 if (OS.TreeView_GetItemRect (hwnd, hItem, rect, true)) {
1313                                                         if (!OS.EqualRect (rect, rects [index])) {
1314                                                                 break;
1315                                                         }
1316                                                 }
1317                                                 hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
1318                                                 index++;
1319                                         }
1320                                         fixScroll = index == count && hItem == hBottomItem;
1321                                 }
1322                         }
1323                         long topHandle = parent.topHandle ();
1324                         OS.DefWindowProc (topHandle, OS.WM_SETREDRAW, 1, 0);
1325                         if (hwnd != topHandle) {
1326                                 OS.DefWindowProc (hwnd, OS.WM_SETREDRAW, 1, 0);
1327                         }
1328                         /*
1329                         * This code is intentionally commented.
1330                         */
1331 //                      OS.SendMessage (hwnd, OS.WM_SETREDRAW, 1, 0);
1332                         if (fixScroll) {
1333                                 parent.updateScrollBar ();
1334                                 SCROLLINFO info = new SCROLLINFO ();
1335                                 info.cbSize = SCROLLINFO.sizeof;
1336                                 info.fMask = OS.SIF_ALL;
1337                                 if (OS.GetScrollInfo (hwnd, OS.SB_VERT, info)) {
1338                                         OS.SetScrollInfo (hwnd, OS.SB_VERT, info, true);
1339                                 }
1340                                 if (handle == hBottomItem) {
1341                                         RECT rect = new RECT ();
1342                                         if (OS.TreeView_GetItemRect (hwnd, hBottomItem, rect, false)) {
1343                                                 OS.InvalidateRect (hwnd, rect, true);
1344                                         }
1345                                 }
1346                         } else {
1347                                 int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
1348                                 OS.RedrawWindow (topHandle, null, 0, flags);
1349                         }
1350                 }
1351         }
1352
1353         /* Check for a selection event */
1354         long hNewItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
1355         if (hNewItem != hOldItem) {
1356                 Event event = new Event ();
1357                 if (hNewItem != 0) {
1358                         event.item = parent._getItem (hNewItem);
1359                         parent.hAnchor = hNewItem;
1360                 }
1361                 parent.sendSelectionEvent (SWT.Selection, event, true);
1362         }
1363 }
1364
1365 /**
1366  * Sets the font that the receiver will use to paint textual information
1367  * for this item to the font specified by the argument, or to the default font
1368  * for that kind of control if the argument is null.
1369  *
1370  * @param font the new font (or null)
1371  *
1372  * @exception IllegalArgumentException <ul>
1373  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1374  * </ul>
1375  * @exception SWTException <ul>
1376  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1377  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1378  * </ul>
1379  *
1380  * @since 3.0
1381  */
1382 public void setFont (Font font){
1383         checkWidget ();
1384         if (font != null && font.isDisposed ()) {
1385                 error (SWT.ERROR_INVALID_ARGUMENT);
1386         }
1387         Font oldFont = this.font;
1388         if (oldFont == font) return;
1389         this.font = font;
1390         if (oldFont != null && oldFont.equals (font)) return;
1391         if (font != null) parent.customDraw = true;
1392         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1393         /*
1394         * Bug in Windows.  When the font is changed for an item,
1395         * the bounds for the item are not updated, causing the text
1396         * to be clipped.  The fix is to reset the text, causing
1397         * Windows to compute the new bounds using the new font.
1398         */
1399         if ((parent.style & SWT.VIRTUAL) == 0 && !cached && !parent.painted) {
1400                 return;
1401         }
1402         long hwnd = parent.handle;
1403         TVITEM tvItem = new TVITEM ();
1404         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1405         tvItem.hItem = handle;
1406         tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1407         OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1408 }
1409
1410
1411 /**
1412  * Sets the font that the receiver will use to paint textual information
1413  * for the specified cell in this item to the font specified by the
1414  * argument, or to the default font for that kind of control if the
1415  * argument is null.
1416  *
1417  * @param index the column index
1418  * @param font the new font (or null)
1419  *
1420  * @exception IllegalArgumentException <ul>
1421  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1422  * </ul>
1423  * @exception SWTException <ul>
1424  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1425  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1426  * </ul>
1427  *
1428  * @since 3.1
1429  */
1430 public void setFont (int index, Font font) {
1431         checkWidget ();
1432         if (font != null && font.isDisposed ()) {
1433                 error (SWT.ERROR_INVALID_ARGUMENT);
1434         }
1435         int count = Math.max (1, parent.getColumnCount ());
1436         if (0 > index || index > count - 1) return;
1437         if (cellFont == null) {
1438                 if (font == null) return;
1439                 cellFont = new Font [count];
1440         }
1441         Font oldFont = cellFont [index];
1442         if (oldFont == font) return;
1443         cellFont [index] = font;
1444         if (oldFont != null && oldFont.equals (font)) return;
1445         if (font != null) parent.customDraw = true;
1446         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1447         /*
1448         * Bug in Windows.  When the font is changed for an item,
1449         * the bounds for the item are not updated, causing the text
1450         * to be clipped.  The fix is to reset the text, causing
1451         * Windows to compute the new bounds using the new font.
1452         */
1453         if (index == 0) {
1454                 if ((parent.style & SWT.VIRTUAL) == 0 && !cached && !parent.painted) {
1455                         return;
1456                 }
1457                 long hwnd = parent.handle;
1458                 TVITEM tvItem = new TVITEM ();
1459                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1460                 tvItem.hItem = handle;
1461                 tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1462                 OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1463         } else {
1464                 redraw (index, true, false);
1465         }
1466 }
1467
1468 /**
1469  * Sets the receiver's foreground color to the color specified
1470  * by the argument, or to the default system color for the item
1471  * if the argument is null.
1472  *
1473  * @param color the new color (or null)
1474  *
1475  * @exception IllegalArgumentException <ul>
1476  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1477  * </ul>
1478  * @exception SWTException <ul>
1479  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1480  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1481  * </ul>
1482  *
1483  * @since 2.0
1484  *
1485  */
1486 public void setForeground (Color color) {
1487         checkWidget ();
1488         if (color != null && color.isDisposed ()) {
1489                 error (SWT.ERROR_INVALID_ARGUMENT);
1490         }
1491         int pixel = -1;
1492         if (color != null) {
1493                 parent.customDraw = true;
1494                 pixel = color.handle;
1495         }
1496         if (foreground == pixel) return;
1497         foreground = pixel;
1498         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1499         redraw ();
1500 }
1501
1502 /**
1503  * Sets the foreground color at the given column index in the receiver
1504  * to the color specified by the argument, or to the default system color for the item
1505  * if the argument is null.
1506  *
1507  * @param index the column index
1508  * @param color the new color (or null)
1509  *
1510  * @exception IllegalArgumentException <ul>
1511  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
1512  * </ul>
1513  * @exception SWTException <ul>
1514  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1515  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1516  * </ul>
1517  *
1518  * @since 3.1
1519  *
1520  */
1521 public void setForeground (int index, Color color){
1522         checkWidget ();
1523         if (color != null && color.isDisposed ()) {
1524                 error (SWT.ERROR_INVALID_ARGUMENT);
1525         }
1526         int count = Math.max (1, parent.getColumnCount ());
1527         if (0 > index || index > count - 1) return;
1528         int pixel = -1;
1529         if (color != null) {
1530                 parent.customDraw = true;
1531                 pixel = color.handle;
1532         }
1533         if (cellForeground == null) {
1534                 cellForeground = new int [count];
1535                 for (int i = 0; i < count; i++) {
1536                         cellForeground [i] = -1;
1537                 }
1538         }
1539         if (cellForeground [index] == pixel) return;
1540         cellForeground [index] = pixel;
1541         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1542         redraw (index, true, false);
1543 }
1544
1545 /**
1546  * Sets the grayed state of the checkbox for this item.  This state change
1547  * only applies if the Tree was created with the SWT.CHECK style.
1548  *
1549  * @param grayed the new grayed state of the checkbox
1550  *
1551  * @exception SWTException <ul>
1552  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1553  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1554  * </ul>
1555  */
1556 public void setGrayed (boolean grayed) {
1557         checkWidget ();
1558         if ((parent.style & SWT.CHECK) == 0) return;
1559         long hwnd = parent.handle;
1560         TVITEM tvItem = new TVITEM ();
1561         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
1562         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
1563         tvItem.hItem = handle;
1564         OS.SendMessage (hwnd, OS.TVM_GETITEM, 0, tvItem);
1565         int state = tvItem.state >> 12;
1566         if (grayed) {
1567                 if (state <= 2) state +=2;
1568         } else {
1569                 if (state > 2) state -=2;
1570         }
1571         state <<= 12;
1572         if (tvItem.state == state) return;
1573         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1574         tvItem.state = state;
1575         OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1576         /*
1577         * Bug in Windows.  When TVM_SETITEM is used to set
1578         * the state image of an item inside TVN_GETDISPINFO,
1579         * the new state is not redrawn.  The fix is to force
1580         * a redraw.
1581         */
1582         if ((parent.style & SWT.VIRTUAL) != 0) {
1583                 if (parent.currentItem == this && OS.IsWindowVisible (hwnd)) {
1584                         RECT rect = new RECT ();
1585                         if (OS.TreeView_GetItemRect (hwnd, handle, rect, false)) {
1586                                 OS.InvalidateRect (hwnd, rect, true);
1587                         }
1588                 }
1589         }
1590 }
1591
1592 /**
1593  * Sets the image for multiple columns in the tree.
1594  *
1595  * @param images the array of new images
1596  *
1597  * @exception IllegalArgumentException <ul>
1598  *    <li>ERROR_NULL_ARGUMENT - if the array of images is null</li>
1599  *    <li>ERROR_INVALID_ARGUMENT - if one of the images has been disposed</li>
1600  * </ul>
1601  * @exception SWTException <ul>
1602  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1603  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1604  * </ul>
1605  *
1606  * @since 3.1
1607  */
1608 public void setImage (Image [] images) {
1609         checkWidget();
1610         if (images == null) error (SWT.ERROR_NULL_ARGUMENT);
1611         for (int i=0; i<images.length; i++) {
1612                 setImage (i, images [i]);
1613         }
1614 }
1615
1616 /**
1617  * Sets the receiver's image at a column.
1618  *
1619  * @param index the column index
1620  * @param image the new image
1621  *
1622  * @exception IllegalArgumentException <ul>
1623  *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
1624  * </ul>
1625  * @exception SWTException <ul>
1626  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1627  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1628  * </ul>
1629  *
1630  * @since 3.1
1631  */
1632 public void setImage (int index, Image image) {
1633         checkWidget();
1634         if (image != null && image.isDisposed ()) {
1635                 error(SWT.ERROR_INVALID_ARGUMENT);
1636         }
1637         Image oldImage = null;
1638         if (index == 0) {
1639                 if (image != null && image.type == SWT.ICON) {
1640                         if (image.equals (this.image)) return;
1641                 }
1642                 oldImage = this.image;
1643                 super.setImage (image);
1644         }
1645         int count = Math.max (1, parent.getColumnCount ());
1646         if (0 > index || index > count - 1) return;
1647         if (images == null && index != 0) {
1648                 images = new Image [count];
1649                 images [0] = image;
1650         }
1651         if (images != null) {
1652                 if (image != null && image.type == SWT.ICON) {
1653                         if (image.equals (images [index])) return;
1654                 }
1655                 oldImage = images [index];
1656                 images [index] = image;
1657         }
1658         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1659
1660         /* Ensure that the image list is created */
1661         //TODO - items that are not in column zero don't need to be in the image list
1662         parent.imageIndex (image, index);
1663
1664         if (index == 0) {
1665                 if ((parent.style & SWT.VIRTUAL) == 0 &&!cached && !parent.painted) {
1666                         return;
1667                 }
1668                 long hwnd = parent.handle;
1669                 TVITEM tvItem = new TVITEM ();
1670                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE;
1671                 tvItem.hItem = handle;
1672                 tvItem.iImage = tvItem.iSelectedImage = OS.I_IMAGECALLBACK;
1673                 /*
1674                 * Bug in Windows.  When I_IMAGECALLBACK is used with TVM_SETITEM
1675                 * to indicate that an image has changed, Windows does not draw
1676                 * the new image.  The fix is to use LPSTR_TEXTCALLBACK to force
1677                 * Windows to ask for the text, causing Windows to ask for both.
1678                 */
1679                 tvItem.mask |= OS.TVIF_TEXT;
1680                 tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1681                 OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1682         } else {
1683                 boolean drawText = (image == null && oldImage != null) || (image != null && oldImage == null);
1684                 redraw (index, drawText, true);
1685         }
1686 }
1687
1688 @Override
1689 public void setImage (Image image) {
1690         checkWidget ();
1691         setImage (0, image);
1692 }
1693
1694 /**
1695  * Sets the number of child items contained in the receiver.
1696  *
1697  * @param count the number of items
1698  *
1699  * @exception SWTException <ul>
1700  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1701  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1702  * </ul>
1703  *
1704  * @since 3.2
1705  */
1706 public void setItemCount (int count) {
1707         checkWidget ();
1708         count = Math.max (0, count);
1709         long hwnd = parent.handle;
1710         long hItem = OS.SendMessage (hwnd, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, handle);
1711         parent.setItemCount (count, handle, hItem);
1712 }
1713
1714 /**
1715  * Sets the text for multiple columns in the tree.
1716  * <p>
1717  * Note: If control characters like '\n', '\t' etc. are used
1718  * in the string, then the behavior is platform dependent.
1719  * </p>
1720  * @param strings the array of new strings
1721  *
1722  * @exception IllegalArgumentException <ul>
1723  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1724  * </ul>
1725  * @exception SWTException <ul>
1726  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1727  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1728  * </ul>
1729  *
1730  * @since 3.1
1731  */
1732 public void setText (String [] strings) {
1733         checkWidget();
1734         if (strings == null) error (SWT.ERROR_NULL_ARGUMENT);
1735         for (int i=0; i<strings.length; i++) {
1736                 String string = strings [i];
1737                 if (string != null) setText (i, string);
1738         }
1739 }
1740
1741 /**
1742  * Sets the receiver's text at a column
1743  * <p>
1744  * Note: If control characters like '\n', '\t' etc. are used
1745  * in the string, then the behavior is platform dependent.
1746  * </p>
1747  * @param index the column index
1748  * @param string the new text
1749  *
1750  * @exception IllegalArgumentException <ul>
1751  *    <li>ERROR_NULL_ARGUMENT - if the text is null</li>
1752  * </ul>
1753  * @exception SWTException <ul>
1754  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1755  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1756  * </ul>
1757  *
1758  * @since 3.1
1759  */
1760 public void setText (int index, String string) {
1761         checkWidget();
1762         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
1763         if (index == 0) {
1764                 if (string.equals (text)) return;
1765                 super.setText (string);
1766         }
1767         int count = Math.max (1, parent.getColumnCount ());
1768         if (0 > index || index > count - 1) return;
1769         if (strings == null && index != 0) {
1770                 strings = new String [count];
1771                 strings [0] = text;
1772         }
1773         if (strings != null) {
1774                 if (string.equals (strings [index])) return;
1775                 strings [index] = string;
1776         }
1777         if ((parent.style & SWT.VIRTUAL) != 0) cached = true;
1778         if (index == 0) {
1779                 if ((parent.style & SWT.VIRTUAL) == 0 && !cached && !parent.painted) {
1780                         return;
1781                 }
1782                 long hwnd = parent.handle;
1783                 TVITEM tvItem = new TVITEM ();
1784                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1785                 tvItem.hItem = handle;
1786                 tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1787                 OS.SendMessage (hwnd, OS.TVM_SETITEM, 0, tvItem);
1788         } else {
1789                 redraw (index, true, false);
1790         }
1791 }
1792
1793 @Override
1794 public void setText (String string) {
1795         checkWidget();
1796         setText (0, string);
1797 }
1798
1799 /*public*/ void sort () {
1800         checkWidget ();
1801         if ((parent.style & SWT.VIRTUAL) != 0) return;
1802         parent.sort (handle, false);
1803 }
1804
1805 }