]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tree.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / Tree.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 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.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.*;
21 import org.eclipse.swt.internal.win32.*;
22
23 /**
24  * Instances of this class provide a selectable user interface object
25  * that displays a hierarchy of items and issues notification when an
26  * item in the hierarchy is selected.
27  * <p>
28  * The item children that may be added to instances of this class
29  * must be of type <code>TreeItem</code>.
30  * </p><p>
31  * Style <code>VIRTUAL</code> is used to create a <code>Tree</code> whose
32  * <code>TreeItem</code>s are to be populated by the client on an on-demand basis
33  * instead of up-front.  This can provide significant performance improvements for
34  * trees that are very large or for which <code>TreeItem</code> population is
35  * expensive (for example, retrieving values from an external source).
36  * </p><p>
37  * Here is an example of using a <code>Tree</code> with style <code>VIRTUAL</code>:</p>
38  * <pre><code>
39  *  final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
40  *  tree.setItemCount(20);
41  *  tree.addListener(SWT.SetData, new Listener() {
42  *      public void handleEvent(Event event) {
43  *          TreeItem item = (TreeItem)event.item;
44  *          TreeItem parentItem = item.getParentItem();
45  *          String text = null;
46  *          if (parentItem == null) {
47  *              text = "node " + tree.indexOf(item);
48  *          } else {
49  *              text = parentItem.getText() + " - " + parentItem.indexOf(item);
50  *          }
51  *          item.setText(text);
52  *          System.out.println(text);
53  *          item.setItemCount(10);
54  *      }
55  *  });
56  * </code></pre>
57  * <p>
58  * Note that although this class is a subclass of <code>Composite</code>,
59  * it does not normally make sense to add <code>Control</code> children to
60  * it, or set a layout on it, unless implementing something like a cell
61  * editor.
62  * </p>
63  * <dl>
64  * <dt><b>Styles:</b></dt>
65  * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL, NO_SCROLL</dd>
66  * <dt><b>Events:</b></dt>
67  * <dd>Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, EraseItem, PaintItem</dd>
68  * </dl>
69  * <p>
70  * Note: Only one of the styles SINGLE and MULTI may be specified.
71  * </p><p>
72  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
73  * </p>
74  *
75  * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
76  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
77  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
78  * @noextend This class is not intended to be subclassed by clients.
79  */
80 public class Tree extends Composite {
81         TreeItem [] items;
82         TreeColumn [] columns;
83         int columnCount;
84         ImageList imageList, headerImageList;
85         TreeItem currentItem;
86         TreeColumn sortColumn;
87         RECT focusRect;
88         long hwndParent, hwndHeader, hAnchor, hInsert, hSelect;
89         int lastID;
90         long hFirstIndexOf, hLastIndexOf;
91         int lastIndexOf, itemCount, sortDirection;
92         boolean dragStarted, gestureCompleted, insertAfter, shrink, ignoreShrink;
93         boolean ignoreSelect, ignoreExpand, ignoreDeselect, ignoreResize;
94         boolean lockSelection, oldSelected, newSelected, ignoreColumnMove;
95         boolean linesVisible, customDraw, painted, ignoreItemHeight;
96         boolean ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus;
97         boolean ignoreDrawSelection, ignoreDrawHot, ignoreFullSelection, explorerTheme;
98         boolean createdAsRTL;
99         boolean headerItemDragging;
100         int scrollWidth, selectionForeground;
101         long headerToolTipHandle, itemToolTipHandle;
102         long lastTimerID = -1;
103         int lastTimerCount;
104         int headerBackground = -1;
105         int headerForeground = -1;
106         static final boolean ENABLE_TVS_EX_FADEINOUTEXPANDOS = System.getProperty("org.eclipse.swt.internal.win32.enableFadeInOutExpandos") != null;
107         static final int TIMER_MAX_COUNT = 8;
108         static final int INSET = 3;
109         static final int GRID_WIDTH = 1;
110         static final int SORT_WIDTH = 10;
111         static final int HEADER_MARGIN = 12;
112         static final int HEADER_EXTRA = 3;
113         static final int INCREMENT = 5;
114         static final int EXPLORER_EXTRA = 2;
115         static final int DRAG_IMAGE_SIZE = 301;
116         static final long TreeProc;
117         static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true);
118         static final long HeaderProc;
119         static final TCHAR HeaderClass = new TCHAR (0, OS.WC_HEADER, true);
120         static {
121                 WNDCLASS lpWndClass = new WNDCLASS ();
122                 OS.GetClassInfo (0, TreeClass, lpWndClass);
123                 TreeProc = lpWndClass.lpfnWndProc;
124                 OS.GetClassInfo (0, HeaderClass, lpWndClass);
125                 HeaderProc = lpWndClass.lpfnWndProc;
126         }
127
128 /**
129  * Constructs a new instance of this class given its parent
130  * and a style value describing its behavior and appearance.
131  * <p>
132  * The style value is either one of the style constants defined in
133  * class <code>SWT</code> which is applicable to instances of this
134  * class, or must be built by <em>bitwise OR</em>'ing together
135  * (that is, using the <code>int</code> "|" operator) two or more
136  * of those <code>SWT</code> style constants. The class description
137  * lists the style constants that are applicable to the class.
138  * Style bits are also inherited from superclasses.
139  * </p>
140  *
141  * @param parent a composite control which will be the parent of the new instance (cannot be null)
142  * @param style the style of control to construct
143  *
144  * @exception IllegalArgumentException <ul>
145  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
146  * </ul>
147  * @exception SWTException <ul>
148  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
149  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
150  * </ul>
151  *
152  * @see SWT#SINGLE
153  * @see SWT#MULTI
154  * @see SWT#CHECK
155  * @see SWT#FULL_SELECTION
156  * @see SWT#VIRTUAL
157  * @see SWT#NO_SCROLL
158  * @see Widget#checkSubclass
159  * @see Widget#getStyle
160  */
161 public Tree (Composite parent, int style) {
162         super (parent, checkStyle (style));
163 }
164
165 static int checkStyle (int style) {
166         /*
167         * Feature in Windows.  Even when WS_HSCROLL or
168         * WS_VSCROLL is not specified, Windows creates
169         * trees and tables with scroll bars.  The fix
170         * is to set H_SCROLL and V_SCROLL.
171         *
172         * NOTE: This code appears on all platforms so that
173         * applications have consistent scroll bar behavior.
174         */
175         if ((style & SWT.NO_SCROLL) == 0) {
176                 style |= SWT.H_SCROLL | SWT.V_SCROLL;
177         }
178         /*
179         * Note: Windows only supports TVS_NOSCROLL and TVS_NOHSCROLL.
180         */
181         if ((style & SWT.H_SCROLL) != 0 && (style & SWT.V_SCROLL) == 0) {
182                 style |= SWT.V_SCROLL;
183         }
184         return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
185 }
186
187 @Override
188 void _addListener (int eventType, Listener listener) {
189         super._addListener (eventType, listener);
190         switch (eventType) {
191                 case SWT.DragDetect: {
192                         if ((state & DRAG_DETECT) != 0) {
193                                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
194                                 bits &= ~OS.TVS_DISABLEDRAGDROP;
195                                 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
196                         }
197                         break;
198                 }
199                 case SWT.MeasureItem:
200                 case SWT.EraseItem:
201                 case SWT.PaintItem: {
202                         customDraw = true;
203                         style |= SWT.DOUBLE_BUFFERED;
204                         if (isCustomToolTip ()) createItemToolTips ();
205                         OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
206                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
207                         if (eventType == SWT.MeasureItem) {
208                                 /*
209                                 * This code is intentionally commented.
210                                 */
211 //                              if (explorerTheme) {
212 //                                      int bits1 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
213 //                                      bits1 &= ~OS.TVS_EX_AUTOHSCROLL;
214 //                                      OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits1);
215 //                              }
216                                 bits |= OS.TVS_NOHSCROLL;
217                         }
218                         /*
219                         * Feature in Windows.  When the tree has the style
220                         * TVS_FULLROWSELECT, the background color for the
221                         * entire row is filled when an item is painted,
222                         * drawing on top of any custom drawing.  The fix
223                         * is to clear TVS_FULLROWSELECT.
224                         */
225                         if ((style & SWT.FULL_SELECTION) != 0) {
226                                 if (eventType != SWT.MeasureItem) {
227                                         if (!explorerTheme) bits &= ~OS.TVS_FULLROWSELECT;
228                                 }
229                         }
230                         if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) {
231                                 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
232                                 OS.InvalidateRect (handle, null, true);
233                                 /*
234                                 * Bug in Windows.  When TVS_NOHSCROLL is set after items
235                                 * have been inserted into the tree, Windows shows the
236                                 * scroll bar.  The fix is to check for this case and
237                                 * explicitly hide the scroll bar.
238                                 */
239                                 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
240                                 if (count != 0 && (bits & OS.TVS_NOHSCROLL) != 0) {
241                                         OS.ShowScrollBar (handle, OS.SB_HORZ, false);
242                                 }
243                         }
244                         break;
245                 }
246         }
247 }
248
249 TreeItem _getItem (long hItem) {
250         TVITEM tvItem = new TVITEM ();
251         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
252         tvItem.hItem = hItem;
253         if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
254                 return _getItem (tvItem.hItem, (int)tvItem.lParam);
255         }
256         return null;
257 }
258
259 TreeItem _getItem (long hItem, int id) {
260         if ((style & SWT.VIRTUAL) == 0) return items [id];
261         return id != -1 ? items [id] : new TreeItem (this, SWT.NONE, -1, -1, hItem);
262 }
263
264 @Override
265 void _removeListener (int eventType, Listener listener) {
266         super._removeListener (eventType, listener);
267         switch (eventType) {
268                 case SWT.MeasureItem: {
269                         /**
270                          * If H_SCROLL is set, reverting the TVS_NOHSCROLL settings which
271                          * was applied while adding SWT.MeasureItem event Listener.
272                          */
273                         if ((style & SWT.H_SCROLL) != 0 && (state & DISPOSE_SENT) == 0) {
274                                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
275                                 bits &= ~OS.TVS_NOHSCROLL;
276                                 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
277                                 OS.InvalidateRect (handle, null, true);
278                         }
279                         break;
280                 }
281         }
282 }
283
284 void _setBackgroundPixel (int newPixel) {
285         int oldPixel = (int)OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0);
286         if (oldPixel != newPixel) {
287                 /*
288                 * Bug in Windows.  When TVM_SETBKCOLOR is used more
289                 * than once to set the background color of a tree,
290                 * the background color of the lines and the plus/minus
291                 * does not change to the new color.  The fix is to set
292                 * the background color to the default before setting
293                 * the new color.
294                 */
295                 if (oldPixel != -1) {
296                         OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
297                 }
298
299                 /* Set the background color */
300                 OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, newPixel);
301
302                 /*
303                 * Feature in Windows.  When TVM_SETBKCOLOR is used to
304                 * set the background color of a tree, the plus/minus
305                 * animation draws badly.  The fix is to clear the effect.
306                 */
307                 if (explorerTheme && ENABLE_TVS_EX_FADEINOUTEXPANDOS) {
308                         int bits2 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
309                         if (newPixel == -1 && findImageControl () == null) {
310                                 bits2 |= OS.TVS_EX_FADEINOUTEXPANDOS;
311                         } else {
312                                 bits2 &= ~OS.TVS_EX_FADEINOUTEXPANDOS;
313                         }
314                         OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits2);
315                 }
316
317                 /* Set the checkbox image list */
318                 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
319         }
320 }
321
322 /**
323  * Adds the listener to the collection of listeners who will
324  * be notified when the user changes the receiver's selection, by sending
325  * it one of the messages defined in the <code>SelectionListener</code>
326  * interface.
327  * <p>
328  * When <code>widgetSelected</code> is called, the item field of the event object is valid.
329  * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
330  * the event object detail field contains the value <code>SWT.CHECK</code>.
331  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
332  * The item field of the event object is valid for default selection, but the detail field is not used.
333  * </p>
334  *
335  * @param listener the listener which should be notified when the user changes the receiver's selection
336  *
337  * @exception IllegalArgumentException <ul>
338  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
339  * </ul>
340  * @exception SWTException <ul>
341  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
342  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
343  * </ul>
344  *
345  * @see SelectionListener
346  * @see #removeSelectionListener
347  * @see SelectionEvent
348  */
349 public void addSelectionListener(SelectionListener listener) {
350         checkWidget ();
351         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
352         TypedListener typedListener = new TypedListener (listener);
353         addListener (SWT.Selection, typedListener);
354         addListener (SWT.DefaultSelection, typedListener);
355 }
356
357 /**
358  * Adds the listener to the collection of listeners who will
359  * be notified when an item in the receiver is expanded or collapsed
360  * by sending it one of the messages defined in the <code>TreeListener</code>
361  * interface.
362  *
363  * @param listener the listener which should be notified
364  *
365  * @exception IllegalArgumentException <ul>
366  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
367  * </ul>
368  * @exception SWTException <ul>
369  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
370  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
371  * </ul>
372  *
373  * @see TreeListener
374  * @see #removeTreeListener
375  */
376 public void addTreeListener(TreeListener listener) {
377         checkWidget ();
378         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
379         TypedListener typedListener = new TypedListener (listener);
380         addListener (SWT.Expand, typedListener);
381         addListener (SWT.Collapse, typedListener);
382 }
383
384 @Override
385 long borderHandle () {
386         return hwndParent != 0 ? hwndParent : handle;
387 }
388
389 LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
390         if (ignoreCustomDraw) return null;
391         if (nmcd.left == nmcd.right) return new LRESULT (OS.CDRF_DODEFAULT);
392         long hDC = nmcd.hdc;
393         OS.RestoreDC (hDC, -1);
394         TreeItem item = getItem (nmcd);
395
396         /*
397         * Feature in Windows.  When a new tree item is inserted
398         * using TVM_INSERTITEM and the tree is using custom draw,
399         * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
400         * and before the item is added to the items array.  The
401         * fix is to check for null.
402         *
403         * NOTE: This only happens on XP with the version 6.00 of
404         * COMCTL32.DLL,
405         */
406         if (item == null) return null;
407
408         /*
409         * Feature in Windows.  Under certain circumstances, Windows
410         * sends CDDS_ITEMPOSTPAINT for an empty rectangle.  This is
411         * not a problem providing that graphics do not occur outside
412         * the rectangle.  The fix is to test for the rectangle and
413         * draw nothing.
414         *
415         * NOTE:  This seems to happen when both I_IMAGECALLBACK
416         * and LPSTR_TEXTCALLBACK are used at the same time with
417         * TVM_SETITEM.
418         */
419         if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) return null;
420         if (!OS.IsWindowVisible (handle)) return null;
421         if ((style & SWT.FULL_SELECTION) != 0 || findImageControl () != null || ignoreDrawSelection || explorerTheme) {
422                 OS.SetBkMode (hDC, OS.TRANSPARENT);
423         }
424         boolean selected = isItemSelected (nmcd);
425         boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
426         if (OS.IsWindowEnabled (handle)) {
427                 if (explorerTheme) {
428                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
429                         if ((bits & OS.TVS_TRACKSELECT) != 0) {
430                                 if ((style & SWT.FULL_SELECTION) != 0 && (selected || hot)) {
431                                         OS.SetTextColor (hDC, OS.GetSysColor (OS.COLOR_WINDOWTEXT));
432                                 } else {
433                                         OS.SetTextColor (hDC, getForegroundPixel ());
434                                 }
435                         }
436                 }
437         }
438         int [] order = null;
439         RECT clientRect = new RECT ();
440         OS.GetClientRect (scrolledHandle (), clientRect);
441         if (hwndHeader != 0) {
442                 OS.MapWindowPoints (hwndParent, handle, clientRect, 2);
443                 if (columnCount != 0) {
444                         order = new int [columnCount];
445                         OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
446                 }
447         }
448         int sortIndex = -1, clrSortBk = -1;
449         if (OS.IsAppThemed ()) {
450                 if (sortColumn != null && sortDirection != SWT.NONE) {
451                         if (findImageControl () == null) {
452                                 sortIndex = indexOf (sortColumn);
453                                 clrSortBk = getSortColumnPixel ();
454                         }
455                 }
456         }
457         int x = 0;
458         Point size = null;
459         for (int i=0; i<Math.max (1, columnCount); i++) {
460                 int index = order == null ? i : order [i], width = nmcd.right - nmcd.left;
461                 if (columnCount > 0 && hwndHeader != 0) {
462                         HDITEM hdItem = new HDITEM ();
463                         hdItem.mask = OS.HDI_WIDTH;
464                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
465                         width = hdItem.cxy;
466                 }
467                 if (i == 0) {
468                         if ((style & SWT.FULL_SELECTION) != 0) {
469                                 boolean clear = !explorerTheme && !ignoreDrawSelection && findImageControl () == null;
470                                 if (clear || (selected && !ignoreDrawSelection) || (hot && !ignoreDrawHot)) {
471                                         boolean draw = true;
472                                         RECT pClipRect = new RECT ();
473                                         OS.SetRect (pClipRect, width, nmcd.top, nmcd.right, nmcd.bottom);
474                                         if (explorerTheme) {
475                                                 if (hooks (SWT.EraseItem)) {
476                                                         RECT itemRect = item.getBounds (index, true, true, false, false, true, hDC);
477                                                         itemRect.left -= EXPLORER_EXTRA;
478                                                         itemRect.right += EXPLORER_EXTRA + 1;
479                                                         pClipRect.left = itemRect.left;
480                                                         pClipRect.right = itemRect.right;
481                                                         if (columnCount > 0 && hwndHeader != 0) {
482                                                                 HDITEM hdItem = new HDITEM ();
483                                                                 hdItem.mask = OS.HDI_WIDTH;
484                                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
485                                                                 pClipRect.right = Math.min (pClipRect.right, nmcd.left + hdItem.cxy);
486                                                         }
487                                                 }
488                                                 RECT pRect = new RECT ();
489                                                 OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
490                                                 if (columnCount > 0 && hwndHeader != 0) {
491                                                         int totalWidth = 0;
492                                                         HDITEM hdItem = new HDITEM ();
493                                                         hdItem.mask = OS.HDI_WIDTH;
494                                                         for (int j=0; j<columnCount; j++) {
495                                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
496                                                                 totalWidth += hdItem.cxy;
497                                                         }
498                                                         if (totalWidth > clientRect.right - clientRect.left) {
499                                                                 pRect.left = 0;
500                                                                 pRect.right = totalWidth;
501                                                         } else {
502                                                                 pRect.left = clientRect.left;
503                                                                 pRect.right = clientRect.right;
504                                                         }
505                                                 }
506                                                 draw = false;
507                                                 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
508                                                 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
509                                                 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
510                                                 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
511                                                 OS.CloseThemeData (hTheme);
512                                         }
513                                         if (draw) fillBackground (hDC, OS.GetBkColor (hDC), pClipRect);
514                                 }
515                         }
516                 }
517                 if (x + width > clientRect.left) {
518                         RECT rect = new RECT (), backgroundRect = null;
519                         boolean drawItem = true, drawText = true, drawImage = true, drawBackground = false;
520                         if (i == 0) {
521                                 drawItem = drawImage = drawText = false;
522                                 if (findImageControl () != null) {
523                                         if (explorerTheme) {
524                                                 if (OS.IsWindowEnabled (handle) && !hooks (SWT.EraseItem)) {
525                                                         Image image = null;
526                                                         if (index == 0) {
527                                                                 image = item.image;
528                                                         } else {
529                                                                 Image [] images  = item.images;
530                                                                 if (images != null) image = images [index];
531                                                         }
532                                                         if (image != null) {
533                                                                 Rectangle bounds = image.getBounds (); // Points
534                                                                 if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points
535                                                                 if (!ignoreDrawForeground) {
536                                                                         GCData data = new GCData();
537                                                                         data.device = display;
538                                                                         GC gc = GC.win32_new (hDC, data);
539                                                                         RECT iconRect = item.getBounds (index, false, true, false, false, true, hDC); // Pixels
540                                                                         gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(iconRect.left, iconRect.top, iconRect.right - iconRect.left, iconRect.bottom - iconRect.top)));
541                                                                         gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(iconRect.left), DPIUtil.autoScaleDown(iconRect.top), size.x, size.y);
542                                                                         OS.SelectClipRgn (hDC, 0);
543                                                                         gc.dispose ();
544                                                                 }
545                                                         }
546                                                 }
547                                         } else {
548                                                 drawItem = drawText = drawBackground = true;
549                                                 rect = item.getBounds (index, true, false, false, false, true, hDC);
550                                                 if (linesVisible) {
551                                                         rect.right++;
552                                                         rect.bottom++;
553                                                 }
554                                         }
555                                 }
556                                 if (selected && !ignoreDrawSelection && !ignoreDrawBackground) {
557                                         if (!explorerTheme) fillBackground (hDC, OS.GetBkColor (hDC), rect);
558                                         drawBackground = false;
559                                 }
560                                 backgroundRect = rect;
561                                 if (hooks (SWT.EraseItem)) {
562                                         drawItem = drawText = drawImage = true;
563                                         rect = item.getBounds (index, true, true, false, false, true, hDC);
564                                         if ((style & SWT.FULL_SELECTION) != 0) {
565                                                 backgroundRect = rect;
566                                         } else {
567                                                 backgroundRect = item.getBounds (index, true, false, false, false, true, hDC);
568                                         }
569                                 }
570                         } else {
571                                 selectionForeground = -1;
572                                 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = false;
573                                 OS.SetRect (rect, x, nmcd.top, x + width, nmcd.bottom);
574                                 backgroundRect = rect;
575                         }
576                         int clrText = -1, clrTextBk = -1;
577                         long hFont = item.fontHandle (index);
578                         if (selectionForeground != -1) clrText = selectionForeground;
579                         if (OS.IsWindowEnabled (handle)) {
580                                 boolean drawForeground = false;
581                                 if (selected) {
582                                         if (i != 0 && (style & SWT.FULL_SELECTION) == 0) {
583                                                 OS.SetTextColor (hDC, getForegroundPixel ());
584                                                 OS.SetBkColor (hDC, getBackgroundPixel ());
585                                                 drawForeground = drawBackground = true;
586                                         }
587                                 } else {
588                                         drawForeground = drawBackground = true;
589                                 }
590                                 if (drawForeground) {
591                                         clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
592                                         if (clrText == -1) clrText = item.foreground;
593                                 }
594                                 if (drawBackground) {
595                                         clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
596                                         if (clrTextBk == -1) clrTextBk = item.background;
597                                         if (clrTextBk == -1 && index == sortIndex) clrTextBk = clrSortBk;
598                                 }
599                         } else {
600                                 if (clrTextBk == -1 && index == sortIndex) {
601                                         drawBackground = true;
602                                         clrTextBk = clrSortBk;
603                                 }
604                         }
605                         if (explorerTheme) {
606                                 if (selected || (nmcd.uItemState & OS.CDIS_HOT) != 0) {
607                                         if ((style & SWT.FULL_SELECTION) != 0) {
608                                                 drawBackground = false;
609                                         } else {
610                                                 if (i == 0) {
611                                                         drawBackground = false;
612                                                         if (!hooks (SWT.EraseItem)) drawText = false;
613                                                 }
614                                         }
615                                 }
616                         }
617                         if (drawItem) {
618                                 if (i != 0) {
619                                         if (hooks (SWT.MeasureItem)) {
620                                                 sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0);
621                                                 if (isDisposed () || item.isDisposed ()) break;
622                                         }
623                                         if (hooks (SWT.EraseItem)) {
624                                                 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
625                                                 int nSavedDC = OS.SaveDC (hDC);
626                                                 GCData data = new GCData ();
627                                                 data.device = display;
628                                                 data.foreground = OS.GetTextColor (hDC);
629                                                 data.background = OS.GetBkColor (hDC);
630                                                 if (!selected || (style & SWT.FULL_SELECTION) == 0) {
631                                                         if (clrText != -1) data.foreground = clrText;
632                                                         if (clrTextBk != -1) data.background = clrTextBk;
633                                                 }
634                                                 data.font = item.getFont (index);
635                                                 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
636                                                 GC gc = GC.win32_new (hDC, data);
637                                                 Event event = new Event ();
638                                                 event.item = item;
639                                                 event.index = index;
640                                                 event.gc = gc;
641                                                 event.detail |= SWT.FOREGROUND;
642                                                 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
643                                                 if ((style & SWT.FULL_SELECTION) != 0) {
644                                                         if (hot) event.detail |= SWT.HOT;
645                                                         if (selected) event.detail |= SWT.SELECTED;
646                                                         if (!explorerTheme) {
647                                                                 //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
648                                                                 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
649                                                                         if (handle == OS.GetFocus ()) {
650                                                                                 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
651                                                                                 if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
652                                                                         }
653                                                                 }
654                                                         }
655                                                 }
656                                                 Rectangle boundsInPixels = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top);
657                                                 event.setBoundsInPixels (boundsInPixels);
658                                                 gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels));
659                                                 sendEvent (SWT.EraseItem, event);
660                                                 event.gc = null;
661                                                 int newTextClr = data.foreground;
662                                                 gc.dispose ();
663                                                 OS.RestoreDC (hDC, nSavedDC);
664                                                 if (isDisposed () || item.isDisposed ()) break;
665                                                 if (event.doit) {
666                                                         ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
667                                                         ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
668                                                         if ((style & SWT.FULL_SELECTION) != 0) {
669                                                                 ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
670                                                                 ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
671                                                                 ignoreDrawHot = (event.detail & SWT.HOT) == 0;
672                                                         }
673                                                 } else {
674                                                         ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
675                                                 }
676                                                 if (selected && ignoreDrawSelection) ignoreDrawHot = true;
677                                                 if ((style & SWT.FULL_SELECTION) != 0) {
678                                                         if (ignoreDrawSelection) ignoreFullSelection = true;
679                                                         if (!ignoreDrawSelection || !ignoreDrawHot) {
680                                                                 if (!selected && !hot) {
681                                                                         selectionForeground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
682                                                                 } else {
683                                                                         if (!explorerTheme) {
684                                                                                 drawBackground = true;
685                                                                                 ignoreDrawBackground = false;
686                                                                                 if ((handle == OS.GetFocus () || display.getHighContrast ()) && OS.IsWindowEnabled (handle)) {
687                                                                                         clrTextBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
688                                                                                 } else {
689                                                                                         clrTextBk = OS.GetSysColor (OS.COLOR_3DFACE);
690                                                                                 }
691                                                                                 if (!ignoreFullSelection && index == columnCount - 1) {
692                                                                                         RECT selectionRect = new RECT ();
693                                                                                         OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, nmcd.right, backgroundRect.bottom);
694                                                                                         backgroundRect = selectionRect;
695                                                                                 }
696                                                                         } else {
697                                                                                 RECT pRect = new RECT ();
698                                                                                 OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
699                                                                                 if (columnCount > 0 && hwndHeader != 0) {
700                                                                                         int totalWidth = 0;
701                                                                                         HDITEM hdItem = new HDITEM ();
702                                                                                         hdItem.mask = OS.HDI_WIDTH;
703                                                                                         for (int j=0; j<columnCount; j++) {
704                                                                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
705                                                                                                 totalWidth += hdItem.cxy;
706                                                                                         }
707                                                                                         if (totalWidth > clientRect.right - clientRect.left) {
708                                                                                                 pRect.left = 0;
709                                                                                                 pRect.right = totalWidth;
710                                                                                         } else {
711                                                                                                 pRect.left = clientRect.left;
712                                                                                                 pRect.right = clientRect.right;
713                                                                                         }
714                                                                                         if (index == columnCount - 1) {
715                                                                                                 RECT selectionRect = new RECT ();
716                                                                                                 OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, pRect.right, backgroundRect.bottom);
717                                                                                                 backgroundRect = selectionRect;
718                                                                                         }
719                                                                                 }
720                                                                                 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
721                                                                                 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
722                                                                                 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
723                                                                                 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, backgroundRect);
724                                                                                 OS.CloseThemeData (hTheme);
725                                                                         }
726                                                                 }
727                                                         } else {
728                                                                 if (selected) {
729                                                                         selectionForeground = newTextClr;
730                                                                         if (!explorerTheme) {
731                                                                                 if (clrTextBk == -1 && OS.IsWindowEnabled (handle)) {
732                                                                                         Control control = findBackgroundControl ();
733                                                                                         if (control == null) control = this;
734                                                                                         clrTextBk = control.getBackgroundPixel ();
735                                                                                 }
736                                                                         }
737                                                                 }
738                                                         }
739                                                 }
740                                         }
741                                         if (selectionForeground != -1) clrText = selectionForeground;
742                                 }
743                                 if (!ignoreDrawBackground) {
744                                         if (clrTextBk != -1) {
745                                                 if (drawBackground) fillBackground (hDC, clrTextBk, backgroundRect);
746                                         } else {
747                                                 Control control = findImageControl ();
748                                                 if (control != null) {
749                                                         if (i == 0) {
750                                                                 int right = Math.min (rect.right, width);
751                                                                 OS.SetRect (rect, rect.left, rect.top, right, rect.bottom);
752                                                                 if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0);
753                                                         } else {
754                                                                 if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0);
755                                                         }
756                                                 }
757                                         }
758                                 }
759                                 rect.left += INSET - 1;
760                                 if (drawImage) {
761                                         Image image = null;
762                                         if (index == 0) {
763                                                 image = item.image;
764                                         } else {
765                                                 Image [] images  = item.images;
766                                                 if (images != null) image = images [index];
767                                         }
768                                         int inset = i != 0 ? INSET : 0;
769                                         int offset = i != 0 ? INSET : INSET + 2;
770                                         if (image != null) {
771                                                 Rectangle bounds = image.getBounds (); // Points
772                                                 if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points
773                                                 if (!ignoreDrawForeground) {
774                                                         //int y1 = rect.top + (index == 0 ? (getItemHeight () - size.y) / 2 : 0);
775                                                         int y1 = rect.top + DPIUtil.autoScaleUp((getItemHeight () - size.y) / 2);
776                                                         int x1 = Math.max (rect.left, rect.left - inset + 1);
777                                                         GCData data = new GCData();
778                                                         data.device = display;
779                                                         GC gc = GC.win32_new (hDC, data);
780                                                         gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(x1, rect.top, rect.right - x1, rect.bottom - rect.top)));
781                                                         gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(x1), DPIUtil.autoScaleDown(y1), size.x, size.y);
782                                                         OS.SelectClipRgn (hDC, 0);
783                                                         gc.dispose ();
784                                                 }
785                                                 OS.SetRect (rect, rect.left + DPIUtil.autoScaleUp(size.x) + offset, rect.top, rect.right - inset, rect.bottom);
786                                         } else {
787                                                 if (i == 0) {
788                                                         if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) != 0) {
789                                                                 if (size == null) size = getImageSize ();
790                                                                 rect.left = Math.min (rect.left + size.x + offset, rect.right);
791                                                         }
792                                                 } else {
793                                                         OS.SetRect (rect, rect.left + offset, rect.top, rect.right - inset, rect.bottom);
794                                                 }
795                                         }
796                                 }
797                                 if (drawText) {
798                                         /*
799                                         * Bug in Windows.  When DrawText() is used with DT_VCENTER
800                                         * and DT_ENDELLIPSIS, the ellipsis can draw outside of the
801                                         * rectangle when the rectangle is empty.  The fix is avoid
802                                         * all text drawing for empty rectangles.
803                                         */
804                                         if (rect.left < rect.right) {
805                                                 String string = null;
806                                                 if (index == 0) {
807                                                         string = item.text;
808                                                 } else {
809                                                         String [] strings  = item.strings;
810                                                         if (strings != null) string = strings [index];
811                                                 }
812                                                 if (string != null) {
813                                                         if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
814                                                         if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
815                                                         if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
816                                                         int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
817                                                         if (i != 0) flags |= OS.DT_ENDELLIPSIS;
818                                                         TreeColumn column = columns != null ? columns [index] : null;
819                                                         if (column != null) {
820                                                                 if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
821                                                                 if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
822                                                         }
823                                                         if ((string != null) && (string.length() > Item.TEXT_LIMIT)) {
824                                                                 string = string.substring(0, Item.TEXT_LIMIT - Item.ELLIPSIS.length()) + Item.ELLIPSIS;
825                                                         }
826                                                         char [] buffer = string.toCharArray ();
827                                                         if (!ignoreDrawForeground) OS.DrawText (hDC, buffer, buffer.length, rect, flags);
828                                                         OS.DrawText (hDC, buffer, buffer.length, rect, flags | OS.DT_CALCRECT);
829                                                         if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
830                                                         if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
831                                                         if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
832                                                 }
833                                         }
834                                 }
835                         }
836                         if (selectionForeground != -1) clrText = selectionForeground;
837                         if (hooks (SWT.PaintItem)) {
838                                 RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
839                                 int nSavedDC = OS.SaveDC (hDC);
840                                 GCData data = new GCData ();
841                                 data.device = display;
842                                 data.font = item.getFont (index);
843                                 data.foreground = OS.GetTextColor (hDC);
844                                 data.background = OS.GetBkColor (hDC);
845                                 if (selected && (style & SWT.FULL_SELECTION) != 0) {
846                                         if (selectionForeground != -1) data.foreground = selectionForeground;
847                                 } else {
848                                         if (clrText != -1) data.foreground = clrText;
849                                         if (clrTextBk != -1) data.background = clrTextBk;
850                                 }
851                                 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
852                                 GC gc = GC.win32_new (hDC, data);
853                                 Event event = new Event ();
854                                 event.item = item;
855                                 event.index = index;
856                                 event.gc = gc;
857                                 event.detail |= SWT.FOREGROUND;
858                                 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
859                                 if (hot) event.detail |= SWT.HOT;
860                                 if (selected && (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0)) {
861                                         event.detail |= SWT.SELECTED;
862                                 }
863                                 if (!explorerTheme) {
864                                         //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
865                                         if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
866                                                 if (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0) {
867                                                         if (handle == OS.GetFocus ()) {
868                                                                 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
869                                                                 if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
870                                                         }
871                                                 }
872                                         }
873                                 }
874                                 event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
875                                 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
876                                 int cellWidth = cellRect.right - cellRect.left;
877                                 int cellHeight = cellRect.bottom - cellRect.top;
878                                 gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(cellRect.left, cellRect.top, cellWidth, cellHeight)));
879                                 sendEvent (SWT.PaintItem, event);
880                                 if (data.focusDrawn) focusRect = null;
881                                 event.gc = null;
882                                 gc.dispose ();
883                                 OS.RestoreDC (hDC, nSavedDC);
884                                 if (isDisposed () || item.isDisposed ()) break;
885                         }
886                 }
887                 x += width;
888                 if (x > clientRect.right) break;
889         }
890         if (linesVisible) {
891                 if ((style & SWT.FULL_SELECTION) != 0) {
892                         if (columnCount != 0) {
893                                 HDITEM hdItem = new HDITEM ();
894                                 hdItem.mask = OS.HDI_WIDTH;
895                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem);
896                                 RECT rect = new RECT ();
897                                 OS.SetRect (rect, nmcd.left + hdItem.cxy, nmcd.top, nmcd.right, nmcd.bottom);
898                                 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
899                         }
900                 }
901                 RECT rect = new RECT ();
902                 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
903                 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
904         }
905         if (!ignoreDrawFocus && focusRect != null) {
906                 OS.DrawFocusRect (hDC, focusRect);
907                 focusRect = null;
908         } else {
909                 if (!explorerTheme) {
910                         if (handle == OS.GetFocus ()) {
911                                 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
912                                 if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
913                                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
914                                         if (hItem == item.handle) {
915                                                 if (!ignoreDrawFocus && findImageControl () != null) {
916                                                         if ((style & SWT.FULL_SELECTION) != 0) {
917                                                                 RECT focusRect = new RECT ();
918                                                                 OS.SetRect (focusRect, 0, nmcd.top, clientRect.right + 1, nmcd.bottom);
919                                                                 OS.DrawFocusRect (hDC, focusRect);
920                                                         } else {
921                                                                 int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
922                                                                 RECT focusRect = item.getBounds (index, true, false, false, false, false, hDC);
923                                                                 RECT clipRect = item.getBounds (index, true, false, false, false, true, hDC);
924                                                                 OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
925                                                                 OS.DrawFocusRect (hDC, focusRect);
926                                                                 OS.SelectClipRgn (hDC, 0);
927                                                         }
928                                                 }
929                                         }
930                                 }
931                         }
932                 }
933         }
934         return new LRESULT (OS.CDRF_DODEFAULT);
935 }
936
937 LRESULT CDDS_ITEMPREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
938         /*
939         * Even when custom draw is being ignored, the font needs
940         * to be selected into the HDC so that the item bounds are
941         * measured correctly.
942         */
943         TreeItem item = getItem (nmcd);
944         /*
945         * Feature in Windows.  When a new tree item is inserted
946         * using TVM_INSERTITEM and the tree is using custom draw,
947         * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
948         * and before the item is added to the items array.  The
949         * fix is to check for null.
950         *
951         * NOTE: This only happens on XP with the version 6.00 of
952         * COMCTL32.DLL,
953         */
954         if (item == null) return null;
955         long hDC = nmcd.hdc;
956         int index = hwndHeader != 0 ? (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) : 0;
957         long hFont = item.fontHandle (index);
958         if (hFont != -1) OS.SelectObject (hDC, hFont);
959         if (ignoreCustomDraw || nmcd.left == nmcd.right) {
960                 return new LRESULT (hFont == -1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT);
961         }
962         RECT clipRect = null;
963         if (columnCount != 0) {
964                 clipRect = new RECT ();
965                 HDITEM hdItem = new HDITEM ();
966                 hdItem.mask = OS.HDI_WIDTH;
967                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
968                 OS.SetRect (clipRect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
969         }
970         int clrText = -1, clrTextBk = -1;
971         if (OS.IsWindowEnabled (handle)) {
972                 clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
973                 if (clrText == -1) clrText = item.foreground;
974                 clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
975                 if (clrTextBk == -1) clrTextBk = item.background;
976         }
977         int clrSortBk = -1;
978         if (OS.IsAppThemed ()) {
979                 if (sortColumn != null && sortDirection != SWT.NONE) {
980                         if (findImageControl () == null) {
981                                 if (indexOf (sortColumn) == index) {
982                                         clrSortBk = getSortColumnPixel ();
983                                         if (clrTextBk == -1) clrTextBk = clrSortBk;
984                                 }
985                         }
986                 }
987         }
988         boolean selected = isItemSelected (nmcd);
989         boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
990         boolean focused = explorerTheme && (nmcd.uItemState & OS.CDIS_FOCUS) != 0;
991         if (OS.IsWindowVisible (handle) && nmcd.left < nmcd.right && nmcd.top < nmcd.bottom) {
992                 if (hFont != -1) OS.SelectObject (hDC, hFont);
993                 if (linesVisible) {
994                         RECT rect = new RECT ();
995                         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
996                         OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
997                 }
998                 //TODO - BUG - measure and erase sent when first column is clipped
999                 Event measureEvent = null;
1000                 Rectangle boundsInPixels = null;
1001                 if (hooks (SWT.MeasureItem)) {
1002                         measureEvent = sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0);
1003                         boundsInPixels = measureEvent.getBoundsInPixels ();
1004                         if (isDisposed () || item.isDisposed ()) return null;
1005                 }
1006                 selectionForeground = -1;
1007                 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = ignoreFullSelection = false;
1008                 if (hooks (SWT.EraseItem)) {
1009                         RECT rect = new RECT ();
1010                         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1011                         RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
1012                         if (clrSortBk != -1) {
1013                                 drawBackground (hDC, cellRect, clrSortBk, 0, 0);
1014                         } else {
1015                                 if (OS.IsWindowEnabled (handle) || findImageControl () != null) {
1016                                         drawBackground (hDC, rect);
1017                                 } else {
1018                                         fillBackground (hDC, OS.GetBkColor (hDC), rect);
1019                                 }
1020                         }
1021                         int nSavedDC = OS.SaveDC (hDC);
1022                         GCData data = new GCData ();
1023                         data.device = display;
1024                         if (selected && explorerTheme) {
1025                                 data.foreground = OS.GetSysColor (OS.COLOR_WINDOWTEXT);
1026                         } else {
1027                                 data.foreground = OS.GetTextColor (hDC);
1028                         }
1029                         data.background = OS.GetBkColor (hDC);
1030                         if (!selected) {
1031                                 if (clrText != -1) data.foreground = clrText;
1032                                 if (clrTextBk != -1) data.background = clrTextBk;
1033                         }
1034                         data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1035                         data.font = item.getFont (index);
1036                         GC gc = GC.win32_new (hDC, data);
1037                         Event event = new Event ();
1038                         event.index = index;
1039                         event.item = item;
1040                         event.gc = gc;
1041                         event.detail |= SWT.FOREGROUND;
1042                         if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
1043                         if (hot) event.detail |= SWT.HOT;
1044                         if (selected) event.detail |= SWT.SELECTED;
1045                         //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
1046                         if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
1047                                 if (handle == OS.GetFocus ()) {
1048                                         int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1049                                         if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
1050                                                 if (!explorerTheme || !selected) {
1051                                                         focused = true;
1052                                                         event.detail |= SWT.FOCUSED;
1053                                                 }
1054                                         }
1055                                 }
1056                         }
1057                         Rectangle boundsInPixels2 = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top);
1058                         event.setBoundsInPixels (boundsInPixels2);
1059                         gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels2));
1060                         sendEvent (SWT.EraseItem, event);
1061                         event.gc = null;
1062                         int newTextClr = data.foreground;
1063                         gc.dispose ();
1064                         OS.RestoreDC (hDC, nSavedDC);
1065                         if (isDisposed () || item.isDisposed ()) return null;
1066                         if (event.doit) {
1067                                 ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
1068                                 ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
1069                                 ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
1070                                 ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
1071                                 ignoreDrawHot = (event.detail & SWT.HOT) == 0;
1072                         } else {
1073                                 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
1074                         }
1075                         if (selected && ignoreDrawSelection) ignoreDrawHot = true;
1076                         if (!ignoreDrawBackground && clrTextBk != -1) {
1077                                 boolean draw = !selected && !hot;
1078                                 if (!explorerTheme && selected) draw = !ignoreDrawSelection;
1079                                 if (draw) {
1080                                         if (columnCount == 0) {
1081                                                 if ((style & SWT.FULL_SELECTION) != 0) {
1082                                                         fillBackground (hDC, clrTextBk, rect);
1083                                                 } else {
1084                                                         RECT textRect = item.getBounds (index, true, false, false, false, true, hDC);
1085                                                         if (measureEvent != null) {
1086                                                                 textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1087                                                         }
1088                                                         fillBackground (hDC, clrTextBk, textRect);
1089                                                 }
1090                                         } else {
1091                                                 fillBackground (hDC, clrTextBk, cellRect);
1092                                         }
1093                                 }
1094                         }
1095                         if (ignoreDrawSelection) ignoreFullSelection = true;
1096                         if (!ignoreDrawSelection || !ignoreDrawHot) {
1097                                 if (!selected && !hot) {
1098                                         selectionForeground = clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
1099                                 }
1100                                 if (explorerTheme) {
1101                                         if ((style & SWT.FULL_SELECTION) == 0) {
1102                                                 RECT pRect = item.getBounds (index, true, true, false, false, false, hDC);
1103                                                 RECT pClipRect = item.getBounds (index, true, true, true, false, true, hDC);
1104                                                 if (measureEvent != null) {
1105                                                         pRect.right = Math.min (pClipRect.right, boundsInPixels.x + boundsInPixels.width);
1106                                                 } else {
1107                                                         pRect.right += EXPLORER_EXTRA;
1108                                                         pClipRect.right += EXPLORER_EXTRA;
1109                                                 }
1110                                                 pRect.left -= EXPLORER_EXTRA;
1111                                                 pClipRect.left -= EXPLORER_EXTRA;
1112                                                 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
1113                                                 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
1114                                                 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
1115                                                 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
1116                                                 OS.CloseThemeData (hTheme);
1117                                         }
1118                                 } else {
1119                                         /*
1120                                         * Feature in Windows.  When the tree has the style
1121                                         * TVS_FULLROWSELECT, the background color for the
1122                                         * entire row is filled when an item is painted,
1123                                         * drawing on top of any custom drawing.  The fix
1124                                         * is to emulate TVS_FULLROWSELECT.
1125                                         */
1126                                         if ((style & SWT.FULL_SELECTION) != 0) {
1127                                                 if ((style & SWT.FULL_SELECTION) != 0 && columnCount == 0) {
1128                                                         fillBackground (hDC, OS.GetBkColor (hDC), rect);
1129                                                 } else {
1130                                                         fillBackground (hDC, OS.GetBkColor (hDC), cellRect);
1131                                                 }
1132                                         } else {
1133                                                 RECT textRect = item.getBounds (index, true, false, false, false, true, hDC);
1134                                                 if (measureEvent != null) {
1135                                                         textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1136                                                 }
1137                                                 fillBackground (hDC, OS.GetBkColor (hDC), textRect);
1138                                         }
1139                                 }
1140                         } else {
1141                                 if (selected || hot) {
1142                                         selectionForeground = clrText = newTextClr;
1143                                         ignoreDrawSelection = ignoreDrawHot = true;
1144                                 }
1145                                 if (explorerTheme) {
1146                                         nmcd.uItemState |= OS.CDIS_DISABLED;
1147                                         /*
1148                                         * Feature in Windows.  On Vista only, when the text
1149                                         * color is unchanged and an item is asked to draw
1150                                         * disabled, it uses the disabled color.  The fix is
1151                                         * to modify the color so that is it no longer equal.
1152                                         */
1153                                         int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1154                                         if (nmcd.clrText == newColor) {
1155                                                 nmcd.clrText |= 0x20000000;
1156                                                 if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1157                                         } else {
1158                                                 nmcd.clrText = newColor;
1159                                         }
1160                                         OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1161                                 }
1162                         }
1163                         if (focused && !ignoreDrawFocus && (style & SWT.FULL_SELECTION) == 0) {
1164                                 RECT textRect = item.getBounds (index, true, explorerTheme, false, false, true, hDC);
1165                                 if (measureEvent != null) {
1166                                         textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1167                                 }
1168                                 nmcd.uItemState &= ~OS.CDIS_FOCUS;
1169                                 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1170                                 focusRect = textRect;
1171                         }
1172                         if (explorerTheme) {
1173                                 if (selected || (hot && ignoreDrawHot)) nmcd.uItemState &= ~OS.CDIS_HOT;
1174                                 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1175                         }
1176                         RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
1177                         OS.SaveDC (hDC);
1178                         OS.SelectClipRgn (hDC, 0);
1179                         if (explorerTheme) {
1180                                 itemRect.left -= EXPLORER_EXTRA;
1181                                 itemRect.right += EXPLORER_EXTRA;
1182                         }
1183                         //TODO - bug in Windows selection or SWT itemRect
1184                         /*if (selected)*/ itemRect.right++;
1185                         if (linesVisible) itemRect.bottom++;
1186                         if (clipRect != null) {
1187                                 OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1188                         }
1189                         OS.ExcludeClipRect (hDC, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
1190                         return new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1191                 }
1192                 /*
1193                 * Feature in Windows.  When the tree has the style
1194                 * TVS_FULLROWSELECT, the background color for the
1195                 * entire row is filled when an item is painted,
1196                 * drawing on top of any custom drawing.  The fix
1197                 * is to emulate TVS_FULLROWSELECT.
1198                 */
1199                 if ((style & SWT.FULL_SELECTION) != 0) {
1200                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1201                         if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1202                                 RECT rect = new RECT ();
1203                                 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1204                                 if (selected) {
1205                                         fillBackground (hDC, OS.GetBkColor (hDC), rect);
1206                                 } else {
1207                                         if (OS.IsWindowEnabled (handle)) drawBackground (hDC, rect);
1208                                 }
1209                                 nmcd.uItemState &= ~OS.CDIS_FOCUS;
1210                                 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1211                         }
1212                 }
1213         }
1214         LRESULT result = null;
1215         if (clrText == -1 && clrTextBk == -1 && hFont == -1) {
1216                 result = new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1217         } else {
1218                 result = new LRESULT (OS.CDRF_NEWFONT | OS.CDRF_NOTIFYPOSTPAINT);
1219                 if (hFont != -1) OS.SelectObject (hDC, hFont);
1220                 if (OS.IsWindowEnabled (handle) && OS.IsWindowVisible (handle)) {
1221                         /*
1222                         * Feature in Windows.  Windows does not fill the entire cell
1223                         * with the background color when TVS_FULLROWSELECT is not set.
1224                         * The fix is to fill the cell with the background color.
1225                         */
1226                         if (clrTextBk != -1) {
1227                                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1228                                 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1229                                         if (columnCount != 0 && hwndHeader != 0) {
1230                                                 RECT rect = new RECT ();
1231                                                 HDITEM hdItem = new HDITEM ();
1232                                                 hdItem.mask = OS.HDI_WIDTH;
1233                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1234                                                 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1235                                                 if (!OS.IsAppThemed ()) {
1236                                                         RECT itemRect = new RECT ();
1237                                                         if (OS.TreeView_GetItemRect (handle, item.handle, itemRect, true)) {
1238                                                                 rect.left = Math.min (itemRect.left, rect.right);
1239                                                         }
1240                                                 }
1241                                                 if ((style & SWT.FULL_SELECTION) != 0) {
1242                                                         if (!selected) fillBackground (hDC, clrTextBk, rect);
1243                                                 } else {
1244                                                         fillBackground (hDC, clrTextBk, rect);
1245                                                 }
1246                                         } else {
1247                                                 if ((style & SWT.FULL_SELECTION) != 0) {
1248                                                         RECT rect = new RECT ();
1249                                                         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1250                                                         if (!selected) fillBackground (hDC, clrTextBk, rect);
1251                                                 }
1252                                         }
1253                                 }
1254                         }
1255                         if (!selected) {
1256                                 nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
1257                                 nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;
1258                                 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1259                         }
1260                 }
1261         }
1262         if (OS.IsWindowEnabled (handle)) {
1263                 /*
1264                 * On Vista only, when an item is asked to draw disabled,
1265                 * the background of the text is not filled with the
1266                 * background color of the tree.  This is true for both
1267                 * regular and full selection trees.  In order to draw a
1268                 * background image, mark the item as disabled using
1269                 * CDIS_DISABLED (when not selected) and set the text
1270                 * to the regular text color to avoid drawing disabled.
1271                 */
1272                 if (explorerTheme) {
1273                         if (findImageControl () !=  null) {
1274                                 if (!selected && (nmcd.uItemState & (OS.CDIS_HOT | OS.CDIS_SELECTED)) == 0) {
1275                                         nmcd.uItemState |= OS.CDIS_DISABLED;
1276                                         /*
1277                                         * Feature in Windows.  On Vista only, when the text
1278                                         * color is unchanged and an item is asked to draw
1279                                         * disabled, it uses the disabled color.  The fix is
1280                                         * to modify the color so it is no longer equal.
1281                                         */
1282                                         int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1283                                         if (nmcd.clrText == newColor) {
1284                                                 nmcd.clrText |= 0x20000000;
1285                                                 if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1286                                         } else {
1287                                                 nmcd.clrText = newColor;
1288                                         }
1289                                         OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1290                                         if (clrTextBk != -1) {
1291                                                 if ((style & SWT.FULL_SELECTION) != 0) {
1292                                                         RECT rect = new RECT ();
1293                                                         if (columnCount != 0) {
1294                                                                 HDITEM hdItem = new HDITEM ();
1295                                                                 hdItem.mask = OS.HDI_WIDTH;
1296                                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1297                                                                 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1298                                                         } else {
1299                                                                 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1300                                                         }
1301                                                         fillBackground (hDC, clrTextBk, rect);
1302                                                 } else {
1303                                                         RECT textRect = item.getBounds (index, true, false, true, false, true, hDC);
1304                                                         fillBackground (hDC, clrTextBk, textRect);
1305                                                 }
1306                                         }
1307                                 }
1308                         }
1309                 }
1310         } else {
1311                 /*
1312                 * Feature in Windows.  When the tree is disabled, it draws
1313                 * with a gray background over the sort column.  The fix is
1314                 * to fill the background with the sort column color.
1315                 */
1316                 if (clrSortBk != -1) {
1317                         RECT rect = new RECT ();
1318                         HDITEM hdItem = new HDITEM ();
1319                         hdItem.mask = OS.HDI_WIDTH;
1320                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1321                         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1322                         fillBackground (hDC, clrSortBk, rect);
1323                 }
1324         }
1325         OS.SaveDC (hDC);
1326         if (clipRect != null) {
1327                 long hRgn = OS.CreateRectRgn (clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1328                 POINT lpPoint = new POINT ();
1329                 OS.GetWindowOrgEx (hDC, lpPoint);
1330                 OS.OffsetRgn (hRgn, -lpPoint.x, -lpPoint.y);
1331                 OS.SelectClipRgn (hDC, hRgn);
1332                 OS.DeleteObject (hRgn);
1333         }
1334         return result;
1335 }
1336
1337 LRESULT CDDS_POSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
1338         if (ignoreCustomDraw) return null;
1339         if (OS.IsWindowVisible (handle)) {
1340                 if (OS.IsAppThemed ()) {
1341                         if (sortColumn != null && sortDirection != SWT.NONE) {
1342                                 if (findImageControl () == null) {
1343                                         int index = indexOf (sortColumn);
1344                                         if (index != -1) {
1345                                                 int top = nmcd.top;
1346                                                 /*
1347                                                 * Bug in Windows.  For some reason, during a collapse,
1348                                                 * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1349                                                 * and the collapse causes the item being collapsed
1350                                                 * to become the last visible item in the tree, the
1351                                                 * message takes a long time to process.  In order for
1352                                                 * the slowness to happen, the children of the item
1353                                                 * must have children.  Times of up to 11 seconds have
1354                                                 * been observed with 23 children, each having one
1355                                                 * child.  The fix is to use the bottom partially
1356                                                 * visible item rather than the last possible item
1357                                                 * that could be visible.
1358                                                 *
1359                                                 * NOTE: This problem only happens on Vista during
1360                                                 * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1361                                                 */
1362                                                 long hItem = 0;
1363                                                 if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1364                                                         hItem = getBottomItem ();
1365                                                 } else {
1366                                                         hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1367                                                 }
1368                                                 if (hItem != 0) {
1369                                                         RECT rect = new RECT ();
1370                                                         if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
1371                                                                 top = rect.bottom;
1372                                                         }
1373                                                 }
1374                                                 RECT rect = new RECT ();
1375                                                 OS.SetRect (rect, nmcd.left, top, nmcd.right, nmcd.bottom);
1376                                                 RECT headerRect = new RECT ();
1377                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
1378                                                 rect.left = headerRect.left;
1379                                                 rect.right = headerRect.right;
1380                                                 fillBackground (nmcd.hdc, getSortColumnPixel (), rect);
1381                                         }
1382                                 }
1383                         }
1384                 }
1385                 if (linesVisible) {
1386                         long hDC = nmcd.hdc;
1387                         if (hwndHeader != 0) {
1388                                 int x = 0;
1389                                 RECT rect = new RECT ();
1390                                 HDITEM hdItem = new HDITEM ();
1391                                 hdItem.mask = OS.HDI_WIDTH;
1392                                 for (int i=0; i<columnCount; i++) {
1393                                         int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, i, 0);
1394                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1395                                         OS.SetRect (rect, x, nmcd.top, x + hdItem.cxy, nmcd.bottom);
1396                                         OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_RIGHT);
1397                                         x += hdItem.cxy;
1398                                 }
1399                         }
1400                         int height = 0;
1401                         RECT rect = new RECT ();
1402                         /*
1403                         * Bug in Windows.  For some reason, during a collapse,
1404                         * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1405                         * and the collapse causes the item being collapsed
1406                         * to become the last visible item in the tree, the
1407                         * message takes a long time to process.  In order for
1408                         * the slowness to happen, the children of the item
1409                         * must have children.  Times of up to 11 seconds have
1410                         * been observed with 23 children, each having one
1411                         * child.  The fix is to use the bottom partially
1412                         * visible item rather than the last possible item
1413                         * that could be visible.
1414                         *
1415                         * NOTE: This problem only happens on Vista during
1416                         * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1417                         */
1418                         long hItem = 0;
1419                         if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1420                                 hItem = getBottomItem ();
1421                         } else {
1422                                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1423                         }
1424                         if (hItem != 0) {
1425                                 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
1426                                         height = rect.bottom - rect.top;
1427                                 }
1428                         }
1429                         if (height == 0) {
1430                                 height = (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
1431                                 OS.GetClientRect (handle, rect);
1432                                 OS.SetRect (rect, rect.left, rect.top, rect.right, rect.top + height);
1433                                 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1434                         }
1435                         if (height != 0) {
1436                                 while (rect.bottom < nmcd.bottom) {
1437                                         int top = rect.top + height;
1438                                         OS.SetRect (rect, rect.left, top, rect.right, top + height);
1439                                         OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1440                                 }
1441                         }
1442                 }
1443         }
1444         return new LRESULT (OS.CDRF_DODEFAULT);
1445 }
1446
1447 LRESULT CDDS_PREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
1448         if (explorerTheme) {
1449                 if ((OS.IsWindowEnabled (handle) && hooks (SWT.EraseItem)) || hasCustomBackground() || findImageControl () != null) {
1450                         RECT rect = new RECT ();
1451                         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1452                         drawBackground (nmcd.hdc, rect);
1453                 }
1454         }
1455         return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
1456 }
1457
1458 @Override
1459 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
1460         if (handle == 0) return 0;
1461         if (hwndParent != 0 && hwnd == hwndParent) {
1462                 return OS.DefWindowProc (hwnd, msg, wParam, lParam);
1463         }
1464         if (hwndHeader != 0 && hwnd == hwndHeader) {
1465                 return OS.CallWindowProc (HeaderProc, hwnd, msg, wParam, lParam);
1466         }
1467         switch (msg) {
1468                 case OS.WM_SETFOCUS: {
1469                         /*
1470                         * Feature in Windows.  When a tree control processes WM_SETFOCUS,
1471                         * if no item is selected, the first item in the tree is selected.
1472                         * This is unexpected and might clear the previous selection.
1473                         * The fix is to detect that there is no selection and set it to
1474                         * the first visible item in the tree.  If the item was not selected,
1475                         * only the focus is assigned.
1476                         */
1477                         if ((style & SWT.SINGLE) != 0) break;
1478                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
1479                         if (hItem == 0) {
1480                                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1481                                 if (hItem != 0) {
1482                                         TVITEM tvItem = new TVITEM ();
1483                                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
1484                                         tvItem.hItem = hItem;
1485                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
1486                                         hSelect = hItem;
1487                                         ignoreDeselect = ignoreSelect = lockSelection = true;
1488                                         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem);
1489                                         ignoreDeselect = ignoreSelect = lockSelection = false;
1490                                         hSelect = 0;
1491                                         if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
1492                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1493                                         }
1494                                 }
1495                         }
1496                         break;
1497                 }
1498         }
1499         long hItem = 0;
1500         boolean redraw = false;
1501         switch (msg) {
1502                 /* Keyboard messages */
1503                 case OS.WM_KEYDOWN:
1504                         if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1505                         //FALL THROUGH
1506                 case OS.WM_CHAR:
1507                 case OS.WM_IME_CHAR:
1508                 case OS.WM_KEYUP:
1509                 case OS.WM_SYSCHAR:
1510                 case OS.WM_SYSKEYDOWN:
1511                 case OS.WM_SYSKEYUP:
1512                         //FALL THROUGH
1513
1514                 /* Scroll messages */
1515                 case OS.WM_HSCROLL:
1516                 case OS.WM_VSCROLL:
1517                         //FALL THROUGH
1518
1519                 /* Resize messages */
1520                 case OS.WM_SIZE:
1521                         redraw = findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle);
1522                         if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
1523                         //FALL THROUGH
1524
1525                 /* Mouse messages */
1526                 case OS.WM_LBUTTONDBLCLK:
1527                 case OS.WM_LBUTTONDOWN:
1528                 case OS.WM_LBUTTONUP:
1529                 case OS.WM_MBUTTONDBLCLK:
1530                 case OS.WM_MBUTTONDOWN:
1531                 case OS.WM_MBUTTONUP:
1532                 case OS.WM_MOUSEHOVER:
1533                 case OS.WM_MOUSELEAVE:
1534                 case OS.WM_MOUSEMOVE:
1535                 case OS.WM_MOUSEWHEEL:
1536                 case OS.WM_RBUTTONDBLCLK:
1537                 case OS.WM_RBUTTONDOWN:
1538                 case OS.WM_RBUTTONUP:
1539                 case OS.WM_XBUTTONDBLCLK:
1540                 case OS.WM_XBUTTONDOWN:
1541                 case OS.WM_XBUTTONUP:
1542                         //FALL THROUGH
1543
1544                 /* Other messages */
1545                 case OS.WM_SETFONT:
1546                 case OS.WM_TIMER: {
1547                         if (findImageControl () != null) {
1548                                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1549                         }
1550
1551                         break;
1552                 }
1553         }
1554         long code = OS.CallWindowProc (TreeProc, hwnd, msg, wParam, lParam);
1555         switch (msg) {
1556                 /* Keyboard messages */
1557                 case OS.WM_KEYDOWN:
1558                         if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1559                         //FALL THROUGH
1560                 case OS.WM_CHAR:
1561                 case OS.WM_IME_CHAR:
1562                 case OS.WM_KEYUP:
1563                 case OS.WM_SYSCHAR:
1564                 case OS.WM_SYSKEYDOWN:
1565                 case OS.WM_SYSKEYUP:
1566                         //FALL THROUGH
1567
1568                 /* Scroll messages */
1569                 case OS.WM_HSCROLL:
1570                 case OS.WM_VSCROLL:
1571                         //FALL THROUGH
1572
1573                 /* Resize messages */
1574                 case OS.WM_SIZE:
1575                         if (redraw) {
1576                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
1577                                 OS.InvalidateRect (handle, null, true);
1578                                 if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
1579                         }
1580                         //FALL THROUGH
1581
1582                 /* Mouse messages */
1583                 case OS.WM_LBUTTONDBLCLK:
1584                 case OS.WM_LBUTTONDOWN:
1585                 case OS.WM_LBUTTONUP:
1586                 case OS.WM_MBUTTONDBLCLK:
1587                 case OS.WM_MBUTTONDOWN:
1588                 case OS.WM_MBUTTONUP:
1589                 case OS.WM_MOUSEHOVER:
1590                 case OS.WM_MOUSELEAVE:
1591                 case OS.WM_MOUSEMOVE:
1592                 case OS.WM_MOUSEWHEEL:
1593                 case OS.WM_RBUTTONDBLCLK:
1594                 case OS.WM_RBUTTONDOWN:
1595                 case OS.WM_RBUTTONUP:
1596                 case OS.WM_XBUTTONDBLCLK:
1597                 case OS.WM_XBUTTONDOWN:
1598                 case OS.WM_XBUTTONUP:
1599                         //FALL THROUGH
1600
1601                 /* Other messages */
1602                 case OS.WM_SETFONT:
1603                 case OS.WM_TIMER: {
1604                         if (findImageControl () != null) {
1605                                 if (hItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) {
1606                                         OS.InvalidateRect (handle, null, true);
1607                                 }
1608                         }
1609                         updateScrollBar ();
1610                         break;
1611                 }
1612
1613                 case OS.WM_PAINT:
1614                         painted = true;
1615                         break;
1616         }
1617         return code;
1618 }
1619
1620 @Override
1621 void checkBuffered () {
1622         super.checkBuffered ();
1623         if ((style & SWT.VIRTUAL) != 0) {
1624                 style |= SWT.DOUBLE_BUFFERED;
1625                 OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
1626         }
1627         if (OS.IsAppThemed ()) {
1628                 int exStyle = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
1629                 if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) style |= SWT.DOUBLE_BUFFERED;
1630         }
1631 }
1632
1633 boolean checkData (TreeItem item, boolean redraw) {
1634         if ((style & SWT.VIRTUAL) == 0) return true;
1635         if (!item.cached) {
1636                 TreeItem parentItem = item.getParentItem ();
1637                 return checkData (item, parentItem == null ? indexOf (item) : parentItem.indexOf (item), redraw);
1638         }
1639         return true;
1640 }
1641
1642 boolean checkData (TreeItem item, int index, boolean redraw) {
1643         if ((style & SWT.VIRTUAL) == 0) return true;
1644         if (!item.cached) {
1645                 item.cached = true;
1646                 Event event = new Event ();
1647                 event.item = item;
1648                 event.index = index;
1649                 TreeItem oldItem = currentItem;
1650                 currentItem = item;
1651                 /*
1652                 * Bug in Windows.  If the tree scrolls during WM_NOTIFY
1653                 * with TVN_GETDISPINFO, pixel corruption occurs.  The fix
1654                 * is to detect that the top item has changed and redraw
1655                 * the entire tree.
1656                 */
1657                 long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1658                 sendEvent (SWT.SetData, event);
1659                 //widget could be disposed at this point
1660                 currentItem = oldItem;
1661                 if (isDisposed () || item.isDisposed ()) return false;
1662                 if (redraw) item.redraw ();
1663                 if (hTopItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) {
1664                         OS.InvalidateRect (handle, null, true);
1665                 }
1666         }
1667         return true;
1668 }
1669
1670 @Override
1671 boolean checkHandle (long hwnd) {
1672         return hwnd == handle || (hwndParent != 0 && hwnd == hwndParent) || (hwndHeader != 0 && hwnd == hwndHeader);
1673 }
1674
1675 boolean checkScroll (long hItem) {
1676         /*
1677         * Feature in Windows.  If redraw is turned off using WM_SETREDRAW
1678         * and a tree item that is not a child of the first root is selected or
1679         * scrolled using TVM_SELECTITEM or TVM_ENSUREVISIBLE, then scrolling
1680         * does not occur.  The fix is to detect this case, and make sure
1681         * that redraw is temporarily enabled.  To avoid flashing, DefWindowProc()
1682         * is called to disable redrawing.
1683         *
1684         * NOTE:  The code that actually works around the problem is in the
1685         * callers of this method.
1686         */
1687         if (getDrawing ()) return false;
1688         long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1689         long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
1690         while (hParent != hRoot && hParent != 0) {
1691                 hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hParent);
1692         }
1693         return hParent == 0;
1694 }
1695
1696 @Override
1697 protected void checkSubclass () {
1698         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
1699 }
1700
1701 /**
1702  * Clears the item at the given zero-relative index in the receiver.
1703  * The text, icon and other attributes of the item are set to the default
1704  * value.  If the tree was created with the <code>SWT.VIRTUAL</code> style,
1705  * these attributes are requested again as needed.
1706  *
1707  * @param index the index of the item to clear
1708  * @param all <code>true</code> if all child items of the indexed item should be
1709  * cleared recursively, and <code>false</code> otherwise
1710  *
1711  * @exception IllegalArgumentException <ul>
1712  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1713  * </ul>
1714  * @exception SWTException <ul>
1715  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1716  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1717  * </ul>
1718  *
1719  * @see SWT#VIRTUAL
1720  * @see SWT#SetData
1721  *
1722  * @since 3.2
1723  */
1724 public void clear (int index, boolean all) {
1725         checkWidget ();
1726         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1727         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1728         hItem = findItem (hItem, index);
1729         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1730         TVITEM tvItem = new TVITEM ();
1731         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1732         clear (hItem, tvItem);
1733         if (all) {
1734                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1735                 clearAll (hItem, tvItem, all);
1736         }
1737 }
1738
1739 void clear (long hItem, TVITEM tvItem) {
1740         tvItem.hItem = hItem;
1741         TreeItem item = null;
1742         if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
1743                 item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null;
1744         }
1745         if (item != null) {
1746                 if ((style & SWT.VIRTUAL) != 0 && !item.cached) return;
1747                 item.clear ();
1748                 item.redraw ();
1749         }
1750 }
1751
1752 /**
1753  * Clears all the items in the receiver. The text, icon and other
1754  * attributes of the items are set to their default values. If the
1755  * tree was created with the <code>SWT.VIRTUAL</code> style, these
1756  * attributes are requested again as needed.
1757  *
1758  * @param all <code>true</code> if all child items should be cleared
1759  * recursively, and <code>false</code> otherwise
1760  *
1761  * @exception SWTException <ul>
1762  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1763  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1764  * </ul>
1765  *
1766  * @see SWT#VIRTUAL
1767  * @see SWT#SetData
1768  *
1769  * @since 3.2
1770  */
1771 public void clearAll (boolean all) {
1772         checkWidget ();
1773         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1774         if (hItem == 0) return;
1775         if (all) {
1776                 boolean redraw = false;
1777                 for (int i=0; i<items.length; i++) {
1778                         TreeItem item = items [i];
1779                         if (item != null && item != currentItem) {
1780                                 item.clear ();
1781                                 redraw = true;
1782                         }
1783                 }
1784                 if (redraw) OS.InvalidateRect (handle, null, true);
1785         } else {
1786                 TVITEM tvItem = new TVITEM ();
1787                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1788                 clearAll (hItem, tvItem, all);
1789         }
1790 }
1791
1792 void clearAll (long hItem, TVITEM tvItem, boolean all) {
1793         while (hItem != 0) {
1794                 clear (hItem, tvItem);
1795                 if (all) {
1796                         long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1797                         clearAll (hFirstItem, tvItem, all);
1798                 }
1799                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
1800         }
1801 }
1802
1803 long CompareFunc (long lParam1, long lParam2, long lParamSort) {
1804         TreeItem item1 = items [(int)lParam1], item2 = items [(int)lParam2];
1805         String text1 = item1.getText ((int)lParamSort), text2 = item2.getText ((int)lParamSort);
1806         return sortDirection == SWT.UP ? text1.compareTo (text2) : text2.compareTo (text1);
1807 }
1808
1809 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
1810         int width = 0, height = 0;
1811         if (hwndHeader != 0) {
1812                 HDITEM hdItem = new HDITEM ();
1813                 hdItem.mask = OS.HDI_WIDTH;
1814                 for (int i=0; i<columnCount; i++) {
1815                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
1816                         width += hdItem.cxy;
1817                 }
1818                 RECT rect = new RECT ();
1819                 OS.GetWindowRect (hwndHeader, rect);
1820                 height += rect.bottom - rect.top;
1821         }
1822         RECT rect = new RECT ();
1823         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1824         while (hItem != 0) {
1825                 if ((style & SWT.VIRTUAL) == 0 && !painted) {
1826                         TVITEM tvItem = new TVITEM ();
1827                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1828                         tvItem.hItem = hItem;
1829                         tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1830                         ignoreCustomDraw = true;
1831                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1832                         ignoreCustomDraw = false;
1833                 }
1834                 if (OS.TreeView_GetItemRect (handle, hItem, rect, true)) {
1835                         width = Math.max (width, rect.right);
1836                         height += rect.bottom - rect.top;
1837                 }
1838                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
1839         }
1840         if (width == 0) width = DEFAULT_WIDTH;
1841         if (height == 0) height = DEFAULT_HEIGHT;
1842         if (wHint != SWT.DEFAULT) width = wHint;
1843         if (hHint != SWT.DEFAULT) height = hHint;
1844         int border = getBorderWidthInPixels ();
1845         width += border * 2;
1846         height += border * 2;
1847         if ((style & SWT.V_SCROLL) != 0) {
1848                 width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
1849         }
1850         if ((style & SWT.H_SCROLL) != 0) {
1851                 height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
1852         }
1853         return new Point (width, height);
1854 }
1855
1856 @Override
1857 void createHandle () {
1858         super.createHandle ();
1859         state &= ~(CANVAS | THEME_BACKGROUND);
1860
1861         /* Use the Explorer theme */
1862         if (OS.IsAppThemed ()) {
1863                 explorerTheme = true;
1864                 OS.SetWindowTheme (handle, Display.EXPLORER, null);
1865                 int bits = OS.TVS_EX_DOUBLEBUFFER | OS.TVS_EX_RICHTOOLTIP;
1866                 if (ENABLE_TVS_EX_FADEINOUTEXPANDOS) bits |= OS.TVS_EX_FADEINOUTEXPANDOS;
1867                 /*
1868                 * This code is intentionally commented.
1869                 */
1870 //              if ((style & SWT.FULL_SELECTION) == 0) bits |= OS.TVS_EX_AUTOHSCROLL;
1871                 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits);
1872                 /*
1873                 * Bug in Windows.  When the tree is using the explorer
1874                 * theme, it does not use COLOR_WINDOW_TEXT for the
1875                 * default foreground color.  The fix is to explicitly
1876                 * set the foreground.
1877                 */
1878                 setForegroundPixel (-1);
1879         }
1880
1881         /* Set the checkbox image list */
1882         if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
1883
1884         /*
1885         * Feature in Windows.  When the control is created,
1886         * it does not use the default system font.  A new HFONT
1887         * is created and destroyed when the control is destroyed.
1888         * This means that a program that queries the font from
1889         * this control, uses the font in another control and then
1890         * destroys this control will have the font unexpectedly
1891         * destroyed in the other control.  The fix is to assign
1892         * the font ourselves each time the control is created.
1893         * The control will not destroy a font that it did not
1894         * create.
1895         */
1896         long hFont = OS.GetStockObject (OS.SYSTEM_FONT);
1897         OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
1898
1899         /*
1900          * Bug in Windows. When image list is not set, tree glyph
1901          * size is tied to tree indent. Indent doesn't automatically
1902          * scale with DPI resulting in distorted glyph image
1903          * at higher DPI settings.
1904          */
1905         int indent = DPIUtil.autoScaleUpUsingNativeDPI(16);
1906         OS.SendMessage(handle, OS.TVM_SETINDENT, indent, 0);
1907
1908         createdAsRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
1909 }
1910
1911 void createHeaderToolTips () {
1912         if (headerToolTipHandle != 0) return;
1913         int bits = 0;
1914         if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
1915         headerToolTipHandle = OS.CreateWindowEx (
1916                 bits,
1917                 new TCHAR (0, OS.TOOLTIPS_CLASS, true),
1918                 null,
1919                 OS.TTS_NOPREFIX,
1920                 OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
1921                 handle,
1922                 0,
1923                 OS.GetModuleHandle (null),
1924                 null);
1925         if (headerToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
1926         /*
1927         * Feature in Windows.  Despite the fact that the
1928         * tool tip text contains \r\n, the tooltip will
1929         * not honour the new line unless TTM_SETMAXTIPWIDTH
1930         * is set.  The fix is to set TTM_SETMAXTIPWIDTH to
1931         * a large value.
1932         */
1933         OS.SendMessage (headerToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
1934 }
1935
1936 void createItem (TreeColumn column, int index) {
1937         if (hwndHeader == 0) createParent ();
1938         if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
1939         if (columnCount == columns.length) {
1940                 TreeColumn [] newColumns = new TreeColumn [columns.length + 4];
1941                 System.arraycopy (columns, 0, newColumns, 0, columns.length);
1942                 columns = newColumns;
1943         }
1944         for (int i=0; i<items.length; i++) {
1945                 TreeItem item = items [i];
1946                 if (item != null) {
1947                         String [] strings = item.strings;
1948                         if (strings != null) {
1949                                 String [] temp = new String [columnCount + 1];
1950                                 System.arraycopy (strings, 0, temp, 0, index);
1951                                 System.arraycopy (strings, index, temp, index + 1, columnCount - index);
1952                                 item.strings = temp;
1953                         }
1954                         Image [] images = item.images;
1955                         if (images != null) {
1956                                 Image [] temp = new Image [columnCount + 1];
1957                                 System.arraycopy (images, 0, temp, 0, index);
1958                                 System.arraycopy (images, index, temp, index + 1, columnCount - index);
1959                                 item.images = temp;
1960                         }
1961                         if (index == 0) {
1962                                 if (columnCount != 0) {
1963                                         if (strings == null) {
1964                                                 item.strings = new String [columnCount + 1];
1965                                                 item.strings [1] = item.text;
1966                                         }
1967                                         item.text = "";
1968                                         if (images == null) {
1969                                                 item.images = new Image [columnCount + 1];
1970                                                 item.images [1] = item.image;
1971                                         }
1972                                         item.image = null;
1973                                 }
1974                         }
1975                         if (item.cellBackground != null) {
1976                                 int [] cellBackground = item.cellBackground;
1977                                 int [] temp = new int [columnCount + 1];
1978                                 System.arraycopy (cellBackground, 0, temp, 0, index);
1979                                 System.arraycopy (cellBackground, index, temp, index + 1, columnCount - index);
1980                                 temp [index] = -1;
1981                                 item.cellBackground = temp;
1982                         }
1983                         if (item.cellForeground != null) {
1984                                 int [] cellForeground = item.cellForeground;
1985                                 int [] temp = new int [columnCount + 1];
1986                                 System.arraycopy (cellForeground, 0, temp, 0, index);
1987                                 System.arraycopy (cellForeground, index, temp, index + 1, columnCount - index);
1988                                 temp [index] = -1;
1989                                 item.cellForeground = temp;
1990                         }
1991                         if (item.cellFont != null) {
1992                                 Font [] cellFont = item.cellFont;
1993                                 Font [] temp = new Font [columnCount + 1];
1994                                 System.arraycopy (cellFont, 0, temp, 0, index);
1995                                 System.arraycopy (cellFont, index, temp, index + 1, columnCount- index);
1996                                 item.cellFont = temp;
1997                         }
1998                 }
1999         }
2000         System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
2001         columns [index] = column;
2002
2003         /*
2004         * Bug in Windows.  For some reason, when HDM_INSERTITEM
2005         * is used to insert an item into a header without text,
2006         * if is not possible to set the text at a later time.
2007         * The fix is to insert the item with an empty string.
2008         */
2009         long hHeap = OS.GetProcessHeap ();
2010         long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
2011         HDITEM hdItem = new HDITEM ();
2012         hdItem.mask = OS.HDI_TEXT | OS.HDI_FORMAT;
2013         hdItem.pszText = pszText;
2014         if ((column.style & SWT.LEFT) == SWT.LEFT) hdItem.fmt = OS.HDF_LEFT;
2015         if ((column.style & SWT.CENTER) == SWT.CENTER) hdItem.fmt = OS.HDF_CENTER;
2016         if ((column.style & SWT.RIGHT) == SWT.RIGHT) hdItem.fmt = OS.HDF_RIGHT;
2017         OS.SendMessage (hwndHeader, OS.HDM_INSERTITEM, index, hdItem);
2018         if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
2019
2020         /* When the first column is created, hide the horizontal scroll bar */
2021         if (columnCount == 1) {
2022                 scrollWidth = 0;
2023                 if ((style & SWT.H_SCROLL) != 0) {
2024                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2025                         bits |= OS.TVS_NOHSCROLL;
2026                         OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2027                 }
2028                 /*
2029                 * Bug in Windows.  When TVS_NOHSCROLL is set after items
2030                 * have been inserted into the tree, Windows shows the
2031                 * scroll bar.  The fix is to check for this case and
2032                 * explicitly hide the scroll bar explicitly.
2033                 */
2034                 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
2035                 if (count != 0) {
2036                         OS.ShowScrollBar (handle, OS.SB_HORZ, false);
2037                 }
2038                 createItemToolTips ();
2039                 if (itemToolTipHandle != 0) {
2040                         OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_AUTOMATIC, -1);
2041                 }
2042         }
2043         setScrollWidth ();
2044         updateImageList ();
2045         updateScrollBar ();
2046
2047         /* Redraw to hide the items when the first column is created */
2048         if (columnCount == 1 && OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) != 0) {
2049                 OS.InvalidateRect (handle, null, true);
2050         }
2051
2052         /* Add the tool tip item for the header */
2053         if (headerToolTipHandle != 0) {
2054                 RECT rect = new RECT ();
2055                 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, rect) != 0) {
2056                         TOOLINFO lpti = new TOOLINFO ();
2057                         lpti.cbSize = TOOLINFO.sizeof;
2058                         lpti.uFlags = OS.TTF_SUBCLASS;
2059                         lpti.hwnd = hwndHeader;
2060                         lpti.uId = column.id = display.nextToolTipId++;
2061                         lpti.left = rect.left;
2062                         lpti.top = rect.top;
2063                         lpti.right = rect.right;
2064                         lpti.bottom = rect.bottom;
2065                         lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2066                         OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2067                 }
2068         }
2069 }
2070
2071 // For fast bulk insert, see comments for TreeItem#TreeItem(TreeItem,int,int)
2072 void createItem (TreeItem item, long hParent, long hInsertAfter, long hItem) {
2073         int id = -1;
2074         if (item != null) {
2075                 id = lastID < items.length ? lastID : 0;
2076                 while (id < items.length && items [id] != null) id++;
2077                 if (id == items.length) {
2078                         /*
2079                         * Grow the array faster when redraw is off or the
2080                         * table is not visible.  When the table is painted,
2081                         * the items array is resized to be smaller to reduce
2082                         * memory usage.
2083                         */
2084                         int length = 0;
2085                         if (getDrawing () && OS.IsWindowVisible (handle)) {
2086                                 length = items.length + 4;
2087                         } else {
2088                                 shrink = true;
2089                                 length = Math.max (4, items.length * 3 / 2);
2090                         }
2091                         TreeItem [] newItems = new TreeItem [length];
2092                         System.arraycopy (items, 0, newItems, 0, items.length);
2093                         items = newItems;
2094                 }
2095                 lastID = id + 1;
2096         }
2097         long hNewItem = 0;
2098         long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
2099         boolean fixParent = hFirstItem == 0;
2100         if (hItem == 0) {
2101                 TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
2102                 tvInsert.hParent = hParent;
2103                 tvInsert.hInsertAfter = hInsertAfter;
2104                 tvInsert.lParam = id;
2105                 tvInsert.pszText = OS.LPSTR_TEXTCALLBACK;
2106                 tvInsert.iImage = tvInsert.iSelectedImage = OS.I_IMAGECALLBACK;
2107                 tvInsert.mask = OS.TVIF_TEXT | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE | OS.TVIF_HANDLE | OS.TVIF_PARAM;
2108                 if ((style & SWT.CHECK) != 0) {
2109                         tvInsert.mask = tvInsert.mask | OS.TVIF_STATE;
2110                         tvInsert.state = 1 << 12;
2111                         tvInsert.stateMask = OS.TVIS_STATEIMAGEMASK;
2112                 }
2113                 ignoreCustomDraw = true;
2114                 hNewItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
2115                 ignoreCustomDraw = false;
2116                 if (hNewItem == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
2117                 /*
2118                 * This code is intentionally commented.
2119                 */
2120 //              if (hParent != 0) {
2121 //                      int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2122 //                      bits |= OS.TVS_LINESATROOT;
2123 //                      OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2124 //              }
2125         } else {
2126                 TVITEM tvItem = new TVITEM ();
2127                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
2128                 tvItem.hItem = hNewItem = hItem;
2129                 tvItem.lParam = id;
2130                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2131         }
2132         if (item != null) {
2133                 item.handle = hNewItem;
2134                 items [id] = item;
2135         }
2136         if (hFirstItem == 0) {
2137                 if (hInsertAfter == OS.TVI_FIRST || hInsertAfter == OS.TVI_LAST) {
2138                         hFirstIndexOf = hLastIndexOf = hFirstItem = hNewItem;
2139                         itemCount = lastIndexOf = 0;
2140                 }
2141         }
2142         if (hFirstItem == hFirstIndexOf && itemCount != -1) itemCount++;
2143         if (hItem == 0) {
2144                 /*
2145                 * Bug in Windows.  When a child item is added to a parent item
2146                 * that has no children outside of WM_NOTIFY with control code
2147                 * TVN_ITEMEXPANDED, the tree widget does not redraw the +/-
2148                 * indicator.  The fix is to detect the case when the first
2149                 * child is added to a visible parent item and redraw the parent.
2150                 */
2151                 if (fixParent) {
2152                         if (getDrawing () && OS.IsWindowVisible (handle)) {
2153                                 RECT rect = new RECT ();
2154                                 if (OS.TreeView_GetItemRect (handle, hParent, rect, false)) {
2155                                         OS.InvalidateRect (handle, rect, true);
2156                                 }
2157                         }
2158                 }
2159                 /*
2160                 * Bug in Windows.  When a new item is added while Windows
2161                 * is requesting data a tree item using TVN_GETDISPINFO,
2162                 * outstanding damage for items that are below the new item
2163                 * is not scrolled.  The fix is to explicitly damage the
2164                 * new area.
2165                 */
2166                 if ((style & SWT.VIRTUAL) != 0) {
2167                         if (currentItem != null) {
2168                                 RECT rect = new RECT ();
2169                                 if (OS.TreeView_GetItemRect (handle, hNewItem, rect, false)) {
2170                                         RECT damageRect = new RECT ();
2171                                         boolean damaged = OS.GetUpdateRect (handle, damageRect, true);
2172                                         if (damaged && damageRect.top < rect.bottom) {
2173                                                 long rgn = OS.CreateRectRgn (0, 0, 0, 0);
2174                                                 int result = OS.GetUpdateRgn (handle, rgn, true);
2175                                                 if (result != OS.NULLREGION) {
2176                                                         OS.OffsetRgn (rgn, 0, rect.bottom - rect.top);
2177                                                         OS.InvalidateRgn (handle, rgn, true);
2178                                                 }
2179                                                 OS.DeleteObject (rgn);
2180                                         }
2181                                 }
2182                         }
2183                 }
2184
2185                 /*
2186                  Note: Don't update scrollbars when drawing is disabled.
2187                  This gives significant improvement for bulk insert scenarios.
2188                  Later, setRedraw(true) will update scrollbars once.
2189                  */
2190                 if (getDrawing ()) updateScrollBar ();
2191         }
2192 }
2193
2194 void createItemToolTips () {
2195         if (itemToolTipHandle != 0) return;
2196         int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
2197         bits1 |= OS.TVS_NOTOOLTIPS;
2198         OS.SetWindowLong (handle, OS.GWL_STYLE, bits1);
2199         int bits2 = 0;
2200         if ((style & SWT.RIGHT_TO_LEFT) != 0) bits2 |= OS.WS_EX_LAYOUTRTL;
2201         /*
2202         * Feature in Windows.  For some reason, when the user
2203         * clicks on a tool tip, it temporarily takes focus, even
2204         * when WS_EX_NOACTIVATE is specified.  The fix is to
2205         * use WS_EX_TRANSPARENT, even though WS_EX_TRANSPARENT
2206         * is documented to affect painting, not hit testing.
2207         */
2208         bits2 |= OS.WS_EX_TRANSPARENT;
2209         itemToolTipHandle = OS.CreateWindowEx (
2210                 bits2,
2211                 new TCHAR (0, OS.TOOLTIPS_CLASS, true),
2212                 null,
2213                 OS.TTS_NOPREFIX | OS.TTS_NOANIMATE | OS.TTS_NOFADE,
2214                 OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
2215                 handle,
2216                 0,
2217                 OS.GetModuleHandle (null),
2218                 null);
2219         if (itemToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
2220         OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_INITIAL, 0);
2221         /*
2222         * Feature in Windows.  Despite the fact that the
2223         * tool tip text contains \r\n, the tooltip will
2224         * not honour the new line unless TTM_SETMAXTIPWIDTH
2225         * is set.  The fix is to set TTM_SETMAXTIPWIDTH to
2226         * a large value.
2227         */
2228         OS.SendMessage (itemToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
2229         TOOLINFO lpti = new TOOLINFO ();
2230         lpti.cbSize = TOOLINFO.sizeof;
2231         lpti.hwnd = handle;
2232         lpti.uId = handle;
2233         lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
2234         lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2235         OS.SendMessage (itemToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2236 }
2237
2238 void createParent () {
2239         forceResize ();
2240         RECT rect = new RECT ();
2241         OS.GetWindowRect (handle, rect);
2242         OS.MapWindowPoints (0, parent.handle, rect, 2);
2243         int oldStyle = OS.GetWindowLong (handle, OS.GWL_STYLE);
2244         int newStyle = super.widgetStyle () & ~OS.WS_VISIBLE;
2245         if ((oldStyle & OS.WS_DISABLED) != 0) newStyle |= OS.WS_DISABLED;
2246 //      if ((oldStyle & OS.WS_VISIBLE) != 0) newStyle |= OS.WS_VISIBLE;
2247         hwndParent = OS.CreateWindowEx (
2248                 super.widgetExtStyle (),
2249                 super.windowClass (),
2250                 null,
2251                 newStyle,
2252                 rect.left,
2253                 rect.top,
2254                 rect.right - rect.left,
2255                 rect.bottom - rect.top,
2256                 parent.handle,
2257                 0,
2258                 OS.GetModuleHandle (null),
2259                 null);
2260         if (hwndParent == 0) error (SWT.ERROR_NO_HANDLES);
2261         OS.SetWindowLongPtr (hwndParent, OS.GWLP_ID, hwndParent);
2262         int bits = OS.WS_EX_NOINHERITLAYOUT;
2263         if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
2264         hwndHeader = OS.CreateWindowEx (
2265                 bits,
2266                 HeaderClass,
2267                 null,
2268                 OS.HDS_BUTTONS | OS.HDS_FULLDRAG | OS.HDS_DRAGDROP | OS.HDS_HIDDEN | OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
2269                 0, 0, 0, 0,
2270                 hwndParent,
2271                 0,
2272                 OS.GetModuleHandle (null),
2273                 null);
2274         if (hwndHeader == 0) error (SWT.ERROR_NO_HANDLES);
2275         OS.SetWindowLongPtr (hwndHeader, OS.GWLP_ID, hwndHeader);
2276         if (OS.IsDBLocale) {
2277                 long hIMC = OS.ImmGetContext (handle);
2278                 OS.ImmAssociateContext (hwndParent, hIMC);
2279                 OS.ImmAssociateContext (hwndHeader, hIMC);
2280                 OS.ImmReleaseContext (handle, hIMC);
2281         }
2282         //This code is intentionally commented
2283 //      if (!OS.IsPPC) {
2284 //              if ((style & SWT.BORDER) != 0) {
2285 //                      int oldExStyle = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
2286 //                      oldExStyle &= ~OS.WS_EX_CLIENTEDGE;
2287 //                      OS.SetWindowLong (handle, OS.GWL_EXSTYLE, oldExStyle);
2288 //              }
2289 //      }
2290         long hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
2291         if (hFont != 0) OS.SendMessage (hwndHeader, OS.WM_SETFONT, hFont, 0);
2292         long hwndInsertAfter = OS.GetWindow (handle, OS.GW_HWNDPREV);
2293         int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
2294         OS.SetWindowPos (hwndParent, hwndInsertAfter, 0, 0, 0, 0, flags);
2295         SCROLLINFO info = new SCROLLINFO ();
2296         info.cbSize = SCROLLINFO.sizeof;
2297         info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
2298         OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
2299         info.nPage = info.nMax + 1;
2300         OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
2301         OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
2302         info.nPage = info.nMax + 1;
2303         OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
2304         customDraw = true;
2305         deregister ();
2306         if ((oldStyle & OS.WS_VISIBLE) != 0) {
2307                 OS.ShowWindow (hwndParent, OS.SW_SHOW);
2308         }
2309         long hwndFocus = OS.GetFocus ();
2310         if (hwndFocus == handle) OS.SetFocus (hwndParent);
2311         OS.SetParent (handle, hwndParent);
2312         if (hwndFocus == handle) OS.SetFocus (handle);
2313         register ();
2314         subclass ();
2315 }
2316
2317 @Override
2318 void createWidget () {
2319         super.createWidget ();
2320         items = new TreeItem [4];
2321         columns = new TreeColumn [4];
2322         itemCount = -1;
2323 }
2324
2325 private boolean customHeaderDrawing() {
2326         return headerBackground != -1 || headerForeground != -1;
2327 }
2328
2329 @Override
2330 int defaultBackground () {
2331         return OS.GetSysColor (OS.COLOR_WINDOW);
2332 }
2333
2334 @Override
2335 void deregister () {
2336         super.deregister ();
2337         if (hwndParent != 0) display.removeControl (hwndParent);
2338         if (hwndHeader != 0) display.removeControl (hwndHeader);
2339 }
2340
2341 void deselect (long hItem, TVITEM tvItem, long hIgnoreItem) {
2342         while (hItem != 0) {
2343                 if (hItem != hIgnoreItem) {
2344                         tvItem.hItem = hItem;
2345                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2346                 }
2347                 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
2348                 deselect (hFirstItem, tvItem, hIgnoreItem);
2349                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
2350         }
2351 }
2352
2353 /**
2354  * Deselects an item in the receiver.  If the item was already
2355  * deselected, it remains deselected.
2356  *
2357  * @param item the item to be deselected
2358  *
2359  * @exception IllegalArgumentException <ul>
2360  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
2361  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
2362  * </ul>
2363  * @exception SWTException <ul>
2364  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2365  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2366  * </ul>
2367  *
2368  * @since 3.4
2369  */
2370 public void deselect (TreeItem item) {
2371         checkWidget ();
2372         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
2373         if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
2374         TVITEM tvItem = new TVITEM ();
2375         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
2376         tvItem.stateMask = OS.TVIS_SELECTED;
2377         tvItem.hItem = item.handle;
2378         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2379 }
2380
2381 /**
2382  * Deselects all selected items in the receiver.
2383  *
2384  * @exception SWTException <ul>
2385  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2386  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2387  * </ul>
2388  */
2389 public void deselectAll () {
2390         checkWidget ();
2391         TVITEM tvItem = new TVITEM ();
2392         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
2393         tvItem.stateMask = OS.TVIS_SELECTED;
2394         if ((style & SWT.SINGLE) != 0) {
2395                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2396                 if (hItem != 0) {
2397                         tvItem.hItem = hItem;
2398                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2399                 }
2400         } else {
2401                 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
2402                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
2403                 if ((style & SWT.VIRTUAL) != 0) {
2404                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
2405                         deselect (hItem, tvItem, 0);
2406                 } else {
2407                         for (int i=0; i<items.length; i++) {
2408                                 TreeItem item = items [i];
2409                                 if (item != null) {
2410                                         tvItem.hItem = item.handle;
2411                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2412                                 }
2413                         }
2414                 }
2415                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
2416         }
2417 }
2418
2419 void destroyItem (TreeColumn column) {
2420         if (hwndHeader == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
2421         int index = 0;
2422         while (index < columnCount) {
2423                 if (columns [index] == column) break;
2424                 index++;
2425         }
2426         int [] oldOrder = new int [columnCount];
2427         OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder);
2428         int orderIndex = 0;
2429         while (orderIndex < columnCount) {
2430                 if (oldOrder [orderIndex] == index) break;
2431                 orderIndex++;
2432         }
2433         RECT headerRect = new RECT ();
2434         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
2435         if (OS.SendMessage (hwndHeader, OS.HDM_DELETEITEM, index, 0) == 0) {
2436                 error (SWT.ERROR_ITEM_NOT_REMOVED);
2437         }
2438         System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
2439         columns [columnCount] = null;
2440         for (int i=0; i<items.length; i++) {
2441                 TreeItem item = items [i];
2442                 if (item != null) {
2443                         if (columnCount == 0) {
2444                                 item.strings = null;
2445                                 item.images = null;
2446                                 item.cellBackground = null;
2447                                 item.cellForeground = null;
2448                                 item.cellFont = null;
2449                         } else {
2450                                 if (item.strings != null) {
2451                                         String [] strings = item.strings;
2452                                         if (index == 0) {
2453                                                 item.text = strings [1] != null ? strings [1] : "";
2454                                         }
2455                                         String [] temp = new String [columnCount];
2456                                         System.arraycopy (strings, 0, temp, 0, index);
2457                                         System.arraycopy (strings, index + 1, temp, index, columnCount - index);
2458                                         item.strings = temp;
2459                                 } else {
2460                                         if (index == 0) item.text = "";
2461                                 }
2462                                 if (item.images != null) {
2463                                         Image [] images = item.images;
2464                                         if (index == 0) item.image = images [1];
2465                                         Image [] temp = new Image [columnCount];
2466                                         System.arraycopy (images, 0, temp, 0, index);
2467                                         System.arraycopy (images, index + 1, temp, index, columnCount - index);
2468                                         item.images = temp;
2469                                 } else {
2470                                         if (index == 0) item.image = null;
2471                                 }
2472                                 if (item.cellBackground != null) {
2473                                         int [] cellBackground = item.cellBackground;
2474                                         int [] temp = new int [columnCount];
2475                                         System.arraycopy (cellBackground, 0, temp, 0, index);
2476                                         System.arraycopy (cellBackground, index + 1, temp, index, columnCount - index);
2477                                         item.cellBackground = temp;
2478                                 }
2479                                 if (item.cellForeground != null) {
2480                                         int [] cellForeground = item.cellForeground;
2481                                         int [] temp = new int [columnCount];
2482                                         System.arraycopy (cellForeground, 0, temp, 0, index);
2483                                         System.arraycopy (cellForeground, index + 1, temp, index, columnCount - index);
2484                                         item.cellForeground = temp;
2485                                 }
2486                                 if (item.cellFont != null) {
2487                                         Font [] cellFont = item.cellFont;
2488                                         Font [] temp = new Font [columnCount];
2489                                         System.arraycopy (cellFont, 0, temp, 0, index);
2490                                         System.arraycopy (cellFont, index + 1, temp, index, columnCount - index);
2491                                         item.cellFont = temp;
2492                                 }
2493                         }
2494                 }
2495         }
2496
2497         /*
2498         * When the last column is deleted, show the horizontal
2499         * scroll bar.  Otherwise, left align the first column
2500         * and redraw the columns to the right.
2501         */
2502         if (columnCount == 0) {
2503                 scrollWidth = 0;
2504                 if (!hooks (SWT.MeasureItem)) {
2505                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2506                         if ((style & SWT.H_SCROLL) != 0) bits &= ~OS.TVS_NOHSCROLL;
2507                         OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2508                         OS.InvalidateRect (handle, null, true);
2509                 }
2510                 if (itemToolTipHandle != 0) {
2511                         OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_INITIAL, 0);
2512                 }
2513         } else {
2514                 if (index == 0) {
2515                         columns [0].style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
2516                         columns [0].style |= SWT.LEFT;
2517                         HDITEM hdItem = new HDITEM ();
2518                         hdItem.mask = OS.HDI_FORMAT | OS.HDI_IMAGE;
2519                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
2520                         hdItem.fmt &= ~OS.HDF_JUSTIFYMASK;
2521                         hdItem.fmt |= OS.HDF_LEFT;
2522                         OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, hdItem);
2523                 }
2524                 RECT rect = new RECT ();
2525                 OS.GetClientRect (handle, rect);
2526                 rect.left = headerRect.left;
2527                 OS.InvalidateRect (handle, rect, true);
2528         }
2529         setScrollWidth ();
2530         updateImageList ();
2531         updateScrollBar ();
2532         if (columnCount != 0) {
2533                 int [] newOrder = new int [columnCount];
2534                 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, newOrder);
2535                 TreeColumn [] newColumns = new TreeColumn [columnCount - orderIndex];
2536                 for (int i=orderIndex; i<newOrder.length; i++) {
2537                         newColumns [i - orderIndex] = columns [newOrder [i]];
2538                         newColumns [i - orderIndex].updateToolTip (newOrder [i]);
2539                 }
2540                 for (int i=0; i<newColumns.length; i++) {
2541                         if (!newColumns [i].isDisposed ()) {
2542                                 newColumns [i].sendEvent (SWT.Move);
2543                         }
2544                 }
2545         }
2546
2547         /* Remove the tool tip item for the header */
2548         if (headerToolTipHandle != 0) {
2549                 TOOLINFO lpti = new TOOLINFO ();
2550                 lpti.cbSize = TOOLINFO.sizeof;
2551                 lpti.uId = column.id;
2552                 lpti.hwnd = hwndHeader;
2553                 OS.SendMessage (headerToolTipHandle, OS.TTM_DELTOOL, 0, lpti);
2554         }
2555 }
2556
2557 void destroyItem (TreeItem item, long hItem) {
2558         hFirstIndexOf = hLastIndexOf = 0;
2559         itemCount = -1;
2560         /*
2561         * Feature in Windows.  When an item is removed that is not
2562         * visible in the tree because it belongs to a collapsed branch,
2563         * Windows redraws the tree causing a flash for each item that
2564         * is removed.  The fix is to detect whether the item is visible,
2565         * force the widget to be fully painted, turn off redraw, remove
2566         * the item and validate the damage caused by the removing of
2567         * the item.
2568         *
2569         * NOTE: This fix is not necessary when double buffering and
2570         * can cause problems for virtual trees due to the call to
2571         * UpdateWindow() that flushes outstanding WM_PAINT events,
2572         * allowing application code to add or remove items during
2573         * this remove operation.
2574         */
2575         long hParent = 0;
2576         boolean fixRedraw = false;
2577         if ((style & SWT.DOUBLE_BUFFERED) == 0) {
2578                 if (getDrawing () && OS.IsWindowVisible (handle)) {
2579                         RECT rect = new RECT ();
2580                         fixRedraw = !OS.TreeView_GetItemRect (handle, hItem, rect, false);
2581                 }
2582         }
2583         if (fixRedraw) {
2584                 hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
2585                 OS.UpdateWindow (handle);
2586                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
2587                 /*
2588                 * This code is intentionally commented.
2589                 */
2590 //              OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
2591         }
2592         ignoreDeselect = ignoreSelect = lockSelection = true;
2593
2594         /*
2595         * Feature in Windows.  When an item is deleted and a tool tip
2596         * is showing, Window requests the new text for the new item
2597         * that is under the cursor right away.  This means that when
2598         * multiple items are deleted, the tool tip flashes, showing
2599         * each new item in the tool tip as it is scrolled into view.
2600         * The fix is to hide tool tips when any item is deleted.
2601         *
2602         * NOTE:  This only happens on Vista.
2603         */
2604         long hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
2605         if (hwndToolTip != 0) OS.SendMessage (hwndToolTip, OS.TTM_POP, 0 ,0);
2606
2607         shrink = ignoreShrink = true;
2608         OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
2609         ignoreShrink = false;
2610         /*
2611          * Bug 546333: When TVGN_CARET item is deleted, Windows automatically
2612          * sets selection to some other item. We do not want that.
2613          */
2614         ignoreDeselect = ignoreSelect = lockSelection = false;
2615         if (fixRedraw) {
2616                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
2617                 OS.ValidateRect (handle, null);
2618                 /*
2619                 * If the item that was deleted was the last child of a tree item that
2620                 * is visible, redraw the parent item to force the +/- to be updated.
2621                 */
2622                 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent) == 0) {
2623                         RECT rect = new RECT ();
2624                         if (OS.TreeView_GetItemRect (handle, hParent, rect, false)) {
2625                                 OS.InvalidateRect (handle, rect, true);
2626                         }
2627                 }
2628         }
2629         int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
2630         if (count == 0) {
2631                 if (imageList != null) {
2632                         OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
2633                         display.releaseImageList (imageList);
2634                 }
2635                 imageList = null;
2636                 if (hwndParent == 0 && !linesVisible) {
2637                         if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
2638                                 customDraw = false;
2639                         }
2640                 }
2641                 items = new TreeItem [4];
2642                 scrollWidth = 0;
2643                 setScrollWidth ();
2644         }
2645
2646         /*
2647          Note: Don't update scrollbars when drawing is disabled.
2648          This gives significant improvement for bulk remove scenarios.
2649          Later, setRedraw(true) will update scrollbars once.
2650          */
2651         if (getDrawing ()) updateScrollBar ();
2652 }
2653
2654 @Override
2655 void destroyScrollBar (int type) {
2656         super.destroyScrollBar (type);
2657         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2658         if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
2659                 bits &= ~(OS.WS_HSCROLL | OS.WS_VSCROLL);
2660                 bits |= OS.TVS_NOSCROLL;
2661         } else {
2662                 if ((style & SWT.H_SCROLL) == 0) {
2663                         bits &= ~OS.WS_HSCROLL;
2664                         bits |= OS.TVS_NOHSCROLL;
2665                 }
2666         }
2667         OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2668 }
2669
2670 @Override
2671 void enableDrag (boolean enabled) {
2672         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2673         if (enabled && hooks (SWT.DragDetect)) {
2674                 bits &= ~OS.TVS_DISABLEDRAGDROP;
2675         } else {
2676                 bits |= OS.TVS_DISABLEDRAGDROP;
2677         }
2678         OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2679 }
2680
2681 @Override
2682 void enableWidget (boolean enabled) {
2683         super.enableWidget (enabled);
2684         /*
2685         * Bug in Windows.  On Vista only, Windows does not draw using
2686         * the background color when the tree is disabled.  The fix is
2687         * to set the default color, even when the color has not been
2688         * changed, causing Windows to draw correctly.
2689         */
2690         Control control = findBackgroundControl ();
2691         if (control == null) control = this;
2692         if (control.backgroundImage == null) {
2693                 _setBackgroundPixel (hasCustomBackground() ? control.getBackgroundPixel () : -1);
2694         }
2695         if (hwndParent != 0) OS.EnableWindow (hwndParent, enabled);
2696
2697         /*
2698         * Feature in Windows.  When the tree has the style
2699         * TVS_FULLROWSELECT, the background color for the
2700         * entire row is filled when an item is painted,
2701         * drawing on top of the sort column color.  The fix
2702         * is to clear TVS_FULLROWSELECT when there is
2703         * as sort column.
2704         */
2705         updateFullSelection ();
2706 }
2707
2708 boolean findCell (int x, int y, TreeItem [] item, int [] index, RECT [] cellRect, RECT [] itemRect) {
2709         boolean found = false;
2710         TVHITTESTINFO lpht = new TVHITTESTINFO ();
2711         lpht.x = x;
2712         lpht.y = y;
2713         OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
2714         if (lpht.hItem != 0) {
2715                 item [0] = _getItem (lpht.hItem);
2716                 POINT pt = new POINT ();
2717                 pt.x = x;
2718                 pt.y = y;
2719                 long hDC = OS.GetDC (handle);
2720                 long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
2721                 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
2722                 RECT rect = new RECT ();
2723                 if (hwndParent != 0) {
2724                         OS.GetClientRect (hwndParent, rect);
2725                         OS.MapWindowPoints (hwndParent, handle, rect, 2);
2726                 } else {
2727                         OS.GetClientRect (handle, rect);
2728                 }
2729                 int count = Math.max (1, columnCount);
2730                 int [] order = new int [count];
2731                 if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
2732                 index [0] = 0;
2733                 boolean quit = false;
2734                 while (index [0] < count && !quit) {
2735                         long hFont = item [0].fontHandle (order [index [0]]);
2736                         if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
2737                         cellRect [0] = item [0].getBounds (order [index [0]], true, false, true, false, true, hDC);
2738                         if (cellRect [0].left > rect.right) {
2739                                 quit = true;
2740                         } else {
2741                                 cellRect [0].right = Math.min (cellRect [0].right, rect.right);
2742                                 if (OS.PtInRect (cellRect [0], pt)) {
2743                                         if (isCustomToolTip ()) {
2744                                                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, lpht.hItem, OS.TVIS_SELECTED);
2745                                                 int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0;
2746                                                 Event event = sendMeasureItemEvent (item [0], order [index [0]], hDC, detail);
2747                                                 if (isDisposed () || item [0].isDisposed ()) break;
2748                                                 Rectangle boundsInPixels = event.getBoundsInPixels();
2749                                                 itemRect [0] = new RECT ();
2750                                                 itemRect [0].left = boundsInPixels.x;
2751                                                 itemRect [0].right = boundsInPixels.x + boundsInPixels.width;
2752                                                 itemRect [0].top = boundsInPixels.y;
2753                                                 itemRect [0].bottom = boundsInPixels.y + boundsInPixels.height;
2754                                         } else {
2755                                                 itemRect [0] = item [0].getBounds (order [index [0]], true, false, false, false, false, hDC);
2756                                         }
2757                                         if (itemRect [0].right > cellRect [0].right) found = true;
2758                                         quit = true;
2759                                 }
2760                         }
2761                         if (hFont != -1) OS.SelectObject (hDC, hFont);
2762                         if (!found) index [0]++;
2763                 }
2764                 if (newFont != 0) OS.SelectObject (hDC, oldFont);
2765                 OS.ReleaseDC (handle, hDC);
2766         }
2767         return found;
2768 }
2769
2770 int findIndex (long hFirstItem, long hItem) {
2771         if (hFirstItem == 0) return -1;
2772         if (hFirstItem == hFirstIndexOf) {
2773                 if (hFirstIndexOf == hItem) {
2774                         hLastIndexOf = hFirstIndexOf;
2775                         return lastIndexOf = 0;
2776                 }
2777                 if (hLastIndexOf == hItem) return lastIndexOf;
2778                 long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2779                 if (hPrevItem == hItem) {
2780                         hLastIndexOf = hPrevItem;
2781                         return --lastIndexOf;
2782                 }
2783                 long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2784                 if (hNextItem == hItem) {
2785                         hLastIndexOf = hNextItem;
2786                         return ++lastIndexOf;
2787                 }
2788                 int previousIndex = lastIndexOf - 1;
2789                 while (hPrevItem != 0 && hPrevItem != hItem) {
2790                         hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2791                         --previousIndex;
2792                 }
2793                 if (hPrevItem == hItem) {
2794                         hLastIndexOf = hPrevItem;
2795                         return lastIndexOf = previousIndex;
2796                 }
2797                 int nextIndex = lastIndexOf + 1;
2798                 while (hNextItem != 0 && hNextItem != hItem) {
2799                         hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2800                         nextIndex++;
2801                 }
2802                 if (hNextItem == hItem) {
2803                         hLastIndexOf = hNextItem;
2804                         return lastIndexOf = nextIndex;
2805                 }
2806                 return -1;
2807         }
2808         int index = 0;
2809         long hNextItem = hFirstItem;
2810         while (hNextItem != 0 && hNextItem != hItem) {
2811                 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2812                 index++;
2813         }
2814         if (hNextItem == hItem) {
2815                 itemCount = -1;
2816                 hFirstIndexOf = hFirstItem;
2817                 hLastIndexOf = hNextItem;
2818                 return lastIndexOf = index;
2819         }
2820         return -1;
2821 }
2822
2823 @Override
2824 Widget findItem (long hItem) {
2825         return _getItem (hItem);
2826 }
2827
2828 long findItem (long hFirstItem, int index) {
2829         if (hFirstItem == 0) return 0;
2830         if (hFirstItem == hFirstIndexOf) {
2831                 if (index == 0) {
2832                         lastIndexOf = 0;
2833                         return hLastIndexOf = hFirstIndexOf;
2834                 }
2835                 if (lastIndexOf == index) return hLastIndexOf;
2836                 if (lastIndexOf - 1 == index) {
2837                         --lastIndexOf;
2838                         return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2839                 }
2840                 if (lastIndexOf + 1 == index) {
2841                         lastIndexOf++;
2842                         return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2843                 }
2844                 if (index < lastIndexOf) {
2845                         int previousIndex = lastIndexOf - 1;
2846                         long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2847                         while (hPrevItem != 0 && index < previousIndex) {
2848                                 hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2849                                 --previousIndex;
2850                         }
2851                         if (index == previousIndex) {
2852                                 lastIndexOf = previousIndex;
2853                                 return hLastIndexOf = hPrevItem;
2854                         }
2855                 } else {
2856                         int nextIndex = lastIndexOf + 1;
2857                         long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2858                         while (hNextItem != 0 && nextIndex < index) {
2859                                 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2860                                 nextIndex++;
2861                         }
2862                         if (index == nextIndex) {
2863                                 lastIndexOf = nextIndex;
2864                                 return hLastIndexOf = hNextItem;
2865                         }
2866                 }
2867                 return 0;
2868         }
2869         int nextIndex = 0;
2870         long hNextItem = hFirstItem;
2871         while (hNextItem != 0 && nextIndex < index) {
2872                 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2873                 nextIndex++;
2874         }
2875         if (index == nextIndex) {
2876                 itemCount = -1;
2877                 lastIndexOf = nextIndex;
2878                 hFirstIndexOf = hFirstItem;
2879                 return hLastIndexOf = hNextItem;
2880         }
2881         return 0;
2882 }
2883
2884 TreeItem getFocusItem () {
2885 //      checkWidget ();
2886         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2887         return hItem != 0 ? _getItem (hItem) : null;
2888 }
2889
2890 /**
2891  * Returns the width in points of a grid line.
2892  *
2893  * @return the width of a grid line in points
2894  *
2895  * @exception SWTException <ul>
2896  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2897  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2898  * </ul>
2899  *
2900  * @since 3.1
2901  */
2902 public int getGridLineWidth () {
2903         checkWidget ();
2904         return DPIUtil.autoScaleDown(getGridLineWidthInPixels ());
2905 }
2906
2907 int getGridLineWidthInPixels () {
2908         return GRID_WIDTH;
2909 }
2910
2911 /**
2912  * Returns the header background color.
2913  *
2914  * @return the receiver's header background color.
2915  *
2916  * @exception SWTException <ul>
2917  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2918  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2919  * </ul>
2920  * @since 3.106
2921  */
2922 public Color getHeaderBackground () {
2923         checkWidget ();
2924         return Color.win32_new (display, getHeaderBackgroundPixel());
2925 }
2926
2927 private int getHeaderBackgroundPixel() {
2928         return headerBackground != -1 ? headerBackground : defaultBackground();
2929 }
2930
2931 /**
2932  * Returns the header foreground color.
2933  *
2934  * @return the receiver's header foreground color.
2935  *
2936  * @exception SWTException <ul>
2937  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2938  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2939  * </ul>
2940  * @since 3.106
2941  */
2942 public Color getHeaderForeground () {
2943         checkWidget ();
2944         return Color.win32_new (display, getHeaderForegroundPixel());
2945 }
2946
2947 private int getHeaderForegroundPixel() {
2948         return headerForeground != -1 ? headerForeground : defaultForeground();
2949 }
2950
2951 /**
2952  * Returns the height of the receiver's header
2953  *
2954  * @return the height of the header or zero if the header is not visible
2955  *
2956  * @exception SWTException <ul>
2957  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2958  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2959  * </ul>
2960  *
2961  * @since 3.1
2962  */
2963 public int getHeaderHeight () {
2964         checkWidget ();
2965         return DPIUtil.autoScaleDown(getHeaderHeightInPixels ());
2966 }
2967
2968 int getHeaderHeightInPixels () {
2969         if (hwndHeader == 0) return 0;
2970         RECT rect = new RECT ();
2971         OS.GetWindowRect (hwndHeader, rect);
2972         return rect.bottom - rect.top;
2973 }
2974
2975 /**
2976  * Returns <code>true</code> if the receiver's header is visible,
2977  * and <code>false</code> otherwise.
2978  * <p>
2979  * If one of the receiver's ancestors is not visible or some
2980  * other condition makes the receiver not visible, this method
2981  * may still indicate that it is considered visible even though
2982  * it may not actually be showing.
2983  * </p>
2984  *
2985  * @return the receiver's header's visibility state
2986  *
2987  * @exception SWTException <ul>
2988  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2989  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2990  * </ul>
2991  *
2992  * @since 3.1
2993  */
2994 public boolean getHeaderVisible () {
2995         checkWidget ();
2996         if (hwndHeader == 0) return false;
2997         int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
2998         return (bits & OS.WS_VISIBLE) != 0;
2999 }
3000
3001 Point getImageSize () {
3002         if (imageList != null) return imageList.getImageSize ();
3003         return new Point (0, getItemHeightInPixels ());
3004 }
3005
3006 long getBottomItem () {
3007         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3008         if (hItem == 0) return 0;
3009         int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
3010         while (index <= count) {
3011                 long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3012                 if (hNextItem == 0) return hItem;
3013                 hItem = hNextItem;
3014                 index++;
3015         }
3016         return hItem;
3017 }
3018
3019 /**
3020  * Returns the column at the given, zero-relative index in the
3021  * receiver. Throws an exception if the index is out of range.
3022  * Columns are returned in the order that they were created.
3023  * If no <code>TreeColumn</code>s were created by the programmer,
3024  * this method will throw <code>ERROR_INVALID_RANGE</code> despite
3025  * the fact that a single column of data may be visible in the tree.
3026  * This occurs when the programmer uses the tree like a list, adding
3027  * items but never creating a column.
3028  *
3029  * @param index the index of the column to return
3030  * @return the column at the given index
3031  *
3032  * @exception IllegalArgumentException <ul>
3033  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
3034  * </ul>
3035  * @exception SWTException <ul>
3036  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3037  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3038  * </ul>
3039  *
3040  * @see Tree#getColumnOrder()
3041  * @see Tree#setColumnOrder(int[])
3042  * @see TreeColumn#getMoveable()
3043  * @see TreeColumn#setMoveable(boolean)
3044  * @see SWT#Move
3045  *
3046  * @since 3.1
3047  */
3048 public TreeColumn getColumn (int index) {
3049         checkWidget ();
3050         if (!(0 <= index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
3051         return columns [index];
3052 }
3053
3054 /**
3055  * Returns the number of columns contained in the receiver.
3056  * If no <code>TreeColumn</code>s were created by the programmer,
3057  * this value is zero, despite the fact that visually, one column
3058  * of items may be visible. This occurs when the programmer uses
3059  * the tree like a list, adding items but never creating a column.
3060  *
3061  * @return the number of columns
3062  *
3063  * @exception SWTException <ul>
3064  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3065  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3066  * </ul>
3067  *
3068  * @since 3.1
3069  */
3070 public int getColumnCount () {
3071         checkWidget ();
3072         return columnCount;
3073 }
3074
3075 /**
3076  * Returns an array of zero-relative integers that map
3077  * the creation order of the receiver's items to the
3078  * order in which they are currently being displayed.
3079  * <p>
3080  * Specifically, the indices of the returned array represent
3081  * the current visual order of the items, and the contents
3082  * of the array represent the creation order of the items.
3083  * </p><p>
3084  * Note: This is not the actual structure used by the receiver
3085  * to maintain its list of items, so modifying the array will
3086  * not affect the receiver.
3087  * </p>
3088  *
3089  * @return the current visual order of the receiver's items
3090  *
3091  * @exception SWTException <ul>
3092  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3093  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3094  * </ul>
3095  *
3096  * @see Tree#setColumnOrder(int[])
3097  * @see TreeColumn#getMoveable()
3098  * @see TreeColumn#setMoveable(boolean)
3099  * @see SWT#Move
3100  *
3101  * @since 3.2
3102  */
3103 public int[] getColumnOrder () {
3104         checkWidget ();
3105         if (columnCount == 0) return new int [0];
3106         int [] order = new int [columnCount];
3107         OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
3108         return order;
3109 }
3110
3111 /**
3112  * Returns an array of <code>TreeColumn</code>s which are the
3113  * columns in the receiver. Columns are returned in the order
3114  * that they were created.  If no <code>TreeColumn</code>s were
3115  * created by the programmer, the array is empty, despite the fact
3116  * that visually, one column of items may be visible. This occurs
3117  * when the programmer uses the tree like a list, adding items but
3118  * never creating a column.
3119  * <p>
3120  * Note: This is not the actual structure used by the receiver
3121  * to maintain its list of items, so modifying the array will
3122  * not affect the receiver.
3123  * </p>
3124  *
3125  * @return the items in the receiver
3126  *
3127  * @exception SWTException <ul>
3128  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3129  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3130  * </ul>
3131  *
3132  * @see Tree#getColumnOrder()
3133  * @see Tree#setColumnOrder(int[])
3134  * @see TreeColumn#getMoveable()
3135  * @see TreeColumn#setMoveable(boolean)
3136  * @see SWT#Move
3137  *
3138  * @since 3.1
3139  */
3140 public TreeColumn [] getColumns () {
3141         checkWidget ();
3142         TreeColumn [] result = new TreeColumn [columnCount];
3143         System.arraycopy (columns, 0, result, 0, columnCount);
3144         return result;
3145 }
3146
3147 /**
3148  * Returns the item at the given, zero-relative index in the
3149  * receiver. Throws an exception if the index is out of range.
3150  *
3151  * @param index the index of the item to return
3152  * @return the item at the given index
3153  *
3154  * @exception IllegalArgumentException <ul>
3155  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
3156  * </ul>
3157  * @exception SWTException <ul>
3158  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3159  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3160  * </ul>
3161  *
3162  * @since 3.1
3163  */
3164 public TreeItem getItem (int index) {
3165         checkWidget ();
3166         if (index < 0) error (SWT.ERROR_INVALID_RANGE);
3167         long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3168         if (hFirstItem == 0) error (SWT.ERROR_INVALID_RANGE);
3169         long hItem = findItem (hFirstItem, index);
3170         if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
3171         return _getItem (hItem);
3172 }
3173
3174 TreeItem getItem (NMTVCUSTOMDRAW nmcd) {
3175         /*
3176         * Bug in Windows.  If the lParam field of TVITEM
3177         * is changed during custom draw using TVM_SETITEM,
3178         * the lItemlParam field of the NMTVCUSTOMDRAW struct
3179         * is not updated until the next custom draw.  The
3180         * fix is to query the field from the item instead
3181         * of using the struct.
3182         */
3183         int id = (int)nmcd.lItemlParam;
3184         if ((style & SWT.VIRTUAL) != 0) {
3185                 if (id == -1) {
3186                         TVITEM tvItem = new TVITEM ();
3187                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3188                         tvItem.hItem = nmcd.dwItemSpec;
3189                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3190                         id = (int)tvItem.lParam;
3191                 }
3192         }
3193         return _getItem (nmcd.dwItemSpec, id);
3194 }
3195
3196 /**
3197  * Returns the item at the given point in the receiver
3198  * or null if no such item exists. The point is in the
3199  * coordinate system of the receiver.
3200  * <p>
3201  * The item that is returned represents an item that could be selected by the user.
3202  * For example, if selection only occurs in items in the first column, then null is
3203  * returned if the point is outside of the item.
3204  * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
3205  * determines the extent of the selection.
3206  * </p>
3207  *
3208  * @param point the point used to locate the item
3209  * @return the item at the given point, or null if the point is not in a selectable item
3210  *
3211  * @exception IllegalArgumentException <ul>
3212  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
3213  * </ul>
3214  * @exception SWTException <ul>
3215  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3216  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3217  * </ul>
3218  */
3219 public TreeItem getItem (Point point) {
3220         checkWidget ();
3221         if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
3222         return getItemInPixels(DPIUtil.autoScaleUp(point));
3223 }
3224
3225 TreeItem getItemInPixels (Point point) {
3226         TVHITTESTINFO lpht = new TVHITTESTINFO ();
3227         lpht.x = point.x;
3228         lpht.y = point.y;
3229         OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
3230         if (lpht.hItem != 0) {
3231                 int flags = OS.TVHT_ONITEM;
3232                 if ((style & SWT.FULL_SELECTION) != 0) {
3233                         flags |= OS.TVHT_ONITEMRIGHT | OS.TVHT_ONITEMINDENT;
3234                 } else {
3235                         if (hooks (SWT.MeasureItem)) {
3236                                 lpht.flags &= ~(OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL);
3237                                 if (hitTestSelection (lpht.hItem, lpht.x, lpht.y)) {
3238                                         lpht.flags |= OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
3239                                 }
3240                         }
3241                 }
3242                 if ((lpht.flags & flags) != 0) return _getItem (lpht.hItem);
3243         }
3244         return null;
3245 }
3246
3247 /**
3248  * Returns the number of items contained in the receiver
3249  * that are direct item children of the receiver.  The
3250  * number that is returned is the number of roots in the
3251  * tree.
3252  *
3253  * @return the number of items
3254  *
3255  * @exception SWTException <ul>
3256  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3257  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3258  * </ul>
3259  */
3260 public int getItemCount () {
3261         checkWidget ();
3262         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3263         if (hItem == 0) return 0;
3264         return getItemCount (hItem);
3265 }
3266
3267 int getItemCount (long hItem) {
3268         int count = 0;
3269         long hFirstItem = hItem;
3270         if (hItem == hFirstIndexOf) {
3271                 if (itemCount != -1) return itemCount;
3272                 hFirstItem = hLastIndexOf;
3273                 count = lastIndexOf;
3274         }
3275         while (hFirstItem != 0) {
3276                 hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hFirstItem);
3277                 count++;
3278         }
3279         if (hItem == hFirstIndexOf) itemCount = count;
3280         return count;
3281 }
3282
3283 /**
3284  * Returns the height of the area which would be used to
3285  * display <em>one</em> of the items in the tree.
3286  *
3287  * @return the height of one item
3288  *
3289  * @exception SWTException <ul>
3290  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3291  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3292  * </ul>
3293  */
3294 public int getItemHeight () {
3295         checkWidget ();
3296         return DPIUtil.autoScaleDown(getItemHeightInPixels());
3297 }
3298
3299 int getItemHeightInPixels () {
3300         return (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
3301 }
3302
3303 /**
3304  * Returns a (possibly empty) array of items contained in the
3305  * receiver that are direct item children of the receiver.  These
3306  * are the roots of the tree.
3307  * <p>
3308  * Note: This is not the actual structure used by the receiver
3309  * to maintain its list of items, so modifying the array will
3310  * not affect the receiver.
3311  * </p>
3312  *
3313  * @return the items
3314  *
3315  * @exception SWTException <ul>
3316  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3317  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3318  * </ul>
3319  */
3320 public TreeItem [] getItems () {
3321         checkWidget ();
3322         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3323         if (hItem == 0) return new TreeItem [0];
3324         return getItems (hItem);
3325 }
3326
3327 TreeItem [] getItems (long hTreeItem) {
3328         int count = 0;
3329         long hItem = hTreeItem;
3330         while (hItem != 0) {
3331                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3332                 count++;
3333         }
3334         int index = 0;
3335         TreeItem [] result = new TreeItem [count];
3336         TVITEM tvItem = new TVITEM ();
3337         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3338         tvItem.hItem = hTreeItem;
3339         /*
3340         * Feature in Windows.  In some cases an expand or collapse message
3341         * can occur from within TVM_DELETEITEM.  When this happens, the item
3342         * being destroyed has been removed from the list of items but has not
3343         * been deleted from the tree.  The fix is to check for null items and
3344         * remove them from the list.
3345         */
3346         while (tvItem.hItem != 0) {
3347                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3348                 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
3349                 if (item != null) result [index++] = item;
3350                 tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem);
3351         }
3352         if (index != count) {
3353                 TreeItem [] newResult = new TreeItem [index];
3354                 System.arraycopy (result, 0, newResult, 0, index);
3355                 result = newResult;
3356         }
3357         return result;
3358 }
3359
3360 /**
3361  * Returns <code>true</code> if the receiver's lines are visible,
3362  * and <code>false</code> otherwise. Note that some platforms draw
3363  * grid lines while others may draw alternating row colors.
3364  * <p>
3365  * If one of the receiver's ancestors is not visible or some
3366  * other condition makes the receiver not visible, this method
3367  * may still indicate that it is considered visible even though
3368  * it may not actually be showing.
3369  * </p>
3370  *
3371  * @return the visibility state of the lines
3372  *
3373  * @exception SWTException <ul>
3374  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3375  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3376  * </ul>
3377  *
3378  * @since 3.1
3379  */
3380 public boolean getLinesVisible () {
3381         checkWidget ();
3382         return linesVisible;
3383 }
3384
3385 long getNextSelection (long hItem) {
3386         while (hItem != 0) {
3387                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3388                 if ((state & OS.TVIS_SELECTED) != 0) return hItem;
3389                 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3390                 long hSelected = getNextSelection (hFirstItem);
3391                 if (hSelected != 0) return hSelected;
3392                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3393         }
3394         return 0;
3395 }
3396
3397 /**
3398  * Returns the receiver's parent item, which must be a
3399  * <code>TreeItem</code> or null when the receiver is a
3400  * root.
3401  *
3402  * @return the receiver's parent item
3403  *
3404  * @exception SWTException <ul>
3405  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3406  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3407  * </ul>
3408  */
3409 public TreeItem getParentItem () {
3410         checkWidget ();
3411         return null;
3412 }
3413
3414 int getSelection (long hItem, TVITEM tvItem, TreeItem [] selection, int index, int count, boolean bigSelection, boolean all) {
3415         while (hItem != 0) {
3416                 boolean expanded = true;
3417                 if (bigSelection) {
3418                         tvItem.hItem = hItem;
3419                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3420                         if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
3421                                 if (selection != null && index < selection.length) {
3422                                         TreeItem item = _getItem (hItem, (int)tvItem.lParam);
3423                                         if (item != null) {
3424                                                 selection [index] = item;
3425                                         } else {
3426                                                 index--;
3427                                         }
3428                                 }
3429                                 index++;
3430                         }
3431                         expanded = (tvItem.state & OS.TVIS_EXPANDED) != 0;
3432                 } else {
3433                         int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED | OS.TVIS_EXPANDED);
3434                         if ((state & OS.TVIS_SELECTED) != 0) {
3435                                 if (tvItem != null && selection != null && index < selection.length) {
3436                                         tvItem.hItem = hItem;
3437                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3438                                         TreeItem item = _getItem (hItem, (int)tvItem.lParam);
3439                                         if (item != null) {
3440                                                 selection [index] = item;
3441                                         } else {
3442                                                 index--;
3443                                         }
3444                                 }
3445                                 index++;
3446                         }
3447                         expanded = (state & OS.TVIS_EXPANDED) != 0;
3448                 }
3449                 if (index == count) break;
3450                 if (all) {
3451                         if (expanded) {
3452                                 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3453                                 if ((index = getSelection (hFirstItem, tvItem, selection, index, count, bigSelection, all)) == count) {
3454                                         break;
3455                                 }
3456                         }
3457                         hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3458                 } else {
3459                         hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3460                 }
3461         }
3462         return index;
3463 }
3464
3465 /**
3466  * Returns an array of <code>TreeItem</code>s that are currently
3467  * selected in the receiver. The order of the items is unspecified.
3468  * An empty array indicates that no items are selected.
3469  * <p>
3470  * Note: This is not the actual structure used by the receiver
3471  * to maintain its selection, so modifying the array will
3472  * not affect the receiver.
3473  * </p>
3474  * @return an array representing the selection
3475  *
3476  * @exception SWTException <ul>
3477  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3478  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3479  * </ul>
3480  */
3481 public TreeItem [] getSelection () {
3482         checkWidget ();
3483         if ((style & SWT.SINGLE) != 0) {
3484                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3485                 if (hItem == 0) return new TreeItem [0];
3486                 TVITEM tvItem = new TVITEM ();
3487                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3488                 tvItem.hItem = hItem;
3489                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3490                 if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0];
3491                 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
3492                 if (item == null) return new TreeItem [0];
3493                 return new TreeItem [] {item};
3494         }
3495         int count = 0;
3496         TreeItem [] guess = new TreeItem [(style & SWT.VIRTUAL) != 0 ? 8 : 1];
3497         long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
3498         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3499         if ((style & SWT.VIRTUAL) != 0) {
3500                 TVITEM tvItem = new TVITEM ();
3501                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3502                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3503                 count = getSelection (hItem, tvItem, guess, 0, -1, false, true);
3504         } else {
3505                 for (int i=0; i<items.length; i++) {
3506                         TreeItem item = items [i];
3507                         if (item != null) {
3508                                 long hItem = item.handle;
3509                                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3510                                 if ((state & OS.TVIS_SELECTED) != 0) {
3511                                         if (count < guess.length) guess [count] = item;
3512                                         count++;
3513                                 }
3514                         }
3515                 }
3516         }
3517         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3518         if (count == 0) return new TreeItem [0];
3519         if (count == guess.length) return guess;
3520         TreeItem [] result = new TreeItem [count];
3521         if (count < guess.length) {
3522                 System.arraycopy (guess, 0, result, 0, count);
3523                 return result;
3524         }
3525         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3526         TVITEM tvItem = new TVITEM ();
3527         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3528         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3529         int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
3530         boolean bigSelection = result.length > itemCount / 2;
3531         if (count != getSelection (hItem, tvItem, result, 0, count, bigSelection, false)) {
3532                 count = getSelection (hItem, tvItem, result, 0, count, bigSelection, true);
3533         }
3534         if (count != result.length) {
3535                 TreeItem[] newResult = new TreeItem[count];
3536                 System.arraycopy (result, 0, newResult, 0, count);
3537                 result = newResult;
3538         }
3539         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3540         return result;
3541 }
3542
3543 /**
3544  * Returns the number of selected items contained in the receiver.
3545  *
3546  * @return the number of selected items
3547  *
3548  * @exception SWTException <ul>
3549  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3550  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3551  * </ul>
3552  */
3553 public int getSelectionCount () {
3554         checkWidget ();
3555         if ((style & SWT.SINGLE) != 0) {
3556                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3557                 if (hItem == 0) return 0;
3558                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3559                 return (state & OS.TVIS_SELECTED) == 0 ? 0 : 1;
3560         }
3561         int count = 0;
3562         long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
3563         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3564         if ((style & SWT.VIRTUAL) != 0) {
3565                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3566                 count = getSelection (hItem, null, null, 0, -1, false, true);
3567         } else {
3568                 for (int i=0; i<items.length; i++) {
3569                         TreeItem item = items [i];
3570                         if (item != null) {
3571                                 long hItem = item.handle;
3572                                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3573                                 if ((state & OS.TVIS_SELECTED) != 0) count++;
3574                         }
3575                 }
3576         }
3577         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3578         return count;
3579 }
3580
3581 /**
3582  * Returns the column which shows the sort indicator for
3583  * the receiver. The value may be null if no column shows
3584  * the sort indicator.
3585  *
3586  * @return the sort indicator
3587  *
3588  * @exception SWTException <ul>
3589  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3590  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3591  * </ul>
3592  *
3593  * @see #setSortColumn(TreeColumn)
3594  *
3595  * @since 3.2
3596  */
3597 public TreeColumn getSortColumn () {
3598         checkWidget ();
3599         return sortColumn;
3600 }
3601
3602 int getSortColumnPixel () {
3603         int pixel = OS.IsWindowEnabled (handle) || hasCustomBackground() ? getBackgroundPixel () : OS.GetSysColor (OS.COLOR_3DFACE);
3604         return getSlightlyDifferentBackgroundColor(pixel);
3605 }
3606
3607 /**
3608  * Returns the direction of the sort indicator for the receiver.
3609  * The value will be one of <code>UP</code>, <code>DOWN</code>
3610  * or <code>NONE</code>.
3611  *
3612  * @return the sort direction
3613  *
3614  * @exception SWTException <ul>
3615  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3616  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3617  * </ul>
3618  *
3619  * @see #setSortDirection(int)
3620  *
3621  * @since 3.2
3622  */
3623 public int getSortDirection () {
3624         checkWidget ();
3625         return sortDirection;
3626 }
3627
3628 /**
3629  * Returns the item which is currently at the top of the receiver.
3630  * This item can change when items are expanded, collapsed, scrolled
3631  * or new items are added or removed.
3632  *
3633  * @return the item at the top of the receiver
3634  *
3635  * @exception SWTException <ul>
3636  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3637  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3638  * </ul>
3639  *
3640  * @since 2.1
3641  */
3642 public TreeItem getTopItem () {
3643         checkWidget ();
3644         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3645         return hItem != 0 ? _getItem (hItem) : null;
3646 }
3647
3648 boolean hitTestSelection (long hItem, int x, int y) {
3649         if (hItem == 0) return false;
3650         TreeItem item = _getItem (hItem);
3651         if (item == null) return false;
3652         if (!hooks (SWT.MeasureItem)) return false;
3653         boolean result = false;
3654
3655         //BUG? - moved columns, only hittest first column
3656         //BUG? - check drag detect
3657         int [] order = new int [1], index = new int [1];
3658
3659         long hDC = OS.GetDC (handle);
3660         long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
3661         if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
3662         long hFont = item.fontHandle (order [index [0]]);
3663         if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
3664         int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3665         int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0;
3666         Event event = sendMeasureItemEvent (item, order [index [0]], hDC, detail);
3667         if (event.getBoundsInPixels ().contains (x, y)) result = true;
3668         if (newFont != 0) OS.SelectObject (hDC, oldFont);
3669         OS.ReleaseDC (handle, hDC);
3670 //      if (isDisposed () || item.isDisposed ()) return false;
3671         return result;
3672 }
3673
3674 int imageIndex (Image image, int index) {
3675         if (image == null) return OS.I_IMAGENONE;
3676         if (imageList == null) {
3677                 Rectangle bounds = image.getBoundsInPixels ();
3678                 imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3679         }
3680         int imageIndex = imageList.indexOf (image);
3681         if (imageIndex == -1) imageIndex = imageList.add (image);
3682         if (hwndHeader == 0 || OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) == index) {
3683                 /*
3684                 * Feature in Windows.  When setting the same image list multiple
3685                 * times, Windows does work making this operation slow.  The fix
3686                 * is to test for the same image list before setting the new one.
3687                 */
3688                 long hImageList = imageList.getHandle ();
3689                 long hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
3690                 if (hOldImageList != hImageList) {
3691                         OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
3692                         updateScrollBar ();
3693                 }
3694         }
3695         return imageIndex;
3696 }
3697
3698 int imageIndexHeader (Image image) {
3699         if (image == null) return OS.I_IMAGENONE;
3700         if (headerImageList == null) {
3701                 Rectangle bounds = image.getBoundsInPixels ();
3702                 headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3703                 int index = headerImageList.indexOf (image);
3704                 if (index == -1) index = headerImageList.add (image);
3705                 long hImageList = headerImageList.getHandle ();
3706                 if (hwndHeader != 0) {
3707                         OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageList);
3708                 }
3709                 updateScrollBar ();
3710                 return index;
3711         }
3712         int index = headerImageList.indexOf (image);
3713         if (index != -1) return index;
3714         return headerImageList.add (image);
3715 }
3716
3717 /**
3718  * Searches the receiver's list starting at the first column
3719  * (index 0) until a column is found that is equal to the
3720  * argument, and returns the index of that column. If no column
3721  * is found, returns -1.
3722  *
3723  * @param column the search column
3724  * @return the index of the column
3725  *
3726  * @exception IllegalArgumentException <ul>
3727  *    <li>ERROR_NULL_ARGUMENT - if the column is null</li>
3728  * </ul>
3729  * @exception SWTException <ul>
3730  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3731  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3732  * </ul>
3733  *
3734  * @since 3.1
3735  */
3736 public int indexOf (TreeColumn column) {
3737         checkWidget ();
3738         if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
3739         if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3740         for (int i=0; i<columnCount; i++) {
3741                 if (columns [i] == column) return i;
3742         }
3743         return -1;
3744 }
3745
3746 /**
3747  * Searches the receiver's list starting at the first item
3748  * (index 0) until an item is found that is equal to the
3749  * argument, and returns the index of that item. If no item
3750  * is found, returns -1.
3751  *
3752  * @param item the search item
3753  * @return the index of the item
3754  *
3755  * @exception IllegalArgumentException <ul>
3756  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
3757  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
3758  * </ul>
3759  * @exception SWTException <ul>
3760  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3761  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3762  * </ul>
3763  *
3764  * @since 3.1
3765  */
3766 public int indexOf (TreeItem item) {
3767         checkWidget ();
3768         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
3769         if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3770         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3771         return hItem == 0 ? -1 : findIndex (hItem, item.handle);
3772 }
3773
3774 boolean isCustomToolTip () {
3775         return hooks (SWT.MeasureItem);
3776 }
3777
3778 boolean isItemSelected (NMTVCUSTOMDRAW nmcd) {
3779         boolean selected = false;
3780         if (OS.IsWindowEnabled (handle)) {
3781                 TVITEM tvItem = new TVITEM ();
3782                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
3783                 tvItem.hItem = nmcd.dwItemSpec;
3784                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3785                 if ((tvItem.state & (OS.TVIS_SELECTED | OS.TVIS_DROPHILITED)) != 0) {
3786                         selected = true;
3787                         /*
3788                         * Feature in Windows.  When the mouse is pressed and the
3789                         * selection is first drawn for a tree, the previously
3790                         * selected item is redrawn but the the TVIS_SELECTED bits
3791                         * are not cleared.  When the user moves the mouse slightly
3792                         * and a drag and drop operation is not started, the item is
3793                         * drawn again and this time with TVIS_SELECTED is cleared.
3794                         * This means that an item that contains colored cells will
3795                         * not draw with the correct background until the mouse is
3796                         * moved.  The fix is to test for the selection colors and
3797                         * guess that the item is not selected.
3798                         *
3799                         * NOTE: This code does not work when the foreground and
3800                         * background of the tree are set to the selection colors
3801                         * but this does not happen in a regular application.
3802                         */
3803                         if (handle == OS.GetFocus ()) {
3804                                 if (OS.GetTextColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3805                                         selected = false;
3806                                 } else {
3807                                         if (OS.GetBkColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3808                                                 selected = false;
3809                                         }
3810                                 }
3811                         }
3812                 } else {
3813                         if (nmcd.dwDrawStage == OS.CDDS_ITEMPOSTPAINT) {
3814                                 /*
3815                                 * Feature in Windows.  When the mouse is pressed and the
3816                                 * selection is first drawn for a tree, the item is drawn
3817                                 * selected, but the TVIS_SELECTED bits for the item are
3818                                 * not set.  When the user moves the mouse slightly and
3819                                 * a drag and drop operation is not started, the item is
3820                                 * drawn again and this time TVIS_SELECTED is set.  This
3821                                 * means that an item that is in a tree that has the style
3822                                 * TVS_FULLROWSELECT and that also contains colored cells
3823                                 * will not draw the entire row selected until the user
3824                                 * moves the mouse.  The fix is to test for the selection
3825                                 * colors and guess that the item is selected.
3826                                 *
3827                                 * NOTE: This code does not work when the foreground and
3828                                 * background of the tree are set to the selection colors
3829                                 * but this does not happen in a regular application.
3830                                 */
3831                                 if (OS.GetTextColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3832                                         if (OS.GetBkColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3833                                                 selected = true;
3834                                         }
3835                                 }
3836                         }
3837                 }
3838         }
3839         return selected;
3840 }
3841
3842 void redrawSelection () {
3843         if ((style & SWT.SINGLE) != 0) {
3844                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3845                 if (hItem != 0) {
3846                         RECT rect = new RECT ();
3847                         if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
3848                                 OS.InvalidateRect (handle, rect, true);
3849                         }
3850                 }
3851         } else {
3852                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3853                 if (hItem != 0) {
3854                         RECT rect = new RECT ();
3855                         int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
3856                         while (index <= count && hItem != 0) {
3857                                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3858                                 if ((state & OS.TVIS_SELECTED) != 0) {
3859                                         if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
3860                                                 OS.InvalidateRect (handle, rect, true);
3861                                         }
3862                                 }
3863                                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3864                                 index++;
3865                         }
3866                 }
3867         }
3868 }
3869
3870 @Override
3871 void register () {
3872         super.register ();
3873         if (hwndParent != 0) display.addControl (hwndParent, this);
3874         if (hwndHeader != 0) display.addControl (hwndHeader, this);
3875 }
3876
3877 void releaseItem (long hItem, TVITEM tvItem, boolean release) {
3878         if (hItem == hAnchor) hAnchor = 0;
3879         if (hItem == hInsert) hInsert = 0;
3880         tvItem.hItem = hItem;
3881         if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
3882                 if (tvItem.lParam != -1) {
3883                         if (tvItem.lParam < lastID) lastID = (int)tvItem.lParam;
3884                         if (release) {
3885                                 TreeItem item = items [(int)tvItem.lParam];
3886                                 if (item != null) item.release (false);
3887                         }
3888                         items [(int)tvItem.lParam] = null;
3889                 }
3890         }
3891 }
3892
3893 void releaseItems (long hItem, TVITEM tvItem) {
3894         hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3895         while (hItem != 0) {
3896                 releaseItems (hItem, tvItem);
3897                 releaseItem (hItem, tvItem, true);
3898                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3899         }
3900 }
3901
3902 @Override
3903 void releaseHandle () {
3904         super.releaseHandle ();
3905         hwndParent = hwndHeader = 0;
3906 }
3907
3908 @Override
3909 void releaseChildren (boolean destroy) {
3910         if (items != null) {
3911                 for (int i=0; i<items.length; i++) {
3912                         TreeItem item = items [i];
3913                         if (item != null && !item.isDisposed ()) {
3914                                 item.release (false);
3915                         }
3916                 }
3917                 items = null;
3918         }
3919         if (columns != null) {
3920                 for (int i=0; i<columns.length; i++) {
3921                         TreeColumn column = columns [i];
3922                         if (column != null && !column.isDisposed ()) {
3923                                 column.release (false);
3924                         }
3925                 }
3926                 columns = null;
3927         }
3928         super.releaseChildren (destroy);
3929 }
3930
3931 @Override
3932 void releaseWidget () {
3933         super.releaseWidget ();
3934         /*
3935         * Feature in Windows.  For some reason, when TVM_GETIMAGELIST
3936         * or TVM_SETIMAGELIST is sent, the tree issues NM_CUSTOMDRAW
3937         * messages.  This behavior is unwanted when the tree is being
3938         * disposed.  The fix is to ignore NM_CUSTOMDRAW messages by
3939         * clearing the custom draw flag.
3940         *
3941         * NOTE: This only happens on Windows XP.
3942         */
3943         customDraw = false;
3944         if (imageList != null) {
3945                 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0);
3946                 display.releaseImageList (imageList);
3947         }
3948         if (headerImageList != null) {
3949                 if (hwndHeader != 0) {
3950                         OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, 0);
3951                 }
3952                 display.releaseImageList (headerImageList);
3953         }
3954         imageList = headerImageList = null;
3955         long hStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
3956         OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, 0);
3957         if (hStateList != 0) OS.ImageList_Destroy (hStateList);
3958         if (itemToolTipHandle != 0) OS.DestroyWindow (itemToolTipHandle);
3959         if (headerToolTipHandle != 0) OS.DestroyWindow (headerToolTipHandle);
3960         itemToolTipHandle = headerToolTipHandle = 0;
3961 }
3962
3963 /**
3964  * Removes all of the items from the receiver.
3965  *
3966  * @exception SWTException <ul>
3967  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3968  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3969  * </ul>
3970  */
3971 public void removeAll () {
3972         checkWidget ();
3973         hFirstIndexOf = hLastIndexOf = 0;
3974         itemCount = -1;
3975         for (int i=0; i<items.length; i++) {
3976                 TreeItem item = items [i];
3977                 if (item != null && !item.isDisposed ()) {
3978                         item.release (false);
3979                 }
3980         }
3981         ignoreDeselect = ignoreSelect = true;
3982         boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
3983         if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
3984         shrink = ignoreShrink = true;
3985         long result = OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, OS.TVI_ROOT);
3986         ignoreShrink = false;
3987         if (redraw) {
3988                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
3989                 OS.InvalidateRect (handle, null, true);
3990         }
3991         ignoreDeselect = ignoreSelect = false;
3992         if (result == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
3993         if (imageList != null) {
3994                 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
3995                 display.releaseImageList (imageList);
3996         }
3997         imageList = null;
3998         if (hwndParent == 0 && !linesVisible) {
3999                 if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
4000                         customDraw = false;
4001                 }
4002         }
4003         hAnchor = hInsert = hFirstIndexOf = hLastIndexOf = 0;
4004         itemCount = -1;
4005         items = new TreeItem [4];
4006         scrollWidth = 0;
4007         setScrollWidth ();
4008         updateScrollBar ();
4009 }
4010
4011 /**
4012  * Removes the listener from the collection of listeners who will
4013  * be notified when the user changes the receiver's selection.
4014  *
4015  * @param listener the listener which should no longer be notified
4016  *
4017  * @exception IllegalArgumentException <ul>
4018  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
4019  * </ul>
4020  * @exception SWTException <ul>
4021  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4022  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4023  * </ul>
4024  *
4025  * @see SelectionListener
4026  * @see #addSelectionListener
4027  */
4028 public void removeSelectionListener (SelectionListener listener) {
4029         checkWidget ();
4030         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
4031         eventTable.unhook (SWT.Selection, listener);
4032         eventTable.unhook (SWT.DefaultSelection, listener);
4033 }
4034
4035 /**
4036  * Removes the listener from the collection of listeners who will
4037  * be notified when items in the receiver are expanded or collapsed.
4038  *
4039  * @param listener the listener which should no longer be notified
4040  *
4041  * @exception IllegalArgumentException <ul>
4042  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
4043  * </ul>
4044  * @exception SWTException <ul>
4045  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4046  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4047  * </ul>
4048  *
4049  * @see TreeListener
4050  * @see #addTreeListener
4051  */
4052 public void removeTreeListener(TreeListener listener) {
4053         checkWidget ();
4054         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
4055         if (eventTable == null) return;
4056         eventTable.unhook (SWT.Expand, listener);
4057         eventTable.unhook (SWT.Collapse, listener);
4058 }
4059
4060 @Override
4061 void reskinChildren (int flags) {
4062         if (items != null) {
4063                 for (int i=0; i<items.length; i++) {
4064                         TreeItem item = items [i];
4065                         if (item != null) item.reskinChildren (flags);
4066                 }
4067         }
4068         if (columns != null) {
4069                 for (int i=0; i<columns.length; i++) {
4070                         TreeColumn column = columns [i];
4071                         if (column != null) column.reskinChildren (flags);
4072                 }
4073         }
4074         super.reskinChildren (flags);
4075 }
4076
4077
4078 /**
4079  * Display a mark indicating the point at which an item will be inserted.
4080  * The drop insert item has a visual hint to show where a dragged item
4081  * will be inserted when dropped on the tree.
4082  *
4083  * @param item the insert item.  Null will clear the insertion mark.
4084  * @param before true places the insert mark above 'item'. false places
4085  *      the insert mark below 'item'.
4086  *
4087  * @exception IllegalArgumentException <ul>
4088  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4089  * </ul>
4090  * @exception SWTException <ul>
4091  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4092  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4093  * </ul>
4094  */
4095 public void setInsertMark (TreeItem item, boolean before) {
4096         checkWidget ();
4097         long hItem = 0;
4098         if (item != null) {
4099                 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4100                 hItem = item.handle;
4101         }
4102         hInsert = hItem;
4103         insertAfter = !before;
4104         OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
4105 }
4106
4107 /**
4108  * Sets the number of root-level items contained in the receiver.
4109  *
4110  * @param count the number of items
4111  *
4112  * @exception SWTException <ul>
4113  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4114  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4115  * </ul>
4116  *
4117  * @since 3.2
4118  */
4119 public void setItemCount (int count) {
4120         checkWidget ();
4121         count = Math.max (0, count);
4122         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4123         setItemCount (count, OS.TVGN_ROOT, hItem);
4124 }
4125
4126 void setItemCount (int count, long hParent, long hItem) {
4127         boolean redraw = false;
4128         if (OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) == 0) {
4129                 redraw = getDrawing () && OS.IsWindowVisible (handle);
4130                 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4131         }
4132         int itemCount = 0;
4133         while (hItem != 0 && itemCount < count) {
4134                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4135                 itemCount++;
4136         }
4137         boolean expanded = false;
4138         TVITEM tvItem = new TVITEM ();
4139         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
4140         if (!redraw && (style & SWT.VIRTUAL) != 0) {
4141                 /*
4142                 * Bug in Windows.  Despite the fact that TVM_GETITEMSTATE claims
4143                 * to return only the bits specified by the stateMask, when called
4144                 * with TVIS_EXPANDED, the entire state is returned.  The fix is
4145                 * to explicitly check for the TVIS_EXPANDED bit.
4146                 */
4147                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hParent, OS.TVIS_EXPANDED);
4148                 expanded = (state & OS.TVIS_EXPANDED) != 0;
4149         }
4150         while (hItem != 0) {
4151                 tvItem.hItem = hItem;
4152                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4153                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4154                 TreeItem item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null;
4155                 if (item != null && !item.isDisposed ()) {
4156                         item.dispose ();
4157                 } else {
4158                         releaseItem (tvItem.hItem, tvItem, false);
4159                         destroyItem (null, tvItem.hItem);
4160                 }
4161         }
4162         if ((style & SWT.VIRTUAL) != 0) {
4163                 for (int i=itemCount; i<count; i++) {
4164                         if (expanded) ignoreShrink = true;
4165                         createItem (null, hParent, OS.TVI_LAST, 0);
4166                         if (expanded) ignoreShrink = false;
4167                 }
4168         } else {
4169                 shrink = true;
4170                 int extra = Math.max (4, (count + 3) / 4 * 4);
4171                 TreeItem [] newItems = new TreeItem [items.length + extra];
4172                 System.arraycopy (items, 0, newItems, 0, items.length);
4173                 items = newItems;
4174                 for (int i=itemCount; i<count; i++) {
4175                         new TreeItem (this, SWT.NONE, hParent, OS.TVI_LAST, 0);
4176                 }
4177         }
4178         if (redraw) {
4179                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4180                 OS.InvalidateRect (handle, null, true);
4181         }
4182 }
4183
4184 /**
4185  * Sets the height of the area which would be used to
4186  * display <em>one</em> of the items in the tree.
4187  *
4188  * @param itemHeight the height of one item
4189  *
4190  * @exception SWTException <ul>
4191  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4192  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4193  * </ul>
4194  *
4195  * @since 3.2
4196  */
4197 /*public*/ void setItemHeight (int itemHeight) {
4198         checkWidget ();
4199         if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT);
4200         OS.SendMessage (handle, OS.TVM_SETITEMHEIGHT, itemHeight, 0);
4201 }
4202
4203 /**
4204  * Marks the receiver's lines as visible if the argument is <code>true</code>,
4205  * and marks it invisible otherwise. Note that some platforms draw
4206  * grid lines while others may draw alternating row colors.
4207  * <p>
4208  * If one of the receiver's ancestors is not visible or some
4209  * other condition makes the receiver not visible, marking
4210  * it visible may not actually cause it to be displayed.
4211  * </p>
4212  *
4213  * @param show the new visibility state
4214  *
4215  * @exception SWTException <ul>
4216  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4217  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4218  * </ul>
4219  *
4220  * @since 3.1
4221  */
4222 public void setLinesVisible (boolean show) {
4223         checkWidget ();
4224         if (linesVisible == show) return;
4225         linesVisible = show;
4226         if (hwndParent == 0 && linesVisible) customDraw = true;
4227         OS.InvalidateRect (handle, null, true);
4228         if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
4229 }
4230
4231 @Override
4232 long scrolledHandle () {
4233         if (hwndHeader == 0) return handle;
4234         return columnCount == 0 && scrollWidth == 0 ? handle : hwndParent;
4235 }
4236
4237 void select (long hItem, TVITEM tvItem) {
4238         while (hItem != 0) {
4239                 tvItem.hItem = hItem;
4240                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4241                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_EXPANDED);
4242                 if ((state & OS.TVIS_EXPANDED) != 0) {
4243                         long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4244                         select (hFirstItem, tvItem);
4245                 }
4246
4247                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4248         }
4249 }
4250
4251 /**
4252  * Selects an item in the receiver.  If the item was already
4253  * selected, it remains selected.
4254  *
4255  * @param item the item to be selected
4256  *
4257  * @exception IllegalArgumentException <ul>
4258  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4259  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4260  * </ul>
4261  * @exception SWTException <ul>
4262  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4263  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4264  * </ul>
4265  *
4266  * @since 3.4
4267  */
4268 public void select (TreeItem item) {
4269         checkWidget ();
4270         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4271         if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
4272         if ((style & SWT.SINGLE) != 0) {
4273                 long hItem = item.handle;
4274                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
4275                 if ((state & OS.TVIS_SELECTED) != 0) return;
4276                 /*
4277                 * Feature in Windows.  When an item is selected with
4278                 * TVM_SELECTITEM and TVGN_CARET, the tree expands and
4279                 * scrolls to show the new selected item.  Unfortunately,
4280                 * there is no other way in Windows to set the focus
4281                 * and select an item.  The fix is to save the current
4282                 * scroll bar positions, turn off redraw, select the item,
4283                 * then scroll back to the original position and redraw
4284                 * the entire tree.
4285                 */
4286                 SCROLLINFO hInfo = null;
4287                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
4288                 if ((bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) {
4289                         hInfo = new SCROLLINFO ();
4290                         hInfo.cbSize = SCROLLINFO.sizeof;
4291                         hInfo.fMask = OS.SIF_ALL;
4292                         OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo);
4293                 }
4294                 SCROLLINFO vInfo = new SCROLLINFO ();
4295                 vInfo.cbSize = SCROLLINFO.sizeof;
4296                 vInfo.fMask = OS.SIF_ALL;
4297                 OS.GetScrollInfo (handle, OS.SB_VERT, vInfo);
4298                 boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
4299                 if (redraw) {
4300                         OS.UpdateWindow (handle);
4301                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4302                 }
4303                 setSelection (item);
4304                 if (hInfo != null) {
4305                         long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos);
4306                         OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0);
4307                 }
4308                 /*
4309                 * Feature in Windows.  It seems that Vista does not
4310                 * use wParam to get the new position when WM_VSCROLL
4311                 * is sent with SB_THUMBPOSITION.  The fix is to use
4312                 * SetScrollInfo() to move the scroll bar thumb before
4313                 * calling WM_VSCROLL.
4314                 *
4315                 * NOTE: This code is only necessary on Windows Vista.
4316                 */
4317                 OS.SetScrollInfo (handle, OS.SB_VERT, vInfo, true);
4318                 long vThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, vInfo.nPos);
4319                 OS.SendMessage (handle, OS.WM_VSCROLL, vThumb, 0);
4320                 if (redraw) {
4321                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4322                         OS.InvalidateRect (handle, null, true);
4323                         if ((style & SWT.DOUBLE_BUFFERED) == 0) {
4324                                 int oldStyle = style;
4325                                 style |= SWT.DOUBLE_BUFFERED;
4326                                 OS.UpdateWindow (handle);
4327                                 style = oldStyle;
4328                         }
4329                 }
4330                 return;
4331         }
4332         expandToItem(item);
4333         TVITEM tvItem = new TVITEM ();
4334         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4335         tvItem.stateMask = OS.TVIS_SELECTED;
4336         tvItem.state = OS.TVIS_SELECTED;
4337         tvItem.hItem = item.handle;
4338         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4339 }
4340
4341 /**
4342  * Selects all of the items in the receiver.
4343  * <p>
4344  * If the receiver is single-select, do nothing.
4345  * </p>
4346  *
4347  * @exception SWTException <ul>
4348  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4349  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4350  * </ul>
4351  */
4352 public void selectAll () {
4353         checkWidget ();
4354         if ((style & SWT.SINGLE) != 0) return;
4355         TVITEM tvItem = new TVITEM ();
4356         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4357         tvItem.state = OS.TVIS_SELECTED;
4358         tvItem.stateMask = OS.TVIS_SELECTED;
4359         long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
4360         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
4361         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4362         select (hItem, tvItem);
4363         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
4364 }
4365
4366 Event sendEraseItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT cellRect) {
4367         int nSavedDC = OS.SaveDC (nmcd.hdc);
4368         RECT insetRect = toolTipInset (cellRect);
4369         OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
4370         GCData data = new GCData ();
4371         data.device = display;
4372         data.foreground = OS.GetTextColor (nmcd.hdc);
4373         data.background = OS.GetBkColor (nmcd.hdc);
4374         data.font = item.getFont (column);
4375         data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
4376         GC gc = GC.win32_new (nmcd.hdc, data);
4377         Event event = new Event ();
4378         event.item = item;
4379         event.index = column;
4380         event.gc = gc;
4381         event.detail |= SWT.FOREGROUND;
4382         event.setBoundsInPixels(new Rectangle(cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top));
4383         //gc.setClipping (event.x, event.y, event.width, event.height);
4384         sendEvent (SWT.EraseItem, event);
4385         event.gc = null;
4386         //int newTextClr = data.foreground;
4387         gc.dispose ();
4388         OS.RestoreDC (nmcd.hdc, nSavedDC);
4389         return event;
4390 }
4391
4392 Event sendMeasureItemEvent (TreeItem item, int index, long hDC, int detail) {
4393         RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
4394         int nSavedDC = OS.SaveDC (hDC);
4395         GCData data = new GCData ();
4396         data.device = display;
4397         data.font = item.getFont (index);
4398         GC gc = GC.win32_new (hDC, data);
4399         Event event = new Event ();
4400         event.item = item;
4401         event.gc = gc;
4402         event.index = index;
4403         event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
4404         event.detail = detail;
4405         sendEvent (SWT.MeasureItem, event);
4406         event.gc = null;
4407         gc.dispose ();
4408         OS.RestoreDC (hDC, nSavedDC);
4409         if (isDisposed () || item.isDisposed ()) return null;
4410         Rectangle rect = event.getBoundsInPixels ();
4411         if (hwndHeader != 0) {
4412                 if (columnCount == 0) {
4413                         if (rect.x + rect.width > scrollWidth) {
4414                                 setScrollWidth (scrollWidth = rect.x + rect.width);
4415                         }
4416                 }
4417         }
4418         if (rect.height > getItemHeightInPixels ()) setItemHeight (rect.height);
4419         return event;
4420 }
4421
4422 Event sendPaintItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT itemRect) {
4423         int nSavedDC = OS.SaveDC (nmcd.hdc);
4424         RECT insetRect = toolTipInset (itemRect);
4425         OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
4426         GCData data = new GCData ();
4427         data.device = display;
4428         data.font = item.getFont (column);
4429         data.foreground = OS.GetTextColor (nmcd.hdc);
4430         data.background = OS.GetBkColor (nmcd.hdc);
4431         data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
4432         GC gc = GC.win32_new (nmcd.hdc, data);
4433         Event event = new Event ();
4434         event.item = item;
4435         event.index = column;
4436         event.gc = gc;
4437         event.detail |= SWT.FOREGROUND;
4438         event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
4439         //gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight);
4440         sendEvent (SWT.PaintItem, event);
4441         event.gc = null;
4442         gc.dispose ();
4443         OS.RestoreDC (nmcd.hdc, nSavedDC);
4444         return event;
4445 }
4446
4447 @Override
4448 void setBackgroundImage (long hBitmap) {
4449         super.setBackgroundImage (hBitmap);
4450         if (hBitmap != 0) {
4451                 /*
4452                 * Feature in Windows.  If TVM_SETBKCOLOR is never
4453                 * used to set the background color of a tree, the
4454                 * background color of the lines and the plus/minus
4455                 * will be drawn using the default background color,
4456                 * not the HBRUSH returned from WM_CTLCOLOR.  The fix
4457                 * is to set the background color to the default (when
4458                 * it is already the default) to make Windows use the
4459                 * brush.
4460                 */
4461                 if (OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0) == -1) {
4462                         OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
4463                 }
4464                 _setBackgroundPixel (-1);
4465         } else {
4466                 Control control = findBackgroundControl ();
4467                 if (control == null) control = this;
4468                 if (control.backgroundImage == null) {
4469                         setBackgroundPixel (control.getBackgroundPixel ());
4470                 }
4471         }
4472         /*
4473         * Feature in Windows.  When the tree has the style
4474         * TVS_FULLROWSELECT, the background color for the
4475         * entire row is filled when an item is painted,
4476         * drawing on top of the background image.  The fix
4477         * is to clear TVS_FULLROWSELECT when a background
4478         * image is set.
4479         */
4480         updateFullSelection ();
4481 }
4482
4483 @Override
4484 void setBackgroundPixel (int pixel) {
4485         Control control = findImageControl ();
4486         if (control != null) {
4487                 setBackgroundImage (control.backgroundImage);
4488                 return;
4489         }
4490         _setBackgroundPixel (pixel);
4491
4492         /*
4493         * Feature in Windows.  When the tree has the style
4494         * TVS_FULLROWSELECT, the background color for the
4495         * entire row is filled when an item is painted,
4496         * drawing on top of the background image.  The fix
4497         * is to restore TVS_FULLROWSELECT when a background
4498         * color is set.
4499         */
4500         updateFullSelection ();
4501 }
4502
4503 @Override
4504 void setCursor () {
4505         /*
4506         * Bug in Windows.  Under certain circumstances, when WM_SETCURSOR
4507         * is sent from SendMessage(), Windows GP's in the window proc for
4508         * the tree.  The fix is to avoid calling the tree window proc and
4509         * set the cursor for the tree outside of WM_SETCURSOR.
4510         *
4511         * NOTE:  This code assumes that the default cursor for the tree
4512         * is IDC_ARROW.
4513         */
4514         Cursor cursor = findCursor ();
4515         long hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : cursor.handle;
4516         OS.SetCursor (hCursor);
4517 }
4518
4519 /**
4520  * Sets the order that the items in the receiver should
4521  * be displayed in to the given argument which is described
4522  * in terms of the zero-relative ordering of when the items
4523  * were added.
4524  *
4525  * @param order the new order to display the items
4526  *
4527  * @exception SWTException <ul>
4528  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4529  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4530  * </ul>
4531  * @exception IllegalArgumentException <ul>
4532  *    <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
4533  *    <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
4534  * </ul>
4535  *
4536  * @see Tree#getColumnOrder()
4537  * @see TreeColumn#getMoveable()
4538  * @see TreeColumn#setMoveable(boolean)
4539  * @see SWT#Move
4540  *
4541  * @since 3.2
4542  */
4543 public void setColumnOrder (int [] order) {
4544         checkWidget ();
4545         if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
4546         if (columnCount == 0) {
4547                 if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
4548                 return;
4549         }
4550         if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
4551         int [] oldOrder = new int [columnCount];
4552         OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder);
4553         boolean reorder = false;
4554         boolean [] seen = new boolean [columnCount];
4555         for (int i=0; i<order.length; i++) {
4556                 int index = order [i];
4557                 if (index < 0 || index >= columnCount) error (SWT.ERROR_INVALID_RANGE);
4558                 if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
4559                 seen [index] = true;
4560                 if (index != oldOrder [i]) reorder = true;
4561         }
4562         if (reorder) {
4563                 RECT [] oldRects = new RECT [columnCount];
4564                 for (int i=0; i<columnCount; i++) {
4565                         oldRects [i] = new RECT ();
4566                         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, oldRects [i]);
4567                 }
4568                 OS.SendMessage (hwndHeader, OS.HDM_SETORDERARRAY, order.length, order);
4569                 OS.InvalidateRect (handle, null, true);
4570                 updateImageList ();
4571                 TreeColumn [] newColumns = new TreeColumn [columnCount];
4572                 System.arraycopy (columns, 0, newColumns, 0, columnCount);
4573                 RECT newRect = new RECT ();
4574                 for (int i=0; i<columnCount; i++) {
4575                         TreeColumn column = newColumns [i];
4576                         if (!column.isDisposed ()) {
4577                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, newRect);
4578                                 if (newRect.left != oldRects [i].left) {
4579                                         column.updateToolTip (i);
4580                                         column.sendEvent (SWT.Move);
4581                                 }
4582                         }
4583                 }
4584         }
4585 }
4586
4587 void setCheckboxImageList () {
4588         if ((style & SWT.CHECK) == 0) return;
4589         int count = 5, flags = OS.ILC_COLOR32;
4590         if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.ILC_MIRROR;
4591         if (!OS.IsAppThemed ()) flags |= OS.ILC_MASK;
4592         int height = (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0), width = height;
4593         long hStateList = OS.ImageList_Create (width, height, flags, count, count);
4594         long hDC = OS.GetDC (handle);
4595         long memDC = OS.CreateCompatibleDC (hDC);
4596         long hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height);
4597         long hOldBitmap = OS.SelectObject (memDC, hBitmap);
4598         RECT rect = new RECT ();
4599         OS.SetRect (rect, 0, 0, width * count, height);
4600         /*
4601         * NOTE: DrawFrameControl() draws a black and white
4602         * mask when not drawing a push button.  In order to
4603         * make the box surrounding the check mark transparent,
4604         * fill it with a color that is neither black or white.
4605         */
4606         int clrBackground = 0;
4607         if (OS.IsAppThemed ()) {
4608                 Control control = findBackgroundControl ();
4609                 if (control == null) control = this;
4610                 clrBackground = control.getBackgroundPixel ();
4611         } else {
4612                 clrBackground = 0x020000FF;
4613                 if ((clrBackground & 0xFFFFFF) == OS.GetSysColor (OS.COLOR_WINDOW)) {
4614                         clrBackground = 0x0200FF00;
4615                 }
4616         }
4617         long hBrush = OS.CreateSolidBrush (clrBackground);
4618         OS.FillRect (memDC, rect, hBrush);
4619         OS.DeleteObject (hBrush);
4620         long oldFont = OS.SelectObject (hDC, defaultFont ());
4621         TEXTMETRIC tm = new TEXTMETRIC ();
4622         OS.GetTextMetrics (hDC, tm);
4623         OS.SelectObject (hDC, oldFont);
4624         int itemWidth = Math.min (tm.tmHeight, width);
4625         int itemHeight = Math.min (tm.tmHeight, height);
4626         if (OS.IsAppThemed()) {
4627                 /*
4628                  * Feature in Windows. DrawThemeBackground stretches the checkbox
4629                  * bitmap to fill the provided rectangle. To avoid stretching
4630                  * artifacts, limit the rectangle to actual checkbox bitmap size.
4631                  */
4632                 SIZE size = new SIZE();
4633                 OS.GetThemePartSize(display.hButtonTheme(), memDC, OS.BP_CHECKBOX, 0, null, OS.TS_TRUE, size);
4634                 itemWidth = Math.min (size.cx, itemWidth);
4635                 itemHeight = Math.min (size.cy, itemHeight);
4636         }
4637         int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1;
4638         OS.SetRect (rect, left + width, top, left + width + itemWidth, top + itemHeight);
4639         if (OS.IsAppThemed ()) {
4640                 long hTheme = display.hButtonTheme ();
4641                 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4642                 rect.left += width;  rect.right += width;
4643                 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_CHECKEDNORMAL, rect, null);
4644                 rect.left += width;  rect.right += width;
4645                 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4646                 rect.left += width;  rect.right += width;
4647                 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_MIXEDNORMAL, rect, null);
4648         } else {
4649                 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT);
4650                 rect.left += width;  rect.right += width;
4651                 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT);
4652                 rect.left += width;  rect.right += width;
4653                 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4654                 rect.left += width;  rect.right += width;
4655                 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4656         }
4657         OS.SelectObject (memDC, hOldBitmap);
4658         OS.DeleteDC (memDC);
4659         OS.ReleaseDC (handle, hDC);
4660         if (OS.IsAppThemed ()) {
4661                 OS.ImageList_Add (hStateList, hBitmap, 0);
4662         } else {
4663                 OS.ImageList_AddMasked (hStateList, hBitmap, clrBackground);
4664         }
4665         OS.DeleteObject (hBitmap);
4666         long hOldStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
4667         OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, hStateList);
4668         if (hOldStateList != 0) OS.ImageList_Destroy (hOldStateList);
4669 }
4670
4671 @Override
4672 public void setFont (Font font) {
4673         checkWidget ();
4674         super.setFont (font);
4675         if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
4676 }
4677
4678 @Override
4679 void setForegroundPixel (int pixel) {
4680         /*
4681         * Bug in Windows.  When the tree is using the explorer
4682         * theme, it does not use COLOR_WINDOW_TEXT for the
4683         * foreground.  When TVM_SETTEXTCOLOR is called with -1,
4684         * it resets the color to black, not COLOR_WINDOW_TEXT.
4685         * The fix is to explicitly set the color.
4686         */
4687         if (explorerTheme) {
4688                 if (pixel == -1) pixel = defaultForeground ();
4689         }
4690         OS.SendMessage (handle, OS.TVM_SETTEXTCOLOR, 0, pixel);
4691 }
4692
4693 /**
4694  * Sets the header background color to the color specified
4695  * by the argument, or to the default system color if the argument is null.
4696  * <p>
4697  * Note: This operation is a <em>HINT</em> and is not supported on all platforms. If
4698  * the native header has a 3D look and feel (e.g. Windows 7), this method
4699  * will cause the header to look FLAT irrespective of the state of the tree style.
4700  * </p>
4701  * @param color the new color (or null)
4702  *
4703  * @exception IllegalArgumentException <ul>
4704  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
4705  * </ul>
4706  * @exception SWTException <ul>
4707  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4708  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4709  * </ul>
4710  * @since 3.106
4711  */
4712 public void setHeaderBackground (Color color) {
4713         checkWidget ();
4714         int pixel = -1;
4715         if (color != null) {
4716                 if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4717                 pixel = color.handle;
4718         }
4719         if (pixel == headerBackground) return;
4720         headerBackground = pixel;
4721         if (getHeaderVisible()) {
4722                 OS.InvalidateRect (hwndHeader, null, true);
4723         }
4724 }
4725
4726 /**
4727  * Sets the header foreground color to the color specified
4728  * by the argument, or to the default system color if the argument is null.
4729  * <p>
4730  * Note: This operation is a <em>HINT</em> and is not supported on all platforms. If
4731  * the native header has a 3D look and feel (e.g. Windows 7), this method
4732  * will cause the header to look FLAT irrespective of the state of the tree style.
4733  * </p>
4734  * @param color the new color (or null)
4735  *
4736  * @exception IllegalArgumentException <ul>
4737  *    <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
4738  * </ul>
4739  * @exception SWTException <ul>
4740  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4741  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4742  * </ul>
4743  * @since 3.106
4744  */
4745 public void setHeaderForeground (Color color) {
4746         checkWidget ();
4747         int pixel = -1;
4748         if (color != null) {
4749                 if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4750                 pixel = color.handle;
4751         }
4752         if (pixel == headerForeground) return;
4753         headerForeground = pixel;
4754         if (getHeaderVisible()) {
4755                 OS.InvalidateRect (hwndHeader, null, true);
4756         }
4757 }
4758
4759 /**
4760  * Marks the receiver's header as visible if the argument is <code>true</code>,
4761  * and marks it invisible otherwise.
4762  * <p>
4763  * If one of the receiver's ancestors is not visible or some
4764  * other condition makes the receiver not visible, marking
4765  * it visible may not actually cause it to be displayed.
4766  * </p>
4767  *
4768  * @param show the new visibility state
4769  *
4770  * @exception SWTException <ul>
4771  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4772  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4773  * </ul>
4774  *
4775  * @since 3.1
4776  */
4777 public void setHeaderVisible (boolean show) {
4778         checkWidget ();
4779         if (hwndHeader == 0) {
4780                 if (!show) return;
4781                 createParent ();
4782         }
4783         int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
4784         if (show) {
4785                 if ((bits & OS.HDS_HIDDEN) == 0) return;
4786                 bits &= ~OS.HDS_HIDDEN;
4787                 OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4788                 OS.ShowWindow (hwndHeader, OS.SW_SHOW);
4789         } else {
4790                 if ((bits & OS.HDS_HIDDEN) != 0) return;
4791                 bits |= OS.HDS_HIDDEN;
4792                 OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4793                 OS.ShowWindow (hwndHeader, OS.SW_HIDE);
4794         }
4795         setScrollWidth ();
4796         updateHeaderToolTips ();
4797         updateScrollBar ();
4798 }
4799
4800 @Override
4801 public void setRedraw (boolean redraw) {
4802         checkWidget ();
4803         /*
4804         * Feature in Windows.  When WM_SETREDRAW is used to
4805         * turn off redraw, the scroll bars are updated when
4806         * items are added and removed.  The fix is to call
4807         * the default window proc to stop all drawing.
4808         *
4809         * Bug in Windows.  For some reason, when WM_SETREDRAW
4810         * is used to turn redraw on for a tree and the tree
4811         * contains no items, the last item in the tree does
4812         * not redraw properly.  If the tree has only one item,
4813         * that item is not drawn.  If another window is dragged
4814         * on top of the item, parts of the item are redrawn
4815         * and erased at random.  The fix is to ensure that this
4816         * case doesn't happen by inserting and deleting an item
4817         * when redraw is turned on and there are no items in
4818         * the tree.
4819         */
4820         long hItem = 0;
4821         boolean willEnableDraw = redraw && (drawCount == 1);
4822         if (willEnableDraw) {
4823                 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
4824                 if (count == 0) {
4825                         TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
4826                         tvInsert.hInsertAfter = OS.TVI_FIRST;
4827                         hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
4828                 }
4829                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4830                 updateScrollBar ();
4831         }
4832
4833         super.setRedraw (redraw);
4834
4835         boolean haveDisabledDraw = !redraw && (drawCount == 1);
4836         if (haveDisabledDraw) {
4837                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4838         }
4839         if (hItem != 0) {
4840                 ignoreShrink = true;
4841                 OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
4842                 ignoreShrink = false;
4843         }
4844 }
4845
4846 void setScrollWidth () {
4847         if (hwndHeader == 0 || hwndParent == 0) return;
4848         int width = 0;
4849         HDITEM hdItem = new HDITEM ();
4850         for (int i=0; i<columnCount; i++) {
4851                 hdItem.mask = OS.HDI_WIDTH;
4852                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
4853                 width += hdItem.cxy;
4854         }
4855         setScrollWidth (Math.max (scrollWidth, width));
4856 }
4857
4858 void setScrollWidth (int width) {
4859         if (hwndHeader == 0 || hwndParent == 0) return;
4860         //TEMPORARY CODE
4861         //scrollWidth = width;
4862         int left = 0;
4863         RECT rect = new RECT ();
4864         SCROLLINFO info = new SCROLLINFO ();
4865         info.cbSize = SCROLLINFO.sizeof;
4866         info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
4867         if (columnCount == 0 && width == 0) {
4868                 OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4869                 info.nPage = info.nMax + 1;
4870                 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4871                 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
4872                 info.nPage = info.nMax + 1;
4873                 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
4874         } else {
4875                 if ((style & SWT.H_SCROLL) != 0) {
4876                         OS.GetClientRect (hwndParent, rect);
4877                         OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4878                         info.nMax = width;
4879                         info.nPage = rect.right - rect.left + 1;
4880                         OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4881                         info.fMask = OS.SIF_POS;
4882                         OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4883                         left = info.nPos;
4884                 }
4885         }
4886         if (horizontalBar != null) {
4887                 horizontalBar.setIncrement (INCREMENT);
4888                 horizontalBar.setPageIncrement (info.nPage);
4889         }
4890         OS.GetClientRect (hwndParent, rect);
4891         long hHeap = OS.GetProcessHeap ();
4892         HDLAYOUT playout = new HDLAYOUT ();
4893         playout.prc = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, RECT.sizeof);
4894         playout.pwpos = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, WINDOWPOS.sizeof);
4895         OS.MoveMemory (playout.prc, rect, RECT.sizeof);
4896         OS.SendMessage (hwndHeader, OS.HDM_LAYOUT, 0, playout);
4897         WINDOWPOS pos = new WINDOWPOS ();
4898         OS.MoveMemory (pos, playout.pwpos, WINDOWPOS.sizeof);
4899         if (playout.prc != 0) OS.HeapFree (hHeap, 0, playout.prc);
4900         if (playout.pwpos != 0) OS.HeapFree (hHeap, 0, playout.pwpos);
4901         OS.SetWindowPos (hwndHeader, OS.HWND_TOP, pos.x - left, pos.y, pos.cx + left, pos.cy, OS.SWP_NOACTIVATE);
4902         int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
4903         int b = (bits & OS.WS_EX_CLIENTEDGE) != 0 ? OS.GetSystemMetrics (OS.SM_CXEDGE) : 0;
4904         int w = pos.cx + (columnCount == 0 && width == 0 ? 0 : OS.GetSystemMetrics (OS.SM_CXVSCROLL));
4905         int h = rect.bottom - rect.top - pos.cy;
4906         boolean oldIgnore = ignoreResize;
4907         ignoreResize = true;
4908         OS.SetWindowPos (handle, 0, pos.x - left - b, pos.y + pos.cy - b, w + left + b * 2, h + b * 2, OS.SWP_NOACTIVATE | OS.SWP_NOZORDER);
4909         ignoreResize = oldIgnore;
4910 }
4911
4912 void setSelection (long hItem, TVITEM tvItem, TreeItem [] selection) {
4913         while (hItem != 0) {
4914                 int index = 0;
4915                 while (index < selection.length) {
4916                         TreeItem item = selection [index];
4917                         if (item != null && item.handle == hItem) break;
4918                         index++;
4919                 }
4920                 tvItem.hItem = hItem;
4921                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4922                 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
4923                         if (index == selection.length) {
4924                                 tvItem.state = 0;
4925                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4926                         }
4927                 } else {
4928                         if (index != selection.length) {
4929                                 expandToItem(_getItem(hItem));
4930                                 tvItem.state = OS.TVIS_SELECTED;
4931                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4932                         }
4933                 }
4934                 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4935                 setSelection (hFirstItem, tvItem, selection);
4936                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4937         }
4938 }
4939
4940 /**
4941  * Sets the receiver's selection to the given item.
4942  * The current selection is cleared before the new item is selected,
4943  * and if necessary the receiver is scrolled to make the new selection visible.
4944  * <p>
4945  * If the item is not in the receiver, then it is ignored.
4946  * </p>
4947  *
4948  * @param item the item to select
4949  *
4950  * @exception IllegalArgumentException <ul>
4951  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4952  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4953  * </ul>
4954  * @exception SWTException <ul>
4955  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4956  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4957  * </ul>
4958  *
4959  * @since 3.2
4960  */
4961 public void setSelection (TreeItem item) {
4962         checkWidget ();
4963         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4964         setSelection (new TreeItem [] {item});
4965 }
4966
4967 /**
4968  * Sets the receiver's selection to be the given array of items.
4969  * The current selection is cleared before the new items are selected,
4970  * and if necessary the receiver is scrolled to make the new selection visible.
4971  * <p>
4972  * Items that are not in the receiver are ignored.
4973  * If the receiver is single-select and multiple items are specified,
4974  * then all items are ignored.
4975  * </p>
4976  *
4977  * @param items the array of items
4978  *
4979  * @exception IllegalArgumentException <ul>
4980  *    <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
4981  *    <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
4982  * </ul>
4983  * @exception SWTException <ul>
4984  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4985  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4986  * </ul>
4987  *
4988  * @see Tree#deselectAll()
4989  */
4990 public void setSelection (TreeItem [] items) {
4991         checkWidget ();
4992         if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
4993         int length = items.length;
4994         if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) {
4995                 deselectAll();
4996                 return;
4997         }
4998
4999         /* Select/deselect the first item */
5000         TreeItem item = items [0];
5001         if (item != null) {
5002                 if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5003                 long hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5004                 long hNewItem = hAnchor = item.handle;
5005
5006                 /*
5007                 * Bug in Windows.  When TVM_SELECTITEM is used to select and
5008                 * scroll an item to be visible and the client area of the tree
5009                 * is smaller that the size of one item, TVM_SELECTITEM makes
5010                 * the next item in the tree visible by making it the top item
5011                 * instead of making the desired item visible.  The fix is to
5012                 * detect the case when the client area is too small and make
5013                 * the desired visible item be the top item in the tree.
5014                 *
5015                 * Note that TVM_SELECTITEM when called with TVGN_FIRSTVISIBLE
5016                 * also requires the work around for scrolling.
5017                 */
5018                 boolean fixScroll = checkScroll (hNewItem);
5019                 if (fixScroll) {
5020                         OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5021                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5022                 }
5023                 ignoreSelect = true;
5024                 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
5025                 ignoreSelect = false;
5026                 if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
5027                         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hNewItem);
5028                         long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hNewItem);
5029                         if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5030                 }
5031                 if (fixScroll) {
5032                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5033                         OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5034                 }
5035
5036                 /*
5037                 * Feature in Windows.  When the old and new focused item
5038                 * are the same, Windows does not check to make sure that
5039                 * the item is actually selected, not just focused.  The
5040                 * fix is to force the item to draw selected by setting
5041                 * the state mask, and to ensure that it is visible.
5042                 */
5043                 if (hOldItem == hNewItem) {
5044                         TVITEM tvItem = new TVITEM ();
5045                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5046                         tvItem.state = OS.TVIS_SELECTED;
5047                         tvItem.stateMask = OS.TVIS_SELECTED;
5048                         tvItem.hItem = hNewItem;
5049                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5050                         showItem (hNewItem);
5051                 }
5052         }
5053         if ((style & SWT.SINGLE) != 0) return;
5054
5055         /* Select/deselect the rest of the items */
5056         TVITEM tvItem = new TVITEM ();
5057         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5058         tvItem.stateMask = OS.TVIS_SELECTED;
5059         long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
5060         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
5061         if ((style & SWT.VIRTUAL) != 0) {
5062                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
5063                 setSelection (hItem, tvItem, items);
5064         } else {
5065                 for (int i=0; i<this.items.length; i++) {
5066                         item = this.items [i];
5067                         if (item != null) {
5068                                 int index = 0;
5069                                 while (index < length) {
5070                                         if (items [index] == item) break;
5071                                         index++;
5072                                 }
5073                                 tvItem.hItem = item.handle;
5074                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5075                                 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
5076                                         if (index == length) {
5077                                                 tvItem.state = 0;
5078                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5079                                         }
5080                                 } else {
5081                                         if (index != length) {
5082                                                 expandToItem(item);
5083                                                 tvItem.state = OS.TVIS_SELECTED;
5084                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5085                                         }
5086                                 }
5087                         }
5088                 }
5089         }
5090         OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
5091 }
5092
5093 void expandToItem(TreeItem item) {
5094         TreeItem parentItem = item.getParentItem();
5095         if (parentItem != null && !parentItem.getExpanded()) {
5096                 expandToItem(parentItem);
5097                 parentItem.setExpanded(true);
5098                 Event event = new Event ();
5099                 event.item = parentItem;
5100                 sendEvent (SWT.Expand, event);
5101         }
5102 }
5103
5104 /**
5105  * Sets the column used by the sort indicator for the receiver. A null
5106  * value will clear the sort indicator.  The current sort column is cleared
5107  * before the new column is set.
5108  *
5109  * @param column the column used by the sort indicator or <code>null</code>
5110  *
5111  * @exception IllegalArgumentException <ul>
5112  *    <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
5113  * </ul>
5114  * @exception SWTException <ul>
5115  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5116  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5117  * </ul>
5118  *
5119  * @since 3.2
5120  */
5121 public void setSortColumn (TreeColumn column) {
5122         checkWidget ();
5123         if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5124         if (sortColumn != null && !sortColumn.isDisposed ()) {
5125                 sortColumn.setSortDirection (SWT.NONE);
5126         }
5127         sortColumn = column;
5128         if (sortColumn != null && sortDirection != SWT.NONE) {
5129                 sortColumn.setSortDirection (sortDirection);
5130         }
5131 }
5132
5133 /**
5134  * Sets the direction of the sort indicator for the receiver. The value
5135  * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
5136  *
5137  * @param direction the direction of the sort indicator
5138  *
5139  * @exception SWTException <ul>
5140  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5141  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5142  * </ul>
5143  *
5144  * @since 3.2
5145  */
5146 public void setSortDirection (int direction) {
5147         checkWidget ();
5148         if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) return;
5149         sortDirection = direction;
5150         if (sortColumn != null && !sortColumn.isDisposed ()) {
5151                 sortColumn.setSortDirection (direction);
5152         }
5153 }
5154
5155 /**
5156  * Sets the item which is currently at the top of the receiver.
5157  * This item can change when items are expanded, collapsed, scrolled
5158  * or new items are added or removed.
5159  *
5160  * @param item the item to be shown
5161  *
5162  * @exception IllegalArgumentException <ul>
5163  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5164  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5165  * </ul>
5166  * @exception SWTException <ul>
5167  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5168  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5169  * </ul>
5170  *
5171  * @see Tree#getTopItem()
5172  *
5173  * @since 2.1
5174  */
5175 public void setTopItem (TreeItem item) {
5176         checkWidget ();
5177         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
5178         if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5179         long hItem = item.handle;
5180         long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5181         if (hItem == hTopItem) return;
5182         boolean fixScroll = checkScroll (hItem), redraw = false;
5183         if (fixScroll) {
5184                 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5185                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5186         } else {
5187                 redraw = getDrawing () && OS.IsWindowVisible (handle);
5188                 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5189         }
5190         SCROLLINFO hInfo = null;
5191         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
5192         long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
5193         if (hParent != 0 && (bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) {
5194                 hInfo = new SCROLLINFO ();
5195                 hInfo.cbSize = SCROLLINFO.sizeof;
5196                 hInfo.fMask = OS.SIF_ALL;
5197                 OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo);
5198         }
5199         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
5200         if (hParent != 0) {
5201                 if (hInfo != null) {
5202                         long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos);
5203                         OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0);
5204                 }
5205         } else {
5206                 OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5207         }
5208         if (fixScroll) {
5209                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5210                 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5211         } else {
5212                 if (redraw) {
5213                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5214                         OS.InvalidateRect (handle, null, true);
5215                 }
5216         }
5217         updateScrollBar ();
5218 }
5219
5220 void showItem (long hItem) {
5221         /*
5222         * Bug in Windows.  When TVM_ENSUREVISIBLE is used to ensure
5223         * that an item is visible and the client area of the tree is
5224         * smaller that the size of one item, TVM_ENSUREVISIBLE makes
5225         * the next item in the tree visible by making it the top item
5226         * instead of making the desired item visible.  The fix is to
5227         * detect the case when the client area is too small and make
5228         * the desired visible item be the top item in the tree.
5229         */
5230         if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
5231                 boolean fixScroll = checkScroll (hItem);
5232                 if (fixScroll) {
5233                         OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5234                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5235                 }
5236                 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
5237                 /* This code is intentionally commented */
5238                 //int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
5239                 //if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5240                 OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5241                 if (fixScroll) {
5242                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5243                         OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5244                 }
5245         } else {
5246                 boolean scroll = true;
5247                 RECT itemRect = new RECT ();
5248                 if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) {
5249                         forceResize ();
5250                         RECT rect = new RECT ();
5251                         OS.GetClientRect (handle, rect);
5252                         POINT pt = new POINT ();
5253                         pt.x = itemRect.left;
5254                         pt.y = itemRect.top;
5255                         if (OS.PtInRect (rect, pt)) {
5256                                 pt.y = itemRect.bottom;
5257                                 if (OS.PtInRect (rect, pt)) scroll = false;
5258                         }
5259                 }
5260                 if (scroll) {
5261                         boolean fixScroll = checkScroll (hItem);
5262                         if (fixScroll) {
5263                                 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5264                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5265                         }
5266                         OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
5267                         if (fixScroll) {
5268                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5269                                 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5270                         }
5271                 }
5272         }
5273         if (hwndParent != 0) {
5274                 RECT itemRect = new RECT ();
5275                 if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) {
5276                         forceResize ();
5277                         RECT rect = new RECT ();
5278                         OS.GetClientRect (hwndParent, rect);
5279                         OS.MapWindowPoints (hwndParent, handle, rect, 2);
5280                         POINT pt = new POINT ();
5281                         pt.x = itemRect.left;
5282                         pt.y = itemRect.top;
5283                         if (!OS.PtInRect (rect, pt)) {
5284                                 pt.y = itemRect.bottom;
5285                                 if (!OS.PtInRect (rect, pt)) {
5286                                         SCROLLINFO info = new SCROLLINFO ();
5287                                         info.cbSize = SCROLLINFO.sizeof;
5288                                         info.fMask = OS.SIF_POS;
5289                                         info.nPos = Math.max (0, pt.x - Tree.INSET / 2);
5290                                         OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
5291                                         setScrollWidth ();
5292                                 }
5293                         }
5294                 }
5295         }
5296         updateScrollBar ();
5297 }
5298
5299 /**
5300  * Shows the column.  If the column is already showing in the receiver,
5301  * this method simply returns.  Otherwise, the columns are scrolled until
5302  * the column is visible.
5303  *
5304  * @param column the column to be shown
5305  *
5306  * @exception IllegalArgumentException <ul>
5307  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5308  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5309  * </ul>
5310  * @exception SWTException <ul>
5311  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5312  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5313  * </ul>
5314  *
5315  * @since 3.1
5316  */
5317 public void showColumn (TreeColumn column) {
5318         checkWidget ();
5319         if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
5320         if (column.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
5321         if (column.parent != this) return;
5322         int index = indexOf (column);
5323         if (index == -1) return;
5324         if (0 <= index && index < columnCount) {
5325                 forceResize ();
5326                 RECT rect = new RECT ();
5327                 OS.GetClientRect (hwndParent, rect);
5328                 OS.MapWindowPoints (hwndParent, handle, rect, 2);
5329                 RECT headerRect = new RECT ();
5330                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
5331                 boolean scroll = headerRect.left < rect.left;
5332                 if (!scroll) {
5333                         int width = Math.min (rect.right - rect.left, headerRect.right - headerRect.left);
5334                         scroll = headerRect.left + width > rect.right;
5335                 }
5336                 if (scroll) {
5337                         SCROLLINFO info = new SCROLLINFO ();
5338                         info.cbSize = SCROLLINFO.sizeof;
5339                         info.fMask = OS.SIF_POS;
5340                         info.nPos = Math.max (0, headerRect.left - Tree.INSET / 2);
5341                         OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
5342                         setScrollWidth ();
5343                 }
5344         }
5345 }
5346
5347 /**
5348  * Shows the item.  If the item is already showing in the receiver,
5349  * this method simply returns.  Otherwise, the items are scrolled
5350  * and expanded until the item is visible.
5351  *
5352  * @param item the item to be shown
5353  *
5354  * @exception IllegalArgumentException <ul>
5355  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5356  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5357  * </ul>
5358  * @exception SWTException <ul>
5359  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5360  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5361  * </ul>
5362  *
5363  * @see Tree#showSelection()
5364  */
5365 public void showItem (TreeItem item) {
5366         checkWidget ();
5367         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
5368         if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
5369         showItem (item.handle);
5370 }
5371
5372 /**
5373  * Shows the selection.  If the selection is already showing in the receiver,
5374  * this method simply returns.  Otherwise, the items are scrolled until
5375  * the selection is visible.
5376  *
5377  * @exception SWTException <ul>
5378  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5379  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5380  * </ul>
5381  *
5382  * @see Tree#showItem(TreeItem)
5383  */
5384 public void showSelection () {
5385         checkWidget ();
5386         long hItem = 0;
5387         if ((style & SWT.SINGLE) != 0) {
5388                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5389                 if (hItem == 0) return;
5390                 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
5391                 if ((state & OS.TVIS_SELECTED) == 0) return;
5392         } else {
5393                 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
5394                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
5395                 if ((style & SWT.VIRTUAL) != 0) {
5396                         long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
5397                         hItem = getNextSelection (hRoot);
5398                 } else {
5399                         //FIXME - this code expands first selected item it finds
5400                         int index = 0;
5401                         while (index <items.length) {
5402                                 TreeItem item = items [index];
5403                                 if (item != null) {
5404                                         int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, item.handle, OS.TVIS_SELECTED);
5405                                         if ((state & OS.TVIS_SELECTED) != 0) {
5406                                                 hItem = item.handle;
5407                                                 break;
5408                                         }
5409                                 }
5410                                 index++;
5411                         }
5412                 }
5413                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
5414         }
5415         if (hItem != 0) showItem (hItem);
5416 }
5417
5418 /*public*/ void sort () {
5419         checkWidget ();
5420         if ((style & SWT.VIRTUAL) != 0) return;
5421         sort (OS.TVI_ROOT, false);
5422 }
5423
5424 void sort (long hParent, boolean all) {
5425         int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
5426         if (itemCount == 0 || itemCount == 1) return;
5427         hFirstIndexOf = hLastIndexOf = 0;
5428         itemCount = -1;
5429         if (sortDirection == SWT.UP || sortDirection == SWT.NONE) {
5430                 OS.SendMessage (handle, OS.TVM_SORTCHILDREN, all ? 1 : 0, hParent);
5431         } else {
5432                 Callback compareCallback = new Callback (this, "CompareFunc", 3);
5433                 long lpfnCompare = compareCallback.getAddress ();
5434                 TVSORTCB psort = new TVSORTCB ();
5435                 psort.hParent = hParent;
5436                 psort.lpfnCompare = lpfnCompare;
5437                 psort.lParam = sortColumn == null ? 0 : indexOf (sortColumn);
5438                 OS.SendMessage (handle, OS.TVM_SORTCHILDRENCB, all ? 1 : 0, psort);
5439                 compareCallback.dispose ();
5440         }
5441 }
5442
5443 @Override
5444 void subclass () {
5445         super.subclass ();
5446         if (hwndHeader != 0) {
5447                 OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, display.windowProc);
5448         }
5449 }
5450
5451 RECT toolTipInset (RECT rect) {
5452         RECT insetRect = new RECT ();
5453         OS.SetRect (insetRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
5454         return insetRect;
5455 }
5456
5457 RECT toolTipRect (RECT rect) {
5458         RECT toolRect = new RECT ();
5459         OS.SetRect (toolRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
5460         return toolRect;
5461 }
5462
5463 @Override
5464 String toolTipText (NMTTDISPINFO hdr) {
5465         long hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
5466         if (hwndToolTip == hdr.hwndFrom && toolTipText != null) return ""; //$NON-NLS-1$
5467         if (headerToolTipHandle == hdr.hwndFrom) {
5468                 for (int i=0; i<columnCount; i++) {
5469                         TreeColumn column = columns [i];
5470                         if (column.id == hdr.idFrom) return column.toolTipText;
5471                 }
5472                 return super.toolTipText (hdr);
5473         }
5474         if (itemToolTipHandle == hdr.hwndFrom) {
5475                 if (toolTipText != null) return "";
5476                 int pos = OS.GetMessagePos ();
5477                 POINT pt = new POINT();
5478                 OS.POINTSTOPOINT (pt, pos);
5479                 OS.ScreenToClient (handle, pt);
5480                 int [] index = new int [1];
5481                 TreeItem [] item = new TreeItem [1];
5482                 RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
5483                 if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
5484                         String text = null;
5485                         if (index [0] == 0) {
5486                                 text = item [0].text;
5487                         } else {
5488                                 String[] strings = item [0].strings;
5489                                 if (strings != null) text = strings [index [0]];
5490                         }
5491                         //TEMPORARY CODE
5492                         if (isCustomToolTip ()) text = " ";
5493                         if (text != null) return text;
5494                 }
5495         }
5496         return super.toolTipText (hdr);
5497 }
5498
5499 @Override
5500 long topHandle () {
5501         return hwndParent != 0 ? hwndParent : handle;
5502 }
5503
5504 void updateFullSelection () {
5505         if ((style & SWT.FULL_SELECTION) != 0) {
5506                 int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
5507                 if ((newBits & OS.TVS_FULLROWSELECT) != 0) {
5508                         if (!OS.IsWindowEnabled (handle) || findImageControl () != null) {
5509                                 if (!explorerTheme) newBits &= ~OS.TVS_FULLROWSELECT;
5510                         }
5511                 } else {
5512                         if (OS.IsWindowEnabled (handle) && findImageControl () == null) {
5513                                 if (!hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
5514                                         newBits |= OS.TVS_FULLROWSELECT;
5515                                 }
5516                         }
5517                 }
5518                 if (newBits != oldBits) {
5519                         OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
5520                         OS.InvalidateRect (handle, null, true);
5521                 }
5522         }
5523 }
5524
5525 void updateHeaderToolTips () {
5526         if (headerToolTipHandle == 0) return;
5527         RECT rect = new RECT ();
5528         TOOLINFO lpti = new TOOLINFO ();
5529         lpti.cbSize = TOOLINFO.sizeof;
5530         lpti.uFlags = OS.TTF_SUBCLASS;
5531         lpti.hwnd = hwndHeader;
5532         lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
5533         for (int i=0; i<columnCount; i++) {
5534                 TreeColumn column = columns [i];
5535                 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, rect) != 0) {
5536                         lpti.uId = column.id = display.nextToolTipId++;
5537                         lpti.left = rect.left;
5538                         lpti.top = rect.top;
5539                         lpti.right = rect.right;
5540                         lpti.bottom = rect.bottom;
5541                         OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
5542                 }
5543         }
5544 }
5545
5546 void updateImageList () {
5547         if (imageList == null) return;
5548         if (hwndHeader == 0) return;
5549         int i = 0, index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
5550         while (i < items.length) {
5551                 TreeItem item = items [i];
5552                 if (item != null) {
5553                         Image image = null;
5554                         if (index == 0) {
5555                                 image = item.image;
5556                         } else {
5557                                 Image [] images = item.images;
5558                                 if (images != null) image = images [index];
5559                         }
5560                         if (image != null) break;
5561                 }
5562                 i++;
5563         }
5564         /*
5565         * Feature in Windows.  When setting the same image list multiple
5566         * times, Windows does work making this operation slow.  The fix
5567         * is to test for the same image list before setting the new one.
5568         */
5569         long hImageList = i == items.length ? 0 : imageList.getHandle ();
5570         long hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
5571         if (hImageList != hOldImageList) {
5572                 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
5573         }
5574 }
5575
5576 @Override
5577 void updateMenuLocation (Event event) {
5578         Rectangle clientArea = getClientAreaInPixels ();
5579         int x = clientArea.x, y = clientArea.y;
5580         TreeItem focusItem = getFocusItem ();
5581         if (focusItem != null) {
5582                 Rectangle bounds = focusItem.getBoundsInPixels (0);
5583                 if (focusItem.text != null && focusItem.text.length () != 0) {
5584                         bounds = focusItem.getBoundsInPixels ();
5585                 }
5586                 x = Math.max (x, bounds.x + bounds.width / 2);
5587                 x = Math.min (x, clientArea.x + clientArea.width);
5588                 y = Math.max (y, bounds.y + bounds.height);
5589                 y = Math.min (y, clientArea.y + clientArea.height);
5590         }
5591         Point pt = toDisplayInPixels (x, y);
5592         event.setLocationInPixels(pt.x, pt.y);
5593 }
5594
5595 @Override
5596 void updateOrientation () {
5597         super.updateOrientation ();
5598         RECT rect = new RECT ();
5599         OS.GetWindowRect (handle, rect);
5600         int width = rect.right - rect.left, height = rect.bottom - rect.top;
5601         OS.SetWindowPos (handle, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5602         OS.SetWindowPos (handle, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5603         if (hwndParent != 0) {
5604                 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
5605                 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
5606                         bits |= OS.WS_EX_LAYOUTRTL;
5607                 } else {
5608                         bits &= ~OS.WS_EX_LAYOUTRTL;
5609                 }
5610                 bits &= ~OS.WS_EX_RTLREADING;
5611                 OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, bits);
5612                 rect = new RECT ();
5613                 OS.GetWindowRect (hwndParent, rect);
5614                 width = rect.right - rect.left; height = rect.bottom - rect.top;
5615                 OS.SetWindowPos (hwndParent, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5616                 OS.SetWindowPos (hwndParent, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5617         }
5618         if (hwndHeader != 0) {
5619                 int bits = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE);
5620                 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
5621                         bits |= OS.WS_EX_LAYOUTRTL;
5622                 } else {
5623                         bits &= ~OS.WS_EX_LAYOUTRTL;
5624                 }
5625                 OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, bits);
5626                 OS.InvalidateRect (hwndHeader, null, true);
5627         }
5628         if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
5629         if (imageList != null) {
5630                 Point size = imageList.getImageSize ();
5631                 display.releaseImageList (imageList);
5632                 imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, size.x, size.y);
5633                 for (int i = 0; i < items.length; i++) {
5634                         TreeItem item = items[i];
5635                         if (item != null) {
5636                                 Image image = item.image;
5637                                 if (image != null) {
5638                                         int index = imageList.indexOf (image);
5639                                         if (index == -1) imageList.add (image);
5640                                 }
5641                         }
5642                 }
5643                 long hImageList = imageList.getHandle ();
5644                 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
5645         }
5646         if (hwndHeader != 0) {
5647                 if (headerImageList != null) {
5648                         Point size = headerImageList.getImageSize ();
5649                         display.releaseImageList (headerImageList);
5650                         headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, size.x, size.y);
5651                         if (columns != null) {
5652                                 for (int i = 0; i < columns.length; i++) {
5653                                         TreeColumn column = columns[i];
5654                                         if (column != null) {
5655                                                 Image image = column.image;
5656                                                 if (image != null) {
5657                                                         HDITEM hdItem = new HDITEM ();
5658                                                         hdItem.mask = OS.HDI_FORMAT;
5659                                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
5660                                                         if ((hdItem.fmt & OS.HDF_IMAGE)!= 0) {
5661                                                                 int index = headerImageList.indexOf (image);
5662                                                                 if (index == -1) index = headerImageList.add (image);
5663                                                                 hdItem.mask = OS.HDI_IMAGE;
5664                                                                 hdItem.iImage = index;
5665                                                                 OS.SendMessage (hwndHeader, OS.HDM_SETITEM, i, hdItem);
5666                                                         }
5667                                                 }
5668                                         }
5669                                 }
5670                         }
5671                         long hImageListHeader = headerImageList.getHandle ();
5672                         OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageListHeader);
5673                 }
5674         }
5675 }
5676
5677 /**
5678  * Copies Tree's scrollbar state to intermediate parent.
5679  *
5680  * If Tree has a header, then (Tree+header) get wrapped into intermediate
5681  * parent. This parent also has scrollbar, and it is configured to
5682  * obscure the Tree's scrollbar - I think this is due to aesthetic
5683  * reasons where the new scrollbar also extends over header. Since it
5684  * obscures the true scrollbar, it always needs to be in sync with the
5685  * true scrollbar.
5686  */
5687 void updateScrollBar () {
5688         if (hwndParent != 0) {
5689                 if (columnCount != 0 || scrollWidth != 0) {
5690                         SCROLLINFO info = new SCROLLINFO ();
5691                         info.cbSize = SCROLLINFO.sizeof;
5692                         info.fMask = OS.SIF_ALL;
5693                         int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
5694                         if (itemCount == 0) {
5695                                 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5696                                 info.nPage = info.nMax + 1;
5697                                 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5698                         } else {
5699                                 OS.GetScrollInfo (handle, OS.SB_VERT, info);
5700                                 if (info.nPage == 0) {
5701                                         SCROLLBARINFO psbi = new SCROLLBARINFO ();
5702                                         psbi.cbSize = SCROLLBARINFO.sizeof;
5703                                         OS.GetScrollBarInfo (handle, OS.OBJID_VSCROLL, psbi);
5704                                         if ((psbi.rgstate [0] & OS.STATE_SYSTEM_INVISIBLE) != 0) {
5705                                                 info.nPage = info.nMax + 1;
5706                                         }
5707                                 }
5708                                 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5709                         }
5710                 }
5711         }
5712 }
5713
5714 @Override
5715 void unsubclass () {
5716         super.unsubclass ();
5717         if (hwndHeader != 0) {
5718                 OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, HeaderProc);
5719         }
5720 }
5721
5722 @Override
5723 int widgetStyle () {
5724         int bits = super.widgetStyle () | OS.TVS_SHOWSELALWAYS | OS.TVS_LINESATROOT | OS.TVS_HASBUTTONS | OS.TVS_NONEVENHEIGHT;
5725         if (OS.IsAppThemed ()) {
5726                 bits |= OS.TVS_TRACKSELECT;
5727                 if ((style & SWT.FULL_SELECTION) != 0) bits |= OS.TVS_FULLROWSELECT;
5728         } else {
5729                 if ((style & SWT.FULL_SELECTION) != 0) {
5730                         bits |= OS.TVS_FULLROWSELECT;
5731                 } else {
5732                         bits |= OS.TVS_HASLINES;
5733                 }
5734         }
5735         if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
5736                 bits &= ~(OS.WS_HSCROLL | OS.WS_VSCROLL);
5737                 bits |= OS.TVS_NOSCROLL;
5738         } else {
5739                 if ((style & SWT.H_SCROLL) == 0) {
5740                         bits &= ~OS.WS_HSCROLL;
5741                         bits |= OS.TVS_NOHSCROLL;
5742                 }
5743         }
5744 //      bits |= OS.TVS_NOTOOLTIPS | OS.TVS_DISABLEDRAGDROP;
5745         return bits | OS.TVS_DISABLEDRAGDROP;
5746 }
5747
5748 @Override
5749 TCHAR windowClass () {
5750         return TreeClass;
5751 }
5752
5753 @Override
5754 long windowProc () {
5755         return TreeProc;
5756 }
5757
5758 @Override
5759 long windowProc (long hwnd, int msg, long wParam, long lParam) {
5760         if (hwndHeader != 0 && hwnd == hwndHeader) {
5761                 switch (msg) {
5762                         case OS.WM_CONTEXTMENU: {
5763                                 LRESULT result = wmContextMenu (hwnd, wParam, lParam);
5764                                 if (result != null) return result.value;
5765                                 break;
5766                         }
5767                         case OS.WM_MOUSELEAVE: {
5768                                 /*
5769                                 * Bug in Windows.  On XP, when a tooltip is hidden
5770                                 * due to a time out or mouse press, the tooltip
5771                                 * remains active although no longer visible and
5772                                 * won't show again until another tooltip becomes
5773                                 * active.  The fix is to reset the tooltip bounds.
5774                                 */
5775                                 updateHeaderToolTips ();
5776                                 updateHeaderToolTips ();
5777                                 break;
5778                         }
5779                         case OS.WM_NOTIFY: {
5780                                 NMHDR hdr = new NMHDR ();
5781                                 OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
5782                                 switch (hdr.code) {
5783                                         case OS.TTN_SHOW:
5784                                         case OS.TTN_POP:
5785                                         case OS.TTN_GETDISPINFO:
5786                                                 return OS.SendMessage (handle, msg, wParam, lParam);
5787                                 }
5788                                 break;
5789                         }
5790                         case OS.WM_SETCURSOR: {
5791                                 if (wParam == hwnd) {
5792                                         int hitTest = (short) OS.LOWORD (lParam);
5793                                         if (hitTest == OS.HTCLIENT) {
5794                                                 HDHITTESTINFO pinfo = new HDHITTESTINFO ();
5795                                                 int pos = OS.GetMessagePos ();
5796                                                 POINT pt = new POINT ();
5797                                                 OS.POINTSTOPOINT (pt, pos);
5798                                                 OS.ScreenToClient (hwnd, pt);
5799                                                 pinfo.x = pt.x;
5800                                                 pinfo.y = pt.y;
5801                                                 int index = (int)OS.SendMessage (hwndHeader, OS.HDM_HITTEST, 0, pinfo);
5802                                                 if (0 <= index && index < columnCount && !columns [index].resizable) {
5803                                                         if ((pinfo.flags & (OS.HHT_ONDIVIDER | OS.HHT_ONDIVOPEN)) != 0) {
5804                                                                 OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
5805                                                                 return 1;
5806                                                         }
5807                                                 }
5808                                         }
5809                                 }
5810                                 break;
5811                         }
5812                 }
5813                 return callWindowProc (hwnd, msg, wParam, lParam);
5814         }
5815         if (hwndParent != 0 && hwnd == hwndParent) {
5816                 switch (msg) {
5817                         case OS.WM_MOVE: {
5818                                 sendEvent (SWT.Move);
5819                                 return 0;
5820                         }
5821                         case OS.WM_SIZE: {
5822                                 setScrollWidth ();
5823                                 if (ignoreResize) return 0;
5824                                 setResizeChildren (false);
5825                                 long code = callWindowProc (hwnd, OS.WM_SIZE, wParam, lParam);
5826                                 sendEvent (SWT.Resize);
5827                                 if (isDisposed ()) return 0;
5828                                 if (layout != null) {
5829                                         markLayout (false, false);
5830                                         updateLayout (false, false);
5831                                 }
5832                                 setResizeChildren (true);
5833                                 updateScrollBar ();
5834                                 return code;
5835                         }
5836                         case OS.WM_NCPAINT: {
5837                                 LRESULT result = wmNCPaint (hwnd, wParam, lParam);
5838                                 if (result != null) return result.value;
5839                                 break;
5840                         }
5841                         case OS.WM_PRINT: {
5842                                 LRESULT result = wmPrint (hwnd, wParam, lParam);
5843                                 if (result != null) return result.value;
5844                                 break;
5845                         }
5846                         case OS.WM_COMMAND:
5847                         case OS.WM_NOTIFY:
5848                         case OS.WM_SYSCOLORCHANGE: {
5849                                 return OS.SendMessage (handle, msg, wParam, lParam);
5850                         }
5851                         case OS.WM_HSCROLL: {
5852                                 /*
5853                                 * Bug on WinCE.  lParam should be NULL when the message is not sent
5854                                 * by a scroll bar control, but it contains the handle to the window.
5855                                 * When the message is sent by a scroll bar control, it correctly
5856                                 * contains the handle to the scroll bar.  The fix is to check for
5857                                 * both.
5858                                 */
5859                                 if (horizontalBar != null && (lParam == 0 || lParam == hwndParent)) {
5860                                         wmScroll (horizontalBar, true, hwndParent, OS.WM_HSCROLL, wParam, lParam);
5861                                 }
5862                                 setScrollWidth ();
5863                                 break;
5864                         }
5865                         case OS.WM_VSCROLL: {
5866                                 SCROLLINFO info = new SCROLLINFO ();
5867                                 info.cbSize = SCROLLINFO.sizeof;
5868                                 info.fMask = OS.SIF_ALL;
5869                                 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5870                                 /*
5871                                 * Update the nPos field to match the nTrackPos field
5872                                 * so that the tree scrolls when the scroll bar of the
5873                                 * parent is dragged.
5874                                 *
5875                                 * NOTE: For some reason, this code is only necessary
5876                                 * on Windows Vista.
5877                                 */
5878                                 if (OS.LOWORD (wParam) == OS.SB_THUMBTRACK) {
5879                                         info.nPos = info.nTrackPos;
5880                                 }
5881                                 OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
5882                                 long code = OS.SendMessage (handle, OS.WM_VSCROLL, wParam, lParam);
5883                                 OS.GetScrollInfo (handle, OS.SB_VERT, info);
5884                                 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5885                                 return code;
5886                         }
5887                 }
5888                 return callWindowProc (hwnd, msg, wParam, lParam);
5889         }
5890         if (msg == Display.DI_GETDRAGIMAGE) {
5891                 /*
5892                 * When there is more than one item selected, DI_GETDRAGIMAGE
5893                 * returns the item under the cursor.  This happens because
5894                 * the tree does not have implement multi-select.  The fix
5895                 * is to disable DI_GETDRAGIMAGE when more than one item is
5896                 * selected.
5897                 */
5898                 if ((style & SWT.MULTI) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) {
5899                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5900                         TreeItem [] items = new TreeItem [10];
5901                         TVITEM tvItem = new TVITEM ();
5902                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
5903                         int count = getSelection (hItem, tvItem, items, 0, 10, false, true);
5904                         if (count == 0) return 0;
5905                         POINT mousePos = new POINT ();
5906                         OS.POINTSTOPOINT (mousePos, OS.GetMessagePos ());
5907                         OS.MapWindowPoints (0, handle, mousePos, 1);
5908                         RECT clientRect = new RECT ();
5909                         OS.GetClientRect(handle, clientRect);
5910                         RECT rect = items [0].getBounds (0, true, true, false);
5911                         if ((style & SWT.FULL_SELECTION) != 0) {
5912                                 int width = DRAG_IMAGE_SIZE;
5913                                 rect.left = Math.max (clientRect.left, mousePos.x - width / 2);
5914                                 if (clientRect.right > rect.left + width) {
5915                                         rect.right = rect.left + width;
5916                                 } else {
5917                                         rect.right = clientRect.right;
5918                                         rect.left = Math.max (clientRect.left, rect.right - width);
5919                                 }
5920                         } else {
5921                                 rect.left = Math.max (rect.left, clientRect.left);
5922                                 rect.right = Math.min (rect.right, clientRect.right);
5923                         }
5924                         long hRgn = OS.CreateRectRgn (rect.left, rect.top, rect.right, rect.bottom);
5925                         for (int i = 1; i < count; i++) {
5926                                 if (rect.bottom - rect.top > DRAG_IMAGE_SIZE) break;
5927                                 if (rect.bottom > clientRect.bottom) break;
5928                                 RECT itemRect = items[i].getBounds (0, true, true, false);
5929                                 if ((style & SWT.FULL_SELECTION) != 0) {
5930                                         itemRect.left = rect.left;
5931                                         itemRect.right = rect.right;
5932                                 } else {
5933                                         itemRect.left = Math.max (itemRect.left, clientRect.left);
5934                                         itemRect.right = Math.min (itemRect.right, clientRect.right);
5935                                 }
5936                                 long rectRgn = OS.CreateRectRgn (itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
5937                                 OS.CombineRgn (hRgn, hRgn, rectRgn, OS.RGN_OR);
5938                                 OS.DeleteObject (rectRgn);
5939                                 rect.bottom = itemRect.bottom;
5940
5941                         }
5942                         OS.GetRgnBox (hRgn, rect);
5943
5944                         /* Create resources */
5945                         long hdc = OS.GetDC (handle);
5946                         long memHdc = OS.CreateCompatibleDC (hdc);
5947                         BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
5948                         bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
5949                         bmiHeader.biWidth = rect.right - rect.left;
5950                         bmiHeader.biHeight = -(rect.bottom - rect.top);
5951                         bmiHeader.biPlanes = 1;
5952                         bmiHeader.biBitCount = 32;
5953                         bmiHeader.biCompression = OS.BI_RGB;
5954                         byte [] bmi = new byte [BITMAPINFOHEADER.sizeof];
5955                         OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
5956                         long [] pBits = new long [1];
5957                         long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
5958                         if (memDib == 0) error (SWT.ERROR_NO_HANDLES);
5959                         long oldMemBitmap = OS.SelectObject (memHdc, memDib);
5960                         int colorKey = 0x0000FD;
5961                         POINT pt = new POINT ();
5962                         OS.SetWindowOrgEx (memHdc, rect.left, rect.top, pt);
5963                         OS.FillRect (memHdc, rect, findBrush (colorKey, OS.BS_SOLID));
5964                         OS.OffsetRgn (hRgn, -rect.left, -rect.top);
5965                         OS.SelectClipRgn (memHdc, hRgn);
5966                         OS.PrintWindow (handle, memHdc, 0);
5967                         OS.SetWindowOrgEx (memHdc, pt.x, pt.y, null);
5968                         OS.SelectObject (memHdc, oldMemBitmap);
5969                         OS.DeleteDC (memHdc);
5970                         OS.ReleaseDC (0, hdc);
5971                         OS.DeleteObject (hRgn);
5972
5973                         SHDRAGIMAGE shdi = new SHDRAGIMAGE ();
5974                         shdi.hbmpDragImage = memDib;
5975                         shdi.crColorKey = colorKey;
5976                         shdi.sizeDragImage.cx = bmiHeader.biWidth;
5977                         shdi.sizeDragImage.cy = -bmiHeader.biHeight;
5978                         shdi.ptOffset.x = mousePos.x - rect.left;
5979                         shdi.ptOffset.y = mousePos.y - rect.top;
5980                         if ((style & SWT.MIRRORED) != 0) {
5981                                 shdi.ptOffset.x = shdi.sizeDragImage.cx - shdi.ptOffset.x;
5982                         }
5983                         OS.MoveMemory (lParam, shdi, SHDRAGIMAGE.sizeof);
5984                         return 1;
5985                 }
5986         }
5987         return super.windowProc (hwnd, msg, wParam, lParam);
5988 }
5989
5990 @Override
5991 LRESULT WM_CHAR (long wParam, long lParam) {
5992         LRESULT result = super.WM_CHAR (wParam, lParam);
5993         if (result != null) return result;
5994         /*
5995         * Feature in Windows.  The tree control beeps
5996         * in WM_CHAR when the search for the item that
5997         * matches the key stroke fails.  This is the
5998         * standard tree behavior but is unexpected when
5999         * the key that was typed was ESC, CR or SPACE.
6000         * The fix is to avoid calling the tree window
6001         * proc in these cases.
6002         */
6003         switch ((int)wParam) {
6004                 case ' ': {
6005                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6006                         if (hItem != 0) {
6007                                 hAnchor = hItem;
6008                                 OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
6009                                 TVITEM tvItem = new TVITEM ();
6010                                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE | OS.TVIF_PARAM;
6011                                 tvItem.hItem = hItem;
6012                                 if ((style & SWT.CHECK) != 0) {
6013                                         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6014                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6015                                         int state = tvItem.state >> 12;
6016                                         if ((state & 0x1) != 0) {
6017                                                 state++;
6018                                         } else  {
6019                                                 --state;
6020                                         }
6021                                         tvItem.state = state << 12;
6022                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6023                                         long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, hItem, 0);
6024                                         OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6025                                 }
6026                                 tvItem.stateMask = OS.TVIS_SELECTED;
6027                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6028                                 if ((style & SWT.MULTI) != 0 && OS.GetKeyState (OS.VK_CONTROL) < 0) {
6029                                         if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
6030                                                 tvItem.state &= ~OS.TVIS_SELECTED;
6031                                         } else {
6032                                                 tvItem.state |= OS.TVIS_SELECTED;
6033                                         }
6034                                 } else {
6035                                         tvItem.state |= OS.TVIS_SELECTED;
6036                                 }
6037                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6038                                 TreeItem item = _getItem (hItem, (int)tvItem.lParam);
6039                                 Event event = new Event ();
6040                                 event.item = item;
6041                                 sendSelectionEvent (SWT.Selection, event, false);
6042                                 if ((style & SWT.CHECK) != 0) {
6043                                         event = new Event ();
6044                                         event.item = item;
6045                                         event.detail = SWT.CHECK;
6046                                         sendSelectionEvent (SWT.Selection, event, false);
6047                                 }
6048                         }
6049                         return LRESULT.ZERO;
6050                 }
6051                 case SWT.CR: {
6052                         /*
6053                         * Feature in Windows.  Windows sends NM_RETURN from WM_KEYDOWN
6054                         * instead of using WM_CHAR.  This means that application code
6055                         * that expects to consume the key press and therefore avoid a
6056                         * SWT.DefaultSelection event from WM_CHAR will fail.  The fix
6057                         * is to implement SWT.DefaultSelection in WM_CHAR instead of
6058                         * using NM_RETURN.
6059                         */
6060                         Event event = new Event ();
6061                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6062                         if (hItem != 0) event.item = _getItem (hItem);
6063                         sendSelectionEvent (SWT.DefaultSelection, event, false);
6064                         return LRESULT.ZERO;
6065                 }
6066                 case SWT.ESC:
6067                         return LRESULT.ZERO;
6068         }
6069         return result;
6070 }
6071
6072 @Override
6073 LRESULT WM_ERASEBKGND (long wParam, long lParam) {
6074         LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
6075         if ((style & SWT.DOUBLE_BUFFERED) != 0) return LRESULT.ONE;
6076         if (findImageControl () != null) return LRESULT.ONE;
6077         return result;
6078 }
6079
6080 @Override
6081 LRESULT WM_GETOBJECT (long wParam, long lParam) {
6082         /*
6083         * Ensure that there is an accessible object created for this
6084         * control because support for checked item and tree column
6085         * accessibility is temporarily implemented in the accessibility
6086         * package.
6087         */
6088         if ((style & SWT.CHECK) != 0 || hwndParent != 0) {
6089                 if (accessible == null) accessible = new_Accessible (this);
6090         }
6091         return super.WM_GETOBJECT (wParam, lParam);
6092 }
6093
6094 @Override
6095 LRESULT WM_HSCROLL (long wParam, long lParam) {
6096         boolean fixScroll = false;
6097         if ((style & SWT.DOUBLE_BUFFERED) != 0) {
6098                 fixScroll = (style & SWT.VIRTUAL) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem);
6099         }
6100         if (fixScroll) {
6101                 style &= ~SWT.DOUBLE_BUFFERED;
6102                 if (explorerTheme) {
6103                         OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, 0);
6104                 }
6105         }
6106         LRESULT result = super.WM_HSCROLL (wParam, lParam);
6107         if (fixScroll) {
6108                 style |= SWT.DOUBLE_BUFFERED;
6109                 if (explorerTheme) {
6110                         OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, OS.TVS_EX_DOUBLEBUFFER);
6111                 }
6112         }
6113         if (result != null) return result;
6114         return result;
6115 }
6116
6117 @Override
6118 LRESULT WM_KEYDOWN (long wParam, long lParam) {
6119         LRESULT result = super.WM_KEYDOWN (wParam, lParam);
6120         if (result != null) return result;
6121         switch ((int)wParam) {
6122                 case OS.VK_LEFT:
6123                 case OS.VK_RIGHT:
6124                         /*
6125                         * Bug in Windows. The behavior for the left and right keys is not
6126                         * changed if the orientation changes after the control was created.
6127                         * The fix is to replace VK_LEFT by VK_RIGHT and VK_RIGHT by VK_LEFT
6128                         * when the current orientation differs from the orientation used to
6129                         * create the control.
6130                         */
6131                         boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
6132                         if (isRTL != createdAsRTL) {
6133                                 long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam == OS.VK_RIGHT ? OS.VK_LEFT : OS.VK_RIGHT, lParam);
6134                                 return new LRESULT (code);
6135                         }
6136                         break;
6137                 case OS.VK_SPACE:
6138                         /*
6139                         * Ensure that the window proc does not process VK_SPACE
6140                         * so that it can be handled in WM_CHAR.  This allows the
6141                         * application to cancel an operation that is normally
6142                         * performed in WM_KEYDOWN from WM_CHAR.
6143                         */
6144                         return LRESULT.ZERO;
6145                 case OS.VK_ADD:
6146                         if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
6147                                 if (hwndHeader != 0) {
6148                                         TreeColumn [] newColumns = new TreeColumn [columnCount];
6149                                         System.arraycopy (columns, 0, newColumns, 0, columnCount);
6150                                         for (int i=0; i<columnCount; i++) {
6151                                                 TreeColumn column = newColumns [i];
6152                                                 if (!column.isDisposed () && column.getResizable ()) {
6153                                                         column.pack ();
6154                                                 }
6155                                         }
6156                                 }
6157                         }
6158                         break;
6159                 case OS.VK_UP:
6160                 case OS.VK_DOWN:
6161                 case OS.VK_PRIOR:
6162                 case OS.VK_NEXT:
6163                 case OS.VK_HOME:
6164                 case OS.VK_END: {
6165                         OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
6166                         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6167                         if ((style & SWT.SINGLE) != 0) break;
6168                         if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
6169                                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6170                                 if (hItem != 0) {
6171                                         if (hAnchor == 0) hAnchor = hItem;
6172                                         ignoreSelect = ignoreDeselect = true;
6173                                         long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
6174                                         ignoreSelect = ignoreDeselect = false;
6175                                         long hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6176                                         TVITEM tvItem = new TVITEM ();
6177                                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6178                                         tvItem.stateMask = OS.TVIS_SELECTED;
6179                                         long hDeselectItem = hItem;
6180                                         RECT rect1 = new RECT ();
6181                                         if (!OS.TreeView_GetItemRect (handle, hAnchor, rect1, false)) {
6182                                                 hAnchor = hItem;
6183                                                 OS.TreeView_GetItemRect (handle, hAnchor, rect1, false);
6184                                         }
6185                                         RECT rect2 = new RECT ();
6186                                         OS.TreeView_GetItemRect (handle, hDeselectItem, rect2, false);
6187                                         int flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
6188                                         while (hDeselectItem != hAnchor) {
6189                                                 tvItem.hItem = hDeselectItem;
6190                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6191                                                 hDeselectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hDeselectItem);
6192                                         }
6193                                         long hSelectItem = hAnchor;
6194                                         OS.TreeView_GetItemRect (handle, hNewItem, rect1, false);
6195                                         OS.TreeView_GetItemRect (handle, hSelectItem, rect2, false);
6196                                         tvItem.state = OS.TVIS_SELECTED;
6197                                         flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
6198                                         while (hSelectItem != hNewItem) {
6199                                                 tvItem.hItem = hSelectItem;
6200                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6201                                                 hSelectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hSelectItem);
6202                                         }
6203                                         tvItem.hItem = hNewItem;
6204                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6205                                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6206                                         tvItem.hItem = hNewItem;
6207                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6208                                         Event event = new Event ();
6209                                         event.item = _getItem (hNewItem, (int)tvItem.lParam);
6210                                         sendSelectionEvent (SWT.Selection, event, false);
6211                                         return new LRESULT (code);
6212                                 }
6213                         }
6214                         if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
6215                                 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6216                                 if (hItem != 0) {
6217                                         TVITEM tvItem = new TVITEM ();
6218                                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6219                                         tvItem.stateMask = OS.TVIS_SELECTED;
6220                                         tvItem.hItem = hItem;
6221                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6222                                         boolean oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6223                                         long hNewItem = 0;
6224                                         switch ((int)wParam) {
6225                                                 case OS.VK_UP:
6226                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUSVISIBLE, hItem);
6227                                                         break;
6228                                                 case OS.VK_DOWN:
6229                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
6230                                                         break;
6231                                                 case OS.VK_HOME:
6232                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
6233                                                         break;
6234                                                 case OS.VK_PRIOR:
6235                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6236                                                         if (hNewItem == hItem) {
6237                                                                 OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEUP, 0);
6238                                                                 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6239                                                         }
6240                                                         break;
6241                                                 case OS.VK_NEXT:
6242                                                         RECT rect = new RECT (), clientRect = new RECT ();
6243                                                         OS.GetClientRect (handle, clientRect);
6244                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6245                                                         do {
6246                                                                 long hVisible = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNewItem);
6247                                                                 if (hVisible == 0) break;
6248                                                                 if (!OS.TreeView_GetItemRect (handle, hVisible, rect, false)) break;
6249                                                                 if (rect.bottom > clientRect.bottom) break;
6250                                                                 if ((hNewItem = hVisible) == hItem) {
6251                                                                         OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEDOWN, 0);
6252                                                                 }
6253                                                         } while (hNewItem != 0);
6254                                                         break;
6255                                                 case OS.VK_END:
6256                                                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
6257                                                         break;
6258                                         }
6259                                         if (hNewItem != 0) {
6260                                                 OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hNewItem);
6261                                                 tvItem.hItem = hNewItem;
6262                                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6263                                                 boolean newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6264                                                 boolean redraw = !newSelected && getDrawing () && OS.IsWindowVisible (handle);
6265                                                 if (redraw) {
6266                                                         OS.UpdateWindow (handle);
6267                                                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
6268                                                 }
6269                                                 hSelect = hNewItem;
6270                                                 ignoreSelect = true;
6271                                                 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
6272                                                 ignoreSelect = false;
6273                                                 hSelect = 0;
6274                                                 if (oldSelected) {
6275                                                         tvItem.state = OS.TVIS_SELECTED;
6276                                                         tvItem.hItem = hItem;
6277                                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6278                                                 }
6279                                                 if (!newSelected) {
6280                                                         tvItem.state = 0;
6281                                                         tvItem.hItem = hNewItem;
6282                                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6283                                                 }
6284                                                 if (redraw) {
6285                                                         RECT rect1 = new RECT (), rect2 = new RECT ();
6286                                                         OS.TreeView_GetItemRect (handle, hItem, rect1, false);
6287                                                         OS.TreeView_GetItemRect (handle, hNewItem, rect2, false);
6288                                                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
6289                                                         OS.InvalidateRect (handle, rect1, true);
6290                                                         OS.InvalidateRect (handle, rect2, true);
6291                                                         OS.UpdateWindow (handle);
6292                                                 }
6293                                                 return LRESULT.ZERO;
6294                                         }
6295                                 }
6296                         }
6297                         long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
6298                         hAnchor = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6299                         return new LRESULT (code);
6300                 }
6301         }
6302         return result;
6303 }
6304
6305 @Override
6306 LRESULT WM_KILLFOCUS (long wParam, long lParam) {
6307         /*
6308         * Bug in Windows.  When a tree item that has an image
6309         * with alpha is expanded or collapsed, the area where
6310         * the image is drawn is not erased before it is drawn.
6311         * This means that the image gets darker each time.
6312         * The fix is to redraw the selection.
6313         *
6314         * Feature in Windows.  When multiple item have
6315         * the TVIS_SELECTED state, Windows redraws only
6316         * the focused item in the color used to show the
6317         * selection when the tree loses or gains focus.
6318         * The fix is to force Windows to redraw the
6319         * selection when focus is gained or lost.
6320         */
6321         boolean redraw = (style & SWT.MULTI) != 0;
6322         if (!redraw && imageList != null) {
6323                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6324                 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
6325                         redraw = true;
6326                 }
6327         }
6328         if (redraw) redrawSelection ();
6329         return super.WM_KILLFOCUS (wParam, lParam);
6330 }
6331
6332 @Override
6333 LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
6334         TVHITTESTINFO lpht = new TVHITTESTINFO ();
6335         lpht.x = OS.GET_X_LPARAM (lParam);
6336         lpht.y = OS.GET_Y_LPARAM (lParam);
6337         OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6338         if (lpht.hItem != 0) {
6339                 if ((style & SWT.CHECK) != 0) {
6340                         if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
6341                                 Display display = this.display;
6342                                 display.captureChanged = false;
6343                                 sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6344                                 if (!sendMouseEvent (SWT.MouseDoubleClick, 1, handle, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
6345                                         if (!display.captureChanged && !isDisposed ()) {
6346                                                 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6347                                         }
6348                                         return LRESULT.ZERO;
6349                                 }
6350                                 if (!display.captureChanged && !isDisposed ()) {
6351                                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6352                                 }
6353                                 OS.SetFocus (handle);
6354                                 TVITEM tvItem = new TVITEM ();
6355                                 tvItem.hItem = lpht.hItem;
6356                                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
6357                                 tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6358                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6359                                 int state = tvItem.state >> 12;
6360                                 if ((state & 0x1) != 0) {
6361                                         state++;
6362                                 } else  {
6363                                         --state;
6364                                 }
6365                                 tvItem.state = state << 12;
6366                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6367                                 long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
6368                                 OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6369                                 Event event = new Event ();
6370                                 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6371                                 event.detail = SWT.CHECK;
6372                                 sendSelectionEvent (SWT.Selection, event, false);
6373                                 return LRESULT.ZERO;
6374                         }
6375                 }
6376         }
6377         LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
6378         if (result == LRESULT.ZERO) return result;
6379         if (lpht.hItem != 0) {
6380                 int flags = OS.TVHT_ONITEM;
6381                 if ((style & SWT.FULL_SELECTION) != 0) {
6382                         flags |= OS.TVHT_ONITEMRIGHT | OS.TVHT_ONITEMINDENT;
6383                 } else {
6384                         if (hooks (SWT.MeasureItem)) {
6385                                 lpht.flags &= ~(OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL);
6386                                 if (hitTestSelection (lpht.hItem, lpht.x, lpht.y)) {
6387                                         lpht.flags |= OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
6388                                 }
6389                         }
6390                 }
6391                 if ((lpht.flags & flags) != 0) {
6392                         Event event = new Event ();
6393                         event.item = _getItem (lpht.hItem);
6394                         sendSelectionEvent (SWT.DefaultSelection, event, false);
6395                 }
6396         }
6397         return result;
6398 }
6399
6400 @Override
6401 LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
6402         /*
6403         * In a multi-select tree, if the user is collapsing a subtree that
6404         * contains selected items, clear the selection from these items and
6405         * issue a selection event.  Only items that are selected and visible
6406         * are cleared.  This code also runs in the case when the white space
6407         * below the last item is selected.
6408         */
6409         TVHITTESTINFO lpht = new TVHITTESTINFO ();
6410         lpht.x = OS.GET_X_LPARAM (lParam);
6411         lpht.y = OS.GET_Y_LPARAM (lParam);
6412         OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6413         if (lpht.hItem == 0 || (lpht.flags & OS.TVHT_ONITEMBUTTON) != 0) {
6414                 Display display = this.display;
6415                 display.captureChanged = false;
6416                 if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6417                         if (!display.captureChanged && !isDisposed ()) {
6418                                 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6419                         }
6420                         return LRESULT.ZERO;
6421                 }
6422                 boolean fixSelection = false, deselected = false;
6423                 long hOldSelection = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6424                 if (lpht.hItem != 0 && (style & SWT.MULTI) != 0) {
6425                         if (hOldSelection != 0) {
6426                                 TVITEM tvItem = new TVITEM ();
6427                                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6428                                 tvItem.hItem = lpht.hItem;
6429                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6430                                 if ((tvItem.state & OS.TVIS_EXPANDED) != 0) {
6431                                         fixSelection = true;
6432                                         tvItem.stateMask = OS.TVIS_SELECTED;
6433                                         long hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, lpht.hItem);
6434                                         while (hNext != 0) {
6435                                                 if (hNext == hAnchor) hAnchor = 0;
6436                                                 tvItem.hItem = hNext;
6437                                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6438                                                 if ((tvItem.state & OS.TVIS_SELECTED) != 0) deselected = true;
6439                                                 tvItem.state = 0;
6440                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6441                                                 long hItem = hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNext);
6442                                                 while (hItem != 0 && hItem != lpht.hItem) {
6443                                                         hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
6444                                                 }
6445                                                 if (hItem == 0) break;
6446                                         }
6447                                 }
6448                         }
6449                 }
6450                 dragStarted = gestureCompleted = false;
6451                 if (fixSelection) {
6452                         hSelect = lpht.hItem;
6453                         ignoreDeselect = ignoreSelect = lockSelection = true;
6454                 }
6455                 long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6456                 /* Bug 225404 */
6457                 if (OS.GetFocus () != handle) OS.SetFocus (handle);
6458                 if (fixSelection) {
6459                         hSelect = 0;
6460                         ignoreDeselect = ignoreSelect = lockSelection = false;
6461                 }
6462                 long hNewSelection = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6463                 if (hOldSelection != hNewSelection) hAnchor = hNewSelection;
6464                 if (dragStarted) {
6465                         if (!display.captureChanged && !isDisposed ()) {
6466                                 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6467                         }
6468                 }
6469                 /*
6470                 * Bug in Windows.  When a tree has no images and an item is
6471                 * expanded or collapsed, for some reason, Windows changes
6472                 * the size of the selection.  When the user expands a tree
6473                 * item, the selection rectangle is made a few pixels larger.
6474                 * When the user collapses an item, the selection rectangle
6475                 * is restored to the original size but the selection is not
6476                 * redrawn, causing pixel corruption.  The fix is to detect
6477                 * this case and redraw the item.
6478                 */
6479                 if ((lpht.flags & OS.TVHT_ONITEMBUTTON) != 0) {
6480                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6481                         if ((bits & OS.TVS_FULLROWSELECT) == 0) {
6482                                 if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) == 0) {
6483                                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6484                                         if (hItem != 0) {
6485                                                 RECT rect = new RECT ();
6486                                                 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
6487                                                         OS.InvalidateRect (handle, rect, true);
6488                                                 }
6489                                         }
6490                                 }
6491                         }
6492                 }
6493                 if (deselected) {
6494                         Event event = new Event ();
6495                         event.item = _getItem (lpht.hItem);
6496                         sendSelectionEvent (SWT.Selection, event, false);
6497                 }
6498                 return new LRESULT (code);
6499         }
6500
6501         /* Look for check/uncheck */
6502         if ((style & SWT.CHECK) != 0) {
6503                 if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
6504                         Display display = this.display;
6505                         display.captureChanged = false;
6506                         if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6507                                 if (!display.captureChanged && !isDisposed ()) {
6508                                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6509                                 }
6510                                 return LRESULT.ZERO;
6511                         }
6512                         if (!display.captureChanged && !isDisposed ()) {
6513                                 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6514                         }
6515                         OS.SetFocus (handle);
6516                         TVITEM tvItem = new TVITEM ();
6517                         tvItem.hItem = lpht.hItem;
6518                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
6519                         tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6520                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6521                         int state = tvItem.state >> 12;
6522                         if ((state & 0x1) != 0) {
6523                                 state++;
6524                         } else  {
6525                                 --state;
6526                         }
6527                         tvItem.state = state << 12;
6528                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6529                         long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
6530                         OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6531                         Event event = new Event ();
6532                         event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6533                         event.detail = SWT.CHECK;
6534                         sendSelectionEvent (SWT.Selection, event, false);
6535                         return LRESULT.ZERO;
6536                 }
6537         }
6538
6539         /*
6540         * Feature in Windows.  When the tree has the style
6541         * TVS_FULLROWSELECT, the background color for the
6542         * entire row is filled when an item is painted,
6543         * drawing on top of any custom drawing.  The fix
6544         * is to emulate TVS_FULLROWSELECT.
6545         */
6546         boolean selected = false;
6547         boolean fakeSelection = false;
6548         if (lpht.hItem != 0) {
6549                 if ((style & SWT.FULL_SELECTION) != 0) {
6550                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6551                         if ((bits & OS.TVS_FULLROWSELECT) == 0) fakeSelection = true;
6552                 } else {
6553                         if (hooks (SWT.MeasureItem)) {
6554                                 selected = hitTestSelection (lpht.hItem, lpht.x, lpht.y);
6555                                 if (selected) {
6556                                         if ((lpht.flags & OS.TVHT_ONITEM) == 0) fakeSelection = true;
6557                                 }
6558                         }
6559                 }
6560         }
6561
6562         /* Process the mouse when an item is not selected */
6563         if (!selected && (style & SWT.FULL_SELECTION) == 0) {
6564                 if ((lpht.flags & OS.TVHT_ONITEM) == 0) {
6565                         Display display = this.display;
6566                         display.captureChanged = false;
6567                         if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6568                                 if (!display.captureChanged && !isDisposed ()) {
6569                                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6570                                 }
6571                                 return LRESULT.ZERO;
6572                         }
6573                         long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6574                         /* Bug 225404 */
6575                         if (OS.GetFocus () != handle) OS.SetFocus (handle);
6576                         if (!display.captureChanged && !isDisposed ()) {
6577                                 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6578                         }
6579                         return new LRESULT (code);
6580                 }
6581         }
6582
6583         /* Get the selected state of the item under the mouse */
6584         TVITEM tvItem = new TVITEM ();
6585         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6586         tvItem.stateMask = OS.TVIS_SELECTED;
6587         boolean hittestSelected = false;
6588         if ((style & SWT.MULTI) != 0) {
6589                 tvItem.hItem = lpht.hItem;
6590                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6591                 hittestSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6592         }
6593
6594         /* Get the selected state of the last selected item */
6595         long hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6596         if ((style & SWT.MULTI) != 0) {
6597                 tvItem.hItem = hOldItem;
6598                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6599
6600                 /* Check for CONTROL or drag selection */
6601                 if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
6602                         /*
6603                         * Feature in Windows.  When the tree is not drawing focus
6604                         * and the user selects a tree item while the CONTROL key
6605                         * is down, the tree window proc sends WM_UPDATEUISTATE
6606                         * to the top level window, causing controls within the shell
6607                         * to redraw.  When drag detect is enabled, the tree window
6608                         * proc runs a modal loop that allows WM_PAINT messages to be
6609                         * delivered during WM_LBUTTONDOWN.  When WM_SETREDRAW is used
6610                         * to disable drawing for the tree and a WM_PAINT happens for
6611                         * a parent of the tree (or a sibling that overlaps), the parent
6612                         * will draw on top of the tree.  If WM_SETREDRAW is turned back
6613                         * on without redrawing the entire tree, pixel corruption occurs.
6614                         * This case only seems to happen when the tree has been given
6615                         * focus from WM_MOUSEACTIVATE of the shell.  The fix is to
6616                         * force the WM_UPDATEUISTATE to be sent before disabling
6617                         * the drawing.
6618                         *
6619                         * NOTE:  Any redraw of a parent (or sibling) will be dispatched
6620                         * during the modal drag detect loop.  This code only fixes the
6621                         * case where the tree causes a redraw from WM_UPDATEUISTATE.
6622                         * In SWT, the InvalidateRect() that caused the pixel corruption
6623                         * is found in Composite.WM_UPDATEUISTATE().
6624                         */
6625                         int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
6626                         if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
6627                                 OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
6628                         }
6629                         OS.UpdateWindow (handle);
6630                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
6631                 } else {
6632                         deselectAll ();
6633                 }
6634         }
6635
6636         /* Do the selection */
6637         Display display = this.display;
6638         display.captureChanged = false;
6639         if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6640                 if (!display.captureChanged && !isDisposed ()) {
6641                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6642                 }
6643                 return LRESULT.ZERO;
6644         }
6645         hSelect = lpht.hItem;
6646         dragStarted = gestureCompleted = false;
6647         ignoreDeselect = ignoreSelect = true;
6648         long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6649         /* Bug 225404 */
6650         if (OS.GetFocus () != handle) OS.SetFocus (handle);
6651         long hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6652         if (fakeSelection) {
6653                 if (hOldItem == 0 || (hNewItem == hOldItem && lpht.hItem != hOldItem)) {
6654                         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
6655                         hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6656                 }
6657                 if (!dragStarted && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
6658                         dragStarted = dragDetect (handle, lpht.x, lpht.y, false, null, null);
6659                 }
6660         }
6661         ignoreDeselect = ignoreSelect = false;
6662         hSelect = 0;
6663         if (dragStarted) {
6664                 if (!display.captureChanged && !isDisposed ()) {
6665                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6666                 }
6667         }
6668
6669         /*
6670         * Feature in Windows.  When the old and new focused item
6671         * are the same, Windows does not check to make sure that
6672         * the item is actually selected, not just focused.  The
6673         * fix is to force the item to draw selected by setting
6674         * the state mask.  This is only necessary when the tree
6675         * is single select.
6676         */
6677         if ((style & SWT.SINGLE) != 0) {
6678                 if (hOldItem == hNewItem) {
6679                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6680                         tvItem.state = OS.TVIS_SELECTED;
6681                         tvItem.stateMask = OS.TVIS_SELECTED;
6682                         tvItem.hItem = hNewItem;
6683                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6684                 }
6685         }
6686
6687         /* Reselect the last item that was unselected */
6688         if ((style & SWT.MULTI) != 0) {
6689
6690                 /* Check for CONTROL and reselect the last item */
6691                 if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
6692                         if (hOldItem == hNewItem && hOldItem == lpht.hItem) {
6693                                 if ((wParam & OS.MK_CONTROL) != 0) {
6694                                         tvItem.state ^= OS.TVIS_SELECTED;
6695                                         if (dragStarted) tvItem.state = OS.TVIS_SELECTED;
6696                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6697                                 }
6698                         } else {
6699                                 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
6700                                         tvItem.state = OS.TVIS_SELECTED;
6701                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6702                                 }
6703                                 if ((wParam & OS.MK_CONTROL) != 0 && !dragStarted) {
6704                                         if (hittestSelected) {
6705                                                 tvItem.state = 0;
6706                                                 tvItem.hItem = lpht.hItem;
6707                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6708                                         }
6709                                 }
6710                         }
6711                         RECT rect1 = new RECT (), rect2 = new RECT ();
6712                         OS.TreeView_GetItemRect (handle, hOldItem, rect1, false);
6713                         OS.TreeView_GetItemRect (handle, hNewItem, rect2, false);
6714                         OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
6715                         OS.InvalidateRect (handle, rect1, true);
6716                         OS.InvalidateRect (handle, rect2, true);
6717                         OS.UpdateWindow (handle);
6718                 }
6719
6720                 /* Check for SHIFT or normal select and deselect/reselect items */
6721                 if ((wParam & OS.MK_CONTROL) == 0) {
6722                         if (!hittestSelected || !dragStarted) {
6723                                 tvItem.state = 0;
6724                                 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
6725                                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
6726                                 if ((style & SWT.VIRTUAL) != 0) {
6727                                         long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
6728                                         deselect (hItem, tvItem, hNewItem);
6729                                 } else {
6730                                         for (int i=0; i<items.length; i++) {
6731                                                 TreeItem item = items [i];
6732                                                 if (item != null && item.handle != hNewItem) {
6733                                                         tvItem.hItem = item.handle;
6734                                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6735                                                 }
6736                                         }
6737                                 }
6738                                 tvItem.hItem = hNewItem;
6739                                 tvItem.state = OS.TVIS_SELECTED;
6740                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6741                                 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
6742                                 if ((wParam & OS.MK_SHIFT) != 0) {
6743                                         RECT rect1 = new RECT ();
6744                                         if (hAnchor == 0) hAnchor = hNewItem;
6745                                         if (OS.TreeView_GetItemRect (handle, hAnchor, rect1, false)) {
6746                                                 RECT rect2 = new RECT ();
6747                                                 if (OS.TreeView_GetItemRect (handle, hNewItem, rect2, false)) {
6748                                                         int flags = rect1.top < rect2.top ? OS.TVGN_NEXTVISIBLE : OS.TVGN_PREVIOUSVISIBLE;
6749                                                         tvItem.state = OS.TVIS_SELECTED;
6750                                                         long hItem = tvItem.hItem = hAnchor;
6751                                                         OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6752                                                         while (hItem != hNewItem) {
6753                                                                 tvItem.hItem = hItem;
6754                                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6755                                                                 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hItem);
6756                                                         }
6757                                                 }
6758                                         }
6759                                 }
6760                         }
6761                 }
6762         }
6763         if ((wParam & OS.MK_SHIFT) == 0) hAnchor = hNewItem;
6764
6765         /* Issue notification */
6766         if (!gestureCompleted) {
6767                 tvItem.hItem = hNewItem;
6768                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6769                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6770                 Event event = new Event ();
6771                 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6772                 sendSelectionEvent (SWT.Selection, event, false);
6773         }
6774         gestureCompleted = false;
6775
6776         /*
6777         * Feature in Windows.  Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
6778         * the widget starts a modal loop to determine if the user wants
6779         * to begin a drag/drop operation or marquee select.  Unfortunately,
6780         * this modal loop eats the corresponding mouse up.  The fix is to
6781         * detect the cases when the modal loop has eaten the mouse up and
6782         * issue a fake mouse up.
6783         */
6784         if (dragStarted) {
6785                 sendDragEvent (1, OS.GET_X_LPARAM (lParam), OS.GET_Y_LPARAM (lParam));
6786         } else {
6787                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6788                 if ((bits & OS.TVS_DISABLEDRAGDROP) == 0) {
6789                         sendMouseEvent (SWT.MouseUp, 1, handle, OS.WM_LBUTTONUP, wParam, lParam);
6790                 }
6791         }
6792         dragStarted = false;
6793         return new LRESULT (code);
6794 }
6795
6796 @Override
6797 LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
6798         Display display = this.display;
6799         LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
6800         if (result != null) return result;
6801         if (itemToolTipHandle != 0) {
6802                 /*
6803                 * Bug in Windows.  On some machines that do not have XBUTTONs,
6804                 * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
6805                 * causing mouse capture to become stuck.  The fix is to test
6806                 * for the extra buttons only when they exist.
6807                 */
6808                 int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
6809                 if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
6810                 if ((wParam & mask) == 0) {
6811                         int x = OS.GET_X_LPARAM (lParam);
6812                         int y = OS.GET_Y_LPARAM (lParam);
6813                         int [] index = new int [1];
6814                         TreeItem [] item = new TreeItem [1];
6815                         RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
6816                         if (findCell (x, y, item, index, cellRect, itemRect)) {
6817                                 /*
6818                                 * Feature in Windows.  When the new tool rectangle is
6819                                 * set using TTM_NEWTOOLRECT and the tooltip is visible,
6820                                 * Windows draws the tooltip right away and the sends
6821                                 * WM_NOTIFY with TTN_SHOW.  This means that the tooltip
6822                                 * shows first at the wrong location and then moves to
6823                                 * the right one.  The fix is to hide the tooltip window.
6824                                 */
6825                                 if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, 0) == 0) {
6826                                         if (OS.IsWindowVisible (itemToolTipHandle)) {
6827                                                 OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6828                                         }
6829                                 }
6830                                 TOOLINFO lpti = new TOOLINFO ();
6831                                 lpti.cbSize = TOOLINFO.sizeof;
6832                                 lpti.hwnd = handle;
6833                                 lpti.uId = handle;
6834                                 lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
6835                                 lpti.left = cellRect [0].left;
6836                                 lpti.top = cellRect [0].top;
6837                                 lpti.right = cellRect [0].right;
6838                                 lpti.bottom = cellRect [0].bottom;
6839                                 OS.SendMessage (itemToolTipHandle, OS.TTM_NEWTOOLRECT, 0, lpti);
6840                         }
6841                 }
6842         }
6843         return result;
6844 }
6845
6846 @Override
6847 LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
6848         LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
6849         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6850         return result;
6851 }
6852
6853 @Override
6854 LRESULT WM_MOVE (long wParam, long lParam) {
6855         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6856         if (ignoreResize) return null;
6857         return super.WM_MOVE (wParam, lParam);
6858 }
6859
6860 @Override
6861 LRESULT WM_RBUTTONDOWN (long wParam, long lParam) {
6862         /*
6863         * Feature in Windows.  The receiver uses WM_RBUTTONDOWN
6864         * to initiate a drag/drop operation depending on how the
6865         * user moves the mouse.  If the user clicks the right button,
6866         * without moving the mouse, the tree consumes the corresponding
6867         * WM_RBUTTONUP.  The fix is to avoid calling the window proc for
6868         * the tree.
6869         */
6870         Display display = this.display;
6871         display.captureChanged = false;
6872         if (!sendMouseEvent (SWT.MouseDown, 3, handle, OS.WM_RBUTTONDOWN, wParam, lParam)) {
6873                 if (!display.captureChanged && !isDisposed ()) {
6874                         if (OS.GetCapture () != handle) OS.SetCapture (handle);
6875                 }
6876                 return LRESULT.ZERO;
6877         }
6878         /*
6879         * This code is intentionally commented.
6880         */
6881 //      if (OS.GetCapture () != handle) OS.SetCapture (handle);
6882         /* Bug 225404 */
6883         if (OS.GetFocus () != handle) OS.SetFocus (handle);
6884
6885         /*
6886         * Feature in Windows.  When the user selects a tree item
6887         * with the right mouse button, the item remains selected
6888         * only as long as the user does not release or move the
6889         * mouse.  As soon as this happens, the selection snaps
6890         * back to the previous selection.  This behavior can be
6891         * observed in the Explorer but is not instantly apparent
6892         * because the Explorer explicitly sets the selection when
6893         * the user chooses a menu item.  If the user cancels the
6894         * menu, the selection snaps back.  The fix is to avoid
6895         * calling the window proc and do the selection ourselves.
6896         * This behavior is consistent with the table.
6897         */
6898         TVHITTESTINFO lpht = new TVHITTESTINFO ();
6899         lpht.x = OS.GET_X_LPARAM (lParam);
6900         lpht.y = OS.GET_Y_LPARAM (lParam);
6901         OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6902         if (lpht.hItem != 0) {
6903                 boolean fakeSelection = (style & SWT.FULL_SELECTION) != 0;
6904                 if (!fakeSelection) {
6905                         if (hooks (SWT.MeasureItem)) {
6906                                 fakeSelection = hitTestSelection (lpht.hItem, lpht.x, lpht.y);
6907                         } else {
6908                                 int flags = OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
6909                                 fakeSelection = (lpht.flags & flags) != 0;
6910                         }
6911                 }
6912                 if (fakeSelection) {
6913                         if ((wParam & (OS.MK_CONTROL | OS.MK_SHIFT)) == 0) {
6914                                 TVITEM tvItem = new TVITEM ();
6915                                 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6916                                 tvItem.stateMask = OS.TVIS_SELECTED;
6917                                 tvItem.hItem = lpht.hItem;
6918                                 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6919                                 if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
6920                                         ignoreSelect = true;
6921                                         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, 0);
6922                                         ignoreSelect = false;
6923                                         OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
6924                                 }
6925                         }
6926                 }
6927         }
6928         return LRESULT.ZERO;
6929 }
6930
6931 @Override
6932 LRESULT WM_PAINT (long wParam, long lParam) {
6933         if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
6934
6935         if (shrink && !ignoreShrink && items != null) {
6936                 /* Resize the item array to fit the last item */
6937                 int count = items.length - 1;
6938                 while (count >= 0) {
6939                         if (items [count] != null) break;
6940                         --count;
6941                 }
6942                 count++;
6943                 if (items.length > 4 && items.length - count > 3) {
6944                         int length = Math.max (4, (count + 3) / 4 * 4);
6945                         TreeItem [] newItems = new TreeItem [length];
6946                         System.arraycopy (items, 0, newItems, 0, count);
6947                         items = newItems;
6948                 }
6949                 shrink = false;
6950         }
6951         if ((style & SWT.DOUBLE_BUFFERED) != 0 || findImageControl () != null) {
6952                 boolean doubleBuffer = true;
6953                 if (explorerTheme) {
6954                         int exStyle = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
6955                         if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) doubleBuffer = false;
6956                 }
6957                 if (doubleBuffer) {
6958                         GC gc = null;
6959                         long paintDC = 0;
6960                         PAINTSTRUCT ps = new PAINTSTRUCT ();
6961                         boolean hooksPaint = hooks (SWT.Paint) || filters (SWT.Paint);
6962                         if (hooksPaint) {
6963                                 GCData data = new GCData ();
6964                                 data.ps = ps;
6965                                 data.hwnd = handle;
6966                                 gc = GC.win32_new (this, data);
6967                                 paintDC = gc.handle;
6968                         } else {
6969                                 paintDC = OS.BeginPaint (handle, ps);
6970                         }
6971                         int width = ps.right - ps.left;
6972                         int height = ps.bottom - ps.top;
6973                         if (width != 0 && height != 0) {
6974                                 long hDC = OS.CreateCompatibleDC (paintDC);
6975                                 POINT lpPoint1 = new POINT (), lpPoint2 = new POINT ();
6976                                 OS.SetWindowOrgEx (hDC, ps.left, ps.top, lpPoint1);
6977                                 OS.SetBrushOrgEx (hDC, ps.left, ps.top, lpPoint2);
6978                                 long hBitmap = OS.CreateCompatibleBitmap (paintDC, width, height);
6979                                 long hOldBitmap = OS.SelectObject (hDC, hBitmap);
6980                                 RECT rect = new RECT ();
6981                                 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
6982                                 drawBackground (hDC, rect);
6983                                 callWindowProc (handle, OS.WM_PAINT, hDC, 0);
6984                                 OS.SetWindowOrgEx (hDC, lpPoint1.x, lpPoint1.y, null);
6985                                 OS.SetBrushOrgEx (hDC, lpPoint2.x, lpPoint2.y, null);
6986                                 OS.BitBlt (paintDC, ps.left, ps.top, width, height, hDC, 0, 0, OS.SRCCOPY);
6987                                 OS.SelectObject (hDC, hOldBitmap);
6988                                 OS.DeleteObject (hBitmap);
6989                                 OS.DeleteObject (hDC);
6990                                 if (hooksPaint) {
6991                                         Event event = new Event ();
6992                                         event.gc = gc;
6993                                         event.setBoundsInPixels(new Rectangle(ps.left, ps.top, ps.right - ps.left, ps.bottom - ps.top));
6994                                         sendEvent (SWT.Paint, event);
6995                                         // widget could be disposed at this point
6996                                         event.gc = null;
6997                                 }
6998                         }
6999                         if (hooksPaint) {
7000                                 gc.dispose ();
7001                         } else {
7002                                 OS.EndPaint (handle, ps);
7003                         }
7004                         return LRESULT.ZERO;
7005                 }
7006         }
7007         return super.WM_PAINT (wParam, lParam);
7008 }
7009
7010 @Override
7011 LRESULT WM_SETCURSOR (long wParam, long lParam) {
7012         LRESULT result = super.WM_SETCURSOR (wParam, lParam);
7013         if (result != null) return result;
7014
7015         /*
7016         * Feature in Windows. On Windows 7, the tree control show the
7017         * hand cursor when the mouse is over an item.  This is the
7018         * correct Windows 7 behavior but not correct for SWT. The fix
7019         * is to always ensure a cursor is set.
7020         */
7021         if (OS.WIN32_VERSION >= OS.VERSION (6, 1)) {
7022                 if (wParam == handle) {
7023                         int hitTest = (short) OS.LOWORD (lParam);
7024                         if (hitTest == OS.HTCLIENT) {
7025                                 OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
7026                                 return LRESULT.ONE;
7027                         }
7028                 }
7029         }
7030         return null;
7031 }
7032
7033 @Override
7034 LRESULT WM_SETFOCUS (long wParam, long lParam) {
7035         /*
7036         * Bug in Windows.  When a tree item that has an image
7037         * with alpha is expanded or collapsed, the area where
7038         * the image is drawn is not erased before it is drawn.
7039         * This means that the image gets darker each time.
7040         * The fix is to redraw the selection.
7041         *
7042         * Feature in Windows.  When multiple item have
7043         * the TVIS_SELECTED state, Windows redraws only
7044         * the focused item in the color used to show the
7045         * selection when the tree loses or gains focus.
7046         * The fix is to force Windows to redraw the
7047         * selection when focus is gained or lost.
7048         */
7049         boolean redraw = (style & SWT.MULTI) != 0;
7050         if (!redraw && imageList != null) {
7051                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7052                 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
7053                         redraw = true;
7054                 }
7055         }
7056         if (redraw) redrawSelection ();
7057         return super.WM_SETFOCUS (wParam, lParam);
7058 }
7059
7060 @Override
7061 LRESULT WM_SETFONT (long wParam, long lParam) {
7062         LRESULT result = super.WM_SETFONT (wParam, lParam);
7063         if (result != null) return result;
7064         if (hwndHeader != 0) {
7065                 /*
7066                 * Bug in Windows.  When a header has a sort indicator
7067                 * triangle, Windows resizes the indicator based on the
7068                 * size of the n-1th font.  The fix is to always make
7069                 * the n-1th font be the default.  This makes the sort
7070                 * indicator always be the default size.
7071                 */
7072                 OS.SendMessage (hwndHeader, OS.WM_SETFONT, 0, lParam);
7073                 OS.SendMessage (hwndHeader, OS.WM_SETFONT, wParam, lParam);
7074         }
7075         if (itemToolTipHandle != 0) {
7076                 OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7077                 OS.SendMessage (itemToolTipHandle, OS.WM_SETFONT, wParam, lParam);
7078         }
7079         if (headerToolTipHandle != 0) {
7080                 OS.SendMessage (headerToolTipHandle, OS.WM_SETFONT, wParam, lParam);
7081                 updateHeaderToolTips ();
7082         }
7083         return result;
7084 }
7085
7086 @Override
7087 LRESULT WM_SETREDRAW (long wParam, long lParam) {
7088         LRESULT result = super.WM_SETREDRAW (wParam, lParam);
7089         if (result != null) return result;
7090         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7091         /*
7092         * Bug in Windows.  Under certain circumstances, when
7093         * WM_SETREDRAW is used to turn off drawing and then
7094         * TVM_GETITEMRECT is sent to get the bounds of an item
7095         * that is not inside the client area, Windows segment
7096         * faults.  The fix is to call the default window proc
7097         * rather than the default tree proc.
7098         *
7099         * NOTE:  This problem is intermittent and happens on
7100         * Windows Vista running under the theme manager.
7101         */
7102         long code = OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
7103         return code == 0 ? LRESULT.ZERO : new LRESULT (code);
7104 }
7105
7106 @Override
7107 LRESULT WM_SIZE (long wParam, long lParam) {
7108         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7109         /*
7110         * Bug in Windows.  When TVS_NOHSCROLL is set when the
7111         * size of the tree is zero, the scroll bar is shown the
7112         * next time the tree resizes.  The fix is to hide the
7113         * scroll bar every time the tree is resized.
7114         */
7115         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7116         if ((bits & OS.TVS_NOHSCROLL) != 0) {
7117                 OS.ShowScrollBar (handle, OS.SB_HORZ, false);
7118         }
7119         /*
7120         * Bug in Windows.  On Vista, when the Explorer theme
7121         * is used with a full selection tree, when the tree
7122         * is resized to be smaller, the rounded right edge
7123         * of the selected items is not drawn.  The fix is the
7124         * redraw the entire tree.
7125         */
7126         if (explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
7127                 OS.InvalidateRect (handle, null, false);
7128         }
7129         if (ignoreResize) return null;
7130         return super.WM_SIZE (wParam, lParam);
7131 }
7132
7133 @Override
7134 LRESULT WM_SYSCOLORCHANGE (long wParam, long lParam) {
7135         LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
7136         if (result != null) return result;
7137         /*
7138         * Bug in Windows.  When the tree is using the explorer
7139         * theme, it does not use COLOR_WINDOW_TEXT for the
7140         * default foreground color.  The fix is to explicitly
7141         * set the foreground.
7142         */
7143         if (explorerTheme) {
7144                 if (foreground == -1) setForegroundPixel (-1);
7145         }
7146         if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
7147         return result;
7148 }
7149
7150 @Override
7151 LRESULT WM_VSCROLL (long wParam, long lParam) {
7152         boolean fixScroll = false;
7153         if ((style & SWT.DOUBLE_BUFFERED) != 0) {
7154                 int code = OS.LOWORD (wParam);
7155                 switch (code) {
7156                         case OS.SB_TOP:
7157                         case OS.SB_BOTTOM:
7158                         case OS.SB_LINEDOWN:
7159                         case OS.SB_LINEUP:
7160                         case OS.SB_PAGEDOWN:
7161                         case OS.SB_PAGEUP:
7162                                 fixScroll = (style & SWT.VIRTUAL) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem);
7163                                 break;
7164                 }
7165         }
7166         if (fixScroll) {
7167                 style &= ~SWT.DOUBLE_BUFFERED;
7168                 if (explorerTheme) {
7169                         OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, 0);
7170                 }
7171         }
7172         LRESULT result = super.WM_VSCROLL (wParam, lParam);
7173         if (fixScroll) {
7174                 style |= SWT.DOUBLE_BUFFERED;
7175                 if (explorerTheme) {
7176                         OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, OS.TVS_EX_DOUBLEBUFFER);
7177                 }
7178         }
7179         if (result != null) return result;
7180         return result;
7181 }
7182
7183 @Override
7184 LRESULT WM_TIMER (long wParam, long lParam) {
7185         LRESULT result = super.WM_TIMER (wParam, lParam);
7186         if (result != null) return result;
7187
7188         /* Bug in Windows. When the expandos are visible (or in process of fading away)
7189          * and the tree control is hidden the animation timer does not stop calling the
7190          * window proc till the tree is visible again. This can cause performance problems
7191          * specially in cases there the application has several tree controls in this state.
7192          * The fix is to detect a timer that repeats itself several times when the control
7193          * is not visible and stop it. The timer is stopped by sending a fake mouse move event.
7194          *
7195          * Note: Just killing the timer could cause some internal clean up task related to the
7196          * animation not to run.
7197          */
7198         long bits = OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
7199         if ((bits & OS.TVS_EX_FADEINOUTEXPANDOS) != 0) {
7200                 if (!OS.IsWindowVisible (handle)) {
7201                         if (lastTimerID == wParam) {
7202                                 lastTimerCount++;
7203                         } else {
7204                                 lastTimerCount = 0;
7205                         }
7206                         lastTimerID = wParam;
7207                         if (lastTimerCount >= TIMER_MAX_COUNT) {
7208                                 OS.CallWindowProc (TreeProc, handle, OS.WM_MOUSEMOVE, 0, 0);
7209                                 lastTimerID = -1;
7210                                 lastTimerCount = 0;
7211                         }
7212                 } else {
7213                         lastTimerID = -1;
7214                         lastTimerCount = 0;
7215                 }
7216         }
7217         return result;
7218 };
7219
7220 @Override
7221 LRESULT wmColorChild (long wParam, long lParam) {
7222         if (findImageControl () != null) {
7223                 return new LRESULT (OS.GetStockObject (OS.NULL_BRUSH));
7224         }
7225         /*
7226         * Feature in Windows.  Tree controls send WM_CTLCOLOREDIT
7227         * to allow application code to change the default colors.
7228         * This is undocumented and conflicts with TVM_SETTEXTCOLOR
7229         * and TVM_SETBKCOLOR, the documented way to do this.  The
7230         * fix is to ignore WM_CTLCOLOREDIT messages from trees.
7231         */
7232         return null;
7233 }
7234
7235 @Override
7236 LRESULT wmNotify (NMHDR hdr, long wParam, long lParam) {
7237         if (hdr.hwndFrom == itemToolTipHandle) {
7238                 LRESULT result = wmNotifyToolTip (hdr, wParam, lParam);
7239                 if (result != null) return result;
7240         }
7241         if (hdr.hwndFrom == hwndHeader) {
7242                 LRESULT result = wmNotifyHeader (hdr, wParam, lParam);
7243                 if (result != null) return result;
7244         }
7245         return super.wmNotify (hdr, wParam, lParam);
7246 }
7247
7248 @Override
7249 LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
7250         switch (hdr.code) {
7251                 case OS.TVN_GETDISPINFO: {
7252                         NMTVDISPINFO lptvdi = new NMTVDISPINFO ();
7253                         OS.MoveMemory (lptvdi, lParam, NMTVDISPINFO.sizeof);
7254                         if ((style & SWT.VIRTUAL) != 0) {
7255                                 /*
7256                                 * Feature in Windows.  When a new tree item is inserted
7257                                 * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
7258                                 * TVM_INSERTITEM returns and before the item is added to
7259                                 * the items array.  The fix is to check for null.
7260                                 *
7261                                 * NOTE: This only happens on XP with the version 6.00 of
7262                                 * COMCTL32.DLL.
7263                                 */
7264                                 boolean checkVisible = true;
7265                                 /*
7266                                 * When an item is being deleted from a virtual tree, do not
7267                                 * allow the application to provide data for a new item that
7268                                 * becomes visible until the item has been removed from the
7269                                 * items array.  Because arbitrary application code can run
7270                                 * during the callback, the items array might be accessed
7271                                 * in an inconsistent state.  Rather than answering the data
7272                                 * right away, queue a redraw for later.
7273                                 */
7274                                 if (!ignoreShrink) {
7275                                         if (items != null && lptvdi.lParam != -1) {
7276                                                 if (items [(int)lptvdi.lParam] != null && items [(int)lptvdi.lParam].cached) {
7277                                                         checkVisible = false;
7278                                                 }
7279                                         }
7280                                 }
7281                                 if (checkVisible) {
7282                                         if (!getDrawing () || !OS.IsWindowVisible (handle)) break;
7283                                         RECT itemRect = new RECT ();
7284                                         if (!OS.TreeView_GetItemRect (handle, lptvdi.hItem, itemRect, false)) {
7285                                                 break;
7286                                         }
7287                                         RECT rect = new RECT ();
7288                                         OS.GetClientRect (handle, rect);
7289                                         if (!OS.IntersectRect (rect, rect, itemRect)) break;
7290                                         if (ignoreShrink) {
7291                                                 OS.InvalidateRect (handle, rect, true);
7292                                                 break;
7293                                         }
7294                                 }
7295                         }
7296                         if (items == null) break;
7297                         /*
7298                         * Bug in Windows.  If the lParam field of TVITEM
7299                         * is changed during custom draw using TVM_SETITEM,
7300                         * the lItemlParam field of the NMTVCUSTOMDRAW struct
7301                         * is not updated until the next custom draw.  The
7302                         * fix is to query the field from the item instead
7303                         * of using the struct.
7304                         */
7305                         int id = (int)lptvdi.lParam;
7306                         if ((style & SWT.VIRTUAL) != 0) {
7307                                 if (id == -1) {
7308                                         TVITEM tvItem = new TVITEM ();
7309                                         tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
7310                                         tvItem.hItem = lptvdi.hItem;
7311                                         OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
7312                                         id = (int)tvItem.lParam;
7313                                 }
7314                         }
7315                         TreeItem item = _getItem (lptvdi.hItem, id);
7316                         /*
7317                         * Feature in Windows.  When a new tree item is inserted
7318                         * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
7319                         * TVM_INSERTITEM returns and before the item is added to
7320                         * the items array.  The fix is to check for null.
7321                         *
7322                         * NOTE: This only happens on XP with the version 6.00 of
7323                         * COMCTL32.DLL.
7324                         *
7325                         * Feature in Windows.  When TVM_DELETEITEM is called with
7326                         * TVI_ROOT to remove all items from a tree, under certain
7327                         * circumstances, the tree sends TVN_GETDISPINFO for items
7328                         * that are about to be disposed.  The fix is to check for
7329                         * disposed items.
7330                         */
7331                         if (item == null) break;
7332                         if (item.isDisposed ()) break;
7333                         if (!item.cached) {
7334                                 if ((style & SWT.VIRTUAL) != 0) {
7335                                         if (!checkData (item, false)) break;
7336                                 }
7337                                 if (painted) item.cached = true;
7338                         }
7339                         int index = 0;
7340                         if (hwndHeader != 0) {
7341                                 index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
7342                         }
7343                         if ((lptvdi.mask & OS.TVIF_TEXT) != 0) {
7344                                 String string = null;
7345                                 if (index == 0) {
7346                                         string = item.text;
7347                                 } else {
7348                                         String [] strings  = item.strings;
7349                                         if (strings != null) string = strings [index];
7350                                 }
7351                                 if (string != null) {
7352                                         int length = Math.min (string.length() + 1, lptvdi.cchTextMax);
7353                                         char [] buffer = new char [length];
7354                                         string.getChars(0, length - 1, buffer, 0);
7355                                         OS.MoveMemory (lptvdi.pszText, buffer, length * TCHAR.sizeof);
7356                                         lptvdi.cchTextMax = length;
7357                                 }
7358                         }
7359                         if ((lptvdi.mask & (OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE)) != 0) {
7360                                 Image image = null;
7361                                 if (index == 0) {
7362                                         image = item.image;
7363                                 } else {
7364                                         Image [] images  = item.images;
7365                                         if (images != null) image = images [index];
7366                                 }
7367                                 lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
7368                                 if (image != null) {
7369                                         lptvdi.iImage = lptvdi.iSelectedImage = imageIndex (image, index);
7370                                 }
7371                                 if (explorerTheme && OS.IsWindowEnabled (handle)) {
7372                                         if (findImageControl () != null) {
7373                                                 lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
7374                                         }
7375                                 }
7376                         }
7377                         OS.MoveMemory (lParam, lptvdi, NMTVDISPINFO.sizeof);
7378                         break;
7379                 }
7380                 case OS.NM_CUSTOMDRAW: {
7381                         if (hdr.hwndFrom == hwndHeader) break;
7382                         if (hooks (SWT.MeasureItem)) {
7383                                 if (hwndHeader == 0) createParent ();
7384                         }
7385                         if (!customDraw && findImageControl () == null) {
7386                                 if (OS.IsAppThemed ()) {
7387                                         if (sortColumn == null || sortDirection == SWT.NONE) {
7388                                                 break;
7389                                         }
7390                                 }
7391                         }
7392                         NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW ();
7393                         OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof);
7394                         switch (nmcd.dwDrawStage) {
7395                                 case OS.CDDS_PREPAINT: return CDDS_PREPAINT (nmcd, wParam, lParam);
7396                                 case OS.CDDS_ITEMPREPAINT: return CDDS_ITEMPREPAINT (nmcd, wParam, lParam);
7397                                 case OS.CDDS_ITEMPOSTPAINT: return CDDS_ITEMPOSTPAINT (nmcd, wParam, lParam);
7398                                 case OS.CDDS_POSTPAINT: return CDDS_POSTPAINT (nmcd, wParam, lParam);
7399                         }
7400                         break;
7401                 }
7402                 case OS.NM_DBLCLK: {
7403                         /*
7404                         * When the user double clicks on a tree item
7405                         * or a line beside the item, the window proc
7406                         * for the tree collapses or expand the branch.
7407                         * When application code associates an action
7408                         * with double clicking, then the tree expand
7409                         * is unexpected and unwanted.  The fix is to
7410                         * avoid the operation by testing to see whether
7411                         * the mouse was inside a tree item.
7412                         */
7413                         if (hooks (SWT.MeasureItem)) return LRESULT.ONE;
7414                         if (hooks (SWT.DefaultSelection)) {
7415                                 POINT pt = new POINT ();
7416                                 int pos = OS.GetMessagePos ();
7417                                 OS.POINTSTOPOINT (pt, pos);
7418                                 OS.ScreenToClient (handle, pt);
7419                                 TVHITTESTINFO lpht = new TVHITTESTINFO ();
7420                                 lpht.x = pt.x;
7421                                 lpht.y = pt.y;
7422                                 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
7423                                 if (lpht.hItem != 0 && (lpht.flags & OS.TVHT_ONITEM) != 0) {
7424                                         return LRESULT.ONE;
7425                                 }
7426                         }
7427                         break;
7428                 }
7429                 /*
7430                 * Bug in Windows.  On Vista, when TVM_SELECTITEM is called
7431                 * with TVGN_CARET in order to set the selection, for some
7432                 * reason, Windows deselects the previous two items that
7433                 * were selected.  The fix is to stop the selection from
7434                 * changing on all but the item that is supposed to be
7435                 * selected.
7436                 */
7437                 case OS.TVN_ITEMCHANGING: {
7438                         if ((style & SWT.MULTI) != 0) {
7439                                 if (hSelect != 0) {
7440                                         NMTVITEMCHANGE pnm = new NMTVITEMCHANGE ();
7441                                         OS.MoveMemory (pnm, lParam, NMTVITEMCHANGE.sizeof);
7442                                         if (hSelect == pnm.hItem) break;
7443                                         return LRESULT.ONE;
7444                                 }
7445                         }
7446                         break;
7447                 }
7448                 case OS.TVN_SELCHANGING: {
7449                         if ((style & SWT.MULTI) != 0) {
7450                                 if (lockSelection) {
7451                                         /* Save the old selection state for both items */
7452                                         NMTREEVIEW treeView = new NMTREEVIEW ();
7453                                         OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7454                                         TVITEM tvItem = treeView.itemOld;
7455                                         oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
7456                                         tvItem = treeView.itemNew;
7457                                         newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
7458                                 }
7459                         }
7460                         if (!ignoreSelect && !ignoreDeselect) {
7461                                 hAnchor = 0;
7462                                 if ((style & SWT.MULTI) != 0) deselectAll ();
7463                         }
7464                         break;
7465                 }
7466                 case OS.TVN_SELCHANGED: {
7467                         NMTREEVIEW treeView = null;
7468                         if ((style & SWT.MULTI) != 0) {
7469                                 if (lockSelection) {
7470                                         /* Restore the old selection state of both items */
7471                                         if (oldSelected) {
7472                                                 if (treeView == null) {
7473                                                         treeView = new NMTREEVIEW ();
7474                                                         OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7475                                                 }
7476                                                 TVITEM tvItem = treeView.itemOld;
7477                                                 tvItem.mask = OS.TVIF_STATE;
7478                                                 tvItem.stateMask = OS.TVIS_SELECTED;
7479                                                 tvItem.state = OS.TVIS_SELECTED;
7480                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
7481                                         }
7482                                         if (!newSelected && ignoreSelect) {
7483                                                 if (treeView == null) {
7484                                                         treeView = new NMTREEVIEW ();
7485                                                         OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7486                                                 }
7487                                                 TVITEM tvItem = treeView.itemNew;
7488                                                 tvItem.mask = OS.TVIF_STATE;
7489                                                 tvItem.stateMask = OS.TVIS_SELECTED;
7490                                                 tvItem.state = 0;
7491                                                 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
7492                                         }
7493                                 }
7494                         }
7495                         if (!ignoreSelect) {
7496                                 if (treeView == null) {
7497                                         treeView = new NMTREEVIEW ();
7498                                         OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7499                                 }
7500                                 TVITEM tvItem = treeView.itemNew;
7501                                 hAnchor = tvItem.hItem;
7502                                 Event event = new Event ();
7503                                 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
7504                                 sendSelectionEvent (SWT.Selection, event, false);
7505                         }
7506                         updateScrollBar ();
7507                         break;
7508                 }
7509                 case OS.TVN_ITEMEXPANDING: {
7510                         if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7511                         boolean runExpanded = false;
7512                         if ((style & SWT.VIRTUAL) != 0) style &= ~SWT.DOUBLE_BUFFERED;
7513                         if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style &= ~SWT.DOUBLE_BUFFERED;
7514                         if (findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle)) {
7515                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
7516                         }
7517                         /*
7518                         * Bug in Windows.  When TVM_SETINSERTMARK is used to set
7519                         * an insert mark for a tree and an item is expanded or
7520                         * collapsed near the insert mark, the tree does not redraw
7521                         * the insert mark properly.  The fix is to hide and show
7522                         * the insert mark whenever an item is expanded or collapsed.
7523                         */
7524                         if (hInsert != 0) {
7525                                 OS.SendMessage (handle, OS.TVM_SETINSERTMARK, 0, 0);
7526                         }
7527                         if (!ignoreExpand) {
7528                                 NMTREEVIEW treeView = new NMTREEVIEW ();
7529                                 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7530                                 TVITEM tvItem = treeView.itemNew;
7531                                 /*
7532                                 * Feature in Windows.  In some cases, TVM_ITEMEXPANDING
7533                                 * is sent from within TVM_DELETEITEM for the tree item
7534                                 * being destroyed.  By the time the message is sent,
7535                                 * the item has already been removed from the list of
7536                                 * items.  The fix is to check for null.
7537                                 */
7538                                 if (items == null) break;
7539                                 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
7540                                 if (item == null) break;
7541                                 Event event = new Event ();
7542                                 event.item = item;
7543                                 switch (treeView.action) {
7544                                         case OS.TVE_EXPAND:
7545                                                 /*
7546                                                 * Bug in Windows.  When the numeric keypad asterisk
7547                                                 * key is used to expand every item in the tree, Windows
7548                                                 * sends TVN_ITEMEXPANDING to items in the tree that
7549                                                 * have already been expanded.  The fix is to detect
7550                                                 * that the item is already expanded and ignore the
7551                                                 * notification.
7552                                                 */
7553                                                 if ((tvItem.state & OS.TVIS_EXPANDED) == 0) {
7554                                                         sendEvent (SWT.Expand, event);
7555                                                         if (isDisposed ()) return LRESULT.ZERO;
7556                                                 }
7557                                                 break;
7558                                         case OS.TVE_COLLAPSE:
7559                                                 sendEvent (SWT.Collapse, event);
7560                                                 if (isDisposed ()) return LRESULT.ZERO;
7561                                                 break;
7562                                 }
7563                                 /*
7564                                 * Bug in Windows.  When all of the items are deleted during
7565                                 * TVN_ITEMEXPANDING, Windows does not send TVN_ITEMEXPANDED.
7566                                 * The fix is to detect this case and run the TVN_ITEMEXPANDED
7567                                 * code in this method.
7568                                 */
7569                                 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, tvItem.hItem);
7570                                 runExpanded = hFirstItem == 0;
7571                         }
7572                         if (!runExpanded) break;
7573                         //FALL THROUGH
7574                 }
7575                 case OS.TVN_ITEMEXPANDED: {
7576                         if ((style & SWT.VIRTUAL) != 0) style |= SWT.DOUBLE_BUFFERED;
7577                         if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style |= SWT.DOUBLE_BUFFERED;
7578                         if (findImageControl () != null && getDrawing () /*&& OS.IsWindowVisible (handle)*/) {
7579                                 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
7580                                 OS.InvalidateRect (handle, null, true);
7581                         }
7582                         /*
7583                         * Bug in Windows.  When TVM_SETINSERTMARK is used to set
7584                         * an insert mark for a tree and an item is expanded or
7585                         * collapsed near the insert mark, the tree does not redraw
7586                         * the insert mark properly.  The fix is to hide and show
7587                         * the insert mark whenever an item is expanded or collapsed.
7588                         */
7589                         if (hInsert != 0) {
7590                                 OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
7591                         }
7592                         /*
7593                         * Bug in Windows.  When a tree item that has an image
7594                         * with alpha is expanded or collapsed, the area where
7595                         * the image is drawn is not erased before it is drawn.
7596                         * This means that the image gets darker each time.
7597                         * The fix is to redraw the item.
7598                         */
7599                         if (imageList != null) {
7600                                 NMTREEVIEW treeView = new NMTREEVIEW ();
7601                                 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7602                                 TVITEM tvItem = treeView.itemNew;
7603                                 if (tvItem.hItem != 0) {
7604                                         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7605                                         if ((bits & OS.TVS_FULLROWSELECT) == 0) {
7606                                                 RECT rect = new RECT ();
7607                                                 if (OS.TreeView_GetItemRect (handle, tvItem.hItem, rect, false)) {
7608                                                         OS.InvalidateRect (handle, rect, true);
7609                                                 }
7610                                         }
7611                                 }
7612                         }
7613                         updateScrollBar ();
7614                         break;
7615                 }
7616                 case OS.TVN_BEGINDRAG:
7617                         if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) break;
7618                         //FALL THROUGH
7619                 case OS.TVN_BEGINRDRAG: {
7620                         dragStarted = true;
7621                         NMTREEVIEW treeView = new NMTREEVIEW ();
7622                         OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7623                         TVITEM tvItem = treeView.itemNew;
7624                         if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) {
7625                                 hSelect = tvItem.hItem;
7626                                 ignoreSelect = ignoreDeselect = true;
7627                                 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem);
7628                                 ignoreSelect = ignoreDeselect = false;
7629                                 hSelect = 0;
7630                         }
7631                         break;
7632                 }
7633         }
7634         return super.wmNotifyChild (hdr, wParam, lParam);
7635 }
7636
7637 LRESULT wmNotifyHeader (NMHDR hdr, long wParam, long lParam) {
7638         /*
7639         * Feature in Windows.  On NT, the automatically created
7640         * header control is created as a UNICODE window, not an
7641         * ANSI window despite the fact that the parent is created
7642         * as an ANSI window.  This means that it sends UNICODE
7643         * notification messages to the parent window on NT for
7644         * no good reason.  The data and size in the NMHEADER and
7645         * HDITEM structs is identical between the platforms so no
7646         * different message is actually necessary.  Despite this,
7647         * Windows sends different messages.  The fix is to look
7648         * for both messages, despite the platform.  This works
7649         * because only one will be sent on either platform, never
7650         * both.
7651         */
7652         switch (hdr.code) {
7653                 case OS.HDN_BEGINTRACK:
7654                 case OS.HDN_DIVIDERDBLCLICK: {
7655                         NMHEADER phdn = new NMHEADER ();
7656                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7657                         TreeColumn column = columns [phdn.iItem];
7658                         if (column != null && !column.getResizable ()) {
7659                                 return LRESULT.ONE;
7660                         }
7661                         ignoreColumnMove = true;
7662                         if (hdr.code == OS.HDN_DIVIDERDBLCLICK) {
7663                                 if (column != null) column.pack ();
7664                         }
7665                         break;
7666                 }
7667                 case OS.NM_CUSTOMDRAW: {
7668                         NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW();
7669                         OS.MoveMemory(nmcd, lParam, NMCUSTOMDRAW.sizeof);
7670                         switch (nmcd.dwDrawStage) {
7671                                 case OS.CDDS_PREPAINT: {
7672                                         /* Drawing here will be deleted by further drawing steps, even with OS.CDRF_SKIPDEFAULT.
7673                                            Changing the TextColor and returning OS.CDRF_NEWFONT has no effect. */
7674                                         return new LRESULT (customHeaderDrawing() ? OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT : OS.CDRF_DODEFAULT);
7675                                 }
7676                                 case OS.CDDS_ITEMPREPAINT: {
7677                                         // draw background
7678                                         RECT rect = new RECT();
7679                                         OS.SetRect(rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
7680                                         int pixel = getHeaderBackgroundPixel();
7681                                         if ((nmcd.uItemState & OS.CDIS_SELECTED) != 0) {
7682                                                 pixel = getDifferentColor(pixel);
7683                                         } else if (columns[(int) nmcd.dwItemSpec] == sortColumn && sortDirection != SWT.NONE) {
7684                                                 pixel = getSlightlyDifferentColor(pixel);
7685                                         }
7686                                         long brush = OS.CreateSolidBrush(pixel);
7687                                         OS.FillRect(nmcd.hdc, rect, brush);
7688                                         OS.DeleteObject(brush);
7689
7690                                         return new LRESULT(OS.CDRF_SKIPDEFAULT); // if we got here, we will paint everything ourself
7691                                 }
7692                                 case OS.CDDS_POSTPAINT: {
7693                                         // get the cursor position
7694                                         POINT cursorPos = new POINT();
7695                                         OS.GetCursorPos(cursorPos);
7696                                         OS.MapWindowPoints(0, hwndHeader, cursorPos, 1);
7697
7698                                         // drawing all cells
7699                                         int highlightedHeaderDividerX = -1;
7700                                         int lastColumnRight = -1;
7701                                         RECT [] rects = new RECT [columnCount];
7702                                         for (int i=0; i<columnCount; i++) {
7703                                                 rects [i] = new RECT ();
7704                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, rects [i]);
7705                                                 if (rects[i].right > lastColumnRight) {
7706                                                         lastColumnRight = rects[i].right;
7707                                                 }
7708
7709                                                 if (columns[i] == sortColumn && sortDirection != SWT.NONE) {
7710                                                         // the display.getSortImage looks terrible after scaling up.
7711                                                         long pen = OS.CreatePen (OS.PS_SOLID, 1, getHeaderForegroundPixel());
7712                                                         long oldPen = OS.SelectObject (nmcd.hdc, pen);
7713                                                         int center = rects[i].left + (rects[i].right - rects[i].left) / 2;
7714                                                         /*
7715                                                          * Sort indicator size needs to scale as per the Native Windows OS DPI level
7716                                                          * when header is custom drawn. For more details refer bug 537097.
7717                                                          */
7718                                                         int leg = DPIUtil.autoScaleUpUsingNativeDPI(3);
7719                                                         if (sortDirection == SWT.UP) {
7720                                                                 OS.Polyline(nmcd.hdc, new int[] {center-leg, 1+leg, center+1, 0}, 2);
7721                                                                 OS.Polyline(nmcd.hdc, new int[] {center+leg, 1+leg, center-1, 0}, 2);
7722                                                         } else if (sortDirection == SWT.DOWN) {
7723                                                                 OS.Polyline(nmcd.hdc, new int[] {center-leg, 1, center+1, 1+leg+1}, 2);
7724                                                                 OS.Polyline(nmcd.hdc, new int[] {center+leg, 1, center-1, 1+leg+1}, 2);
7725                                                         }
7726                                                         OS.SelectObject (nmcd.hdc, oldPen);
7727                                                         OS.DeleteObject (pen);
7728                                                 }
7729
7730                                                 /* Windows 7 and 10 always draw a nearly invisible vertical line between the columns, even if lines are disabled.
7731                                                    This line uses no fixed color constant, but calculates it from the background color.
7732                                                    The method getSlightlyDifferentColor gives us a color, that is near enough to the windows algorithm. */
7733                                                 long pen = OS.CreatePen (OS.PS_SOLID, getGridLineWidthInPixels(), getSlightlyDifferentColor(getHeaderBackgroundPixel()));
7734                                                 long oldPen = OS.SelectObject (nmcd.hdc, pen);
7735                                                 OS.Polyline(nmcd.hdc, new int[] {rects[i].right-1, rects[i].top, rects[i].right-1, rects[i].bottom}, 2);
7736                                                 OS.SelectObject (nmcd.hdc, oldPen);
7737                                                 OS.DeleteObject (pen);
7738
7739                                                 pen = OS.CreatePen (OS.PS_SOLID, getGridLineWidthInPixels(), OS.GetSysColor(OS.COLOR_3DFACE));
7740                                                 oldPen = OS.SelectObject (nmcd.hdc, pen);
7741                                                 /* To differentiate headers, always draw header column separator. */
7742                                                 OS.Polyline(nmcd.hdc, new int[] {rects[i].right-1, rects[i].top, rects[i].right-1, rects[i].bottom}, 2);
7743                                                 /* To differentiate header & content area, always draw the line separator between header & first row. */
7744                                                 if (i == 0) OS.Polyline(nmcd.hdc, new int[] {nmcd.left, nmcd.bottom-1, nmcd.right, nmcd.bottom-1}, 2);
7745                                                 OS.SelectObject (nmcd.hdc, oldPen);
7746                                                 OS.DeleteObject (pen);
7747
7748                                                 if (headerItemDragging && highlightedHeaderDividerX == -1) {
7749                                                         int distanceToLeftBorder = cursorPos.x - rects[i].left;
7750                                                         int distanceToRightBorder = rects[i].right - cursorPos.x;
7751                                                         if (distanceToLeftBorder >= 0 && distanceToRightBorder >= 0) {
7752                                                                 // the cursor is in the current rectangle
7753                                                                 highlightedHeaderDividerX = distanceToLeftBorder <= distanceToRightBorder ? rects[i].left-1 : rects[i].right;
7754                                                         }
7755                                                 }
7756
7757                                                 int x = rects[i].left + INSET + 2;
7758                                                 if (columns[i].image != null) {
7759                                                         GCData data = new GCData();
7760                                                         data.device = display;
7761                                                         GC gc = GC.win32_new (nmcd.hdc, data);
7762                                                         int y = Math.max (0, (nmcd.bottom - columns[i].image.getBoundsInPixels().height) / 2);
7763                                                         gc.drawImage (columns[i].image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y));
7764                                                         x += columns[i].image.getBoundsInPixels().width + 12;
7765                                                         gc.dispose ();
7766                                                 }
7767
7768                                                 if (columns[i].text != null) {
7769                                                         int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
7770                                                         if ((columns[i].style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
7771                                                         if ((columns[i].style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
7772                                                         char [] buffer = columns[i].text.toCharArray ();
7773                                                         OS.SetBkMode(nmcd.hdc, OS.TRANSPARENT);
7774                                                         OS.SetTextColor(nmcd.hdc, getHeaderForegroundPixel());
7775                                                         RECT textRect = new RECT();
7776                                                         textRect.left = x;
7777                                                         textRect.top = rects[i].top;
7778                                                         textRect.right = rects[i].right;
7779                                                         textRect.bottom = rects[i].bottom;
7780                                                         OS.DrawText (nmcd.hdc, buffer, buffer.length, textRect, flags);
7781                                                 }
7782                                         }
7783
7784                                         if (lastColumnRight < nmcd.right) {
7785                                                 // draw background of the 'no column' area
7786                                                 RECT rect = new RECT();
7787                                                 OS.SetRect(rect, lastColumnRight, nmcd.top, nmcd.right, nmcd.bottom-1);
7788                                                 long brush = OS.CreateSolidBrush(getHeaderBackgroundPixel());
7789                                                 OS.FillRect(nmcd.hdc, rect, brush);
7790                                                 OS.DeleteObject(brush);
7791                                         }
7792
7793                                         // always draw the highlighted border at the end, to avoid overdrawing by other borders.
7794                                         if (highlightedHeaderDividerX != -1) {
7795                                                 long pen = OS.CreatePen (OS.PS_SOLID, 4, OS.GetSysColor(OS.COLOR_HIGHLIGHT));
7796                                                 long oldPen = OS.SelectObject (nmcd.hdc, pen);
7797                                                 OS.Polyline(nmcd.hdc, new int[] {highlightedHeaderDividerX, nmcd.top, highlightedHeaderDividerX, nmcd.bottom}, 2);
7798                                                 OS.SelectObject (nmcd.hdc, oldPen);
7799                                                 OS.DeleteObject (pen);
7800                                         }
7801
7802                                         return new LRESULT(OS.CDRF_DODEFAULT);
7803                                 }
7804                         }
7805                         break;
7806                 }
7807                 case OS.NM_RELEASEDCAPTURE: {
7808                         if (!ignoreColumnMove) {
7809                                 for (int i=0; i<columnCount; i++) {
7810                                         TreeColumn column = columns [i];
7811                                         column.updateToolTip (i);
7812                                 }
7813                                 updateImageList ();
7814                         }
7815                         ignoreColumnMove = false;
7816                         break;
7817                 }
7818                 case OS.HDN_BEGINDRAG: {
7819                         if (ignoreColumnMove) return LRESULT.ONE;
7820                         NMHEADER phdn = new NMHEADER ();
7821                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7822                         if (phdn.iItem != -1) {
7823                                 TreeColumn column = columns [phdn.iItem];
7824                                 if (column != null && !column.getMoveable ()) {
7825                                         ignoreColumnMove = true;
7826                                         return LRESULT.ONE;
7827                                 }
7828                                 headerItemDragging = true;
7829                         }
7830                         break;
7831                 }
7832                 case OS.HDN_ENDDRAG: {
7833                         headerItemDragging = false;
7834                         NMHEADER phdn = new NMHEADER ();
7835                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7836                         if (phdn.iItem != -1 && phdn.pitem != 0) {
7837                                 HDITEM pitem = new HDITEM ();
7838                                 OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
7839                                 if ((pitem.mask & OS.HDI_ORDER) != 0 && pitem.iOrder != -1) {
7840                                         int [] order = new int [columnCount];
7841                                         OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
7842                                         int index = 0;
7843                                         while (index < order.length) {
7844                                                 if (order [index] == phdn.iItem) break;
7845                                                 index++;
7846                                         }
7847                                         if (index == order.length) index = 0;
7848                                         if (index == pitem.iOrder) break;
7849                                         int start = Math.min (index, pitem.iOrder);
7850                                         int end = Math.max (index, pitem.iOrder);
7851                                         RECT rect = new RECT (), headerRect = new RECT ();
7852                                         OS.GetClientRect (handle, rect);
7853                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [start], headerRect);
7854                                         rect.left = Math.max (rect.left, headerRect.left);
7855                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [end], headerRect);
7856                                         rect.right = Math.min (rect.right, headerRect.right);
7857                                         OS.InvalidateRect (handle, rect, true);
7858                                         ignoreColumnMove = false;
7859                                         for (int i=start; i<=end; i++) {
7860                                                 TreeColumn column = columns [order [i]];
7861                                                 if (!column.isDisposed ()) {
7862                                                         column.postEvent (SWT.Move);
7863                                                 }
7864                                         }
7865                                 }
7866                         }
7867                         break;
7868                 }
7869                 case OS.HDN_ITEMCHANGING: {
7870                         NMHEADER phdn = new NMHEADER ();
7871                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7872                         if (phdn.pitem != 0) {
7873                                 HDITEM newItem = new HDITEM ();
7874                                 OS.MoveMemory (newItem, phdn.pitem, HDITEM.sizeof);
7875                                 if ((newItem.mask & OS.HDI_WIDTH) != 0) {
7876                                         RECT rect = new RECT ();
7877                                         OS.GetClientRect (handle, rect);
7878                                         HDITEM oldItem = new HDITEM ();
7879                                         oldItem.mask = OS.HDI_WIDTH;
7880                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEM, phdn.iItem, oldItem);
7881                                         int deltaX = newItem.cxy - oldItem.cxy;
7882                                         RECT headerRect = new RECT ();
7883                                         OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, phdn.iItem, headerRect);
7884                                         int gridWidth = linesVisible ? GRID_WIDTH : 0;
7885                                         rect.left = headerRect.right - gridWidth;
7886                                         int newX = rect.left + deltaX;
7887                                         rect.right = Math.max (rect.right, rect.left + Math.abs (deltaX));
7888                                         if (explorerTheme || (findImageControl () != null || hooks (SWT.MeasureItem) || hooks (SWT.EraseItem) || hooks (SWT.PaintItem))) {
7889                                                 rect.left -= OS.GetSystemMetrics (OS.SM_CXFOCUSBORDER);
7890                                                 OS.InvalidateRect (handle, rect, true);
7891                                                 OS.OffsetRect (rect, deltaX, 0);
7892                                                 OS.InvalidateRect (handle, rect, true);
7893                                         } else {
7894                                                 int flags = OS.SW_INVALIDATE | OS.SW_ERASE;
7895                                                 OS.ScrollWindowEx (handle, deltaX, 0, rect, null, 0, null, flags);
7896                                         }
7897                                         if (OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, phdn.iItem, 0) != 0) {
7898                                                 rect.left = headerRect.left;
7899                                                 rect.right = newX;
7900                                                 OS.InvalidateRect (handle, rect, true);
7901                                         }
7902                                         setScrollWidth ();
7903                                 }
7904                         }
7905                         break;
7906                 }
7907                 case OS.HDN_ITEMCHANGED: {
7908                         NMHEADER phdn = new NMHEADER ();
7909                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7910                         if (phdn.pitem != 0) {
7911                                 HDITEM pitem = new HDITEM ();
7912                                 OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
7913                                 if ((pitem.mask & OS.HDI_WIDTH) != 0) {
7914                                         if (ignoreColumnMove) {
7915                                                 int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
7916                                                 OS.RedrawWindow (handle, null, 0, flags);
7917                                         }
7918                                         TreeColumn column = columns [phdn.iItem];
7919                                         if (column != null) {
7920                                                 column.updateToolTip (phdn.iItem);
7921                                                 column.sendEvent (SWT.Resize);
7922                                                 if (isDisposed ()) return LRESULT.ZERO;
7923                                                 TreeColumn [] newColumns = new TreeColumn [columnCount];
7924                                                 System.arraycopy (columns, 0, newColumns, 0, columnCount);
7925                                                 int [] order = new int [columnCount];
7926                                                 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
7927                                                 boolean moved = false;
7928                                                 for (int i=0; i<columnCount; i++) {
7929                                                         TreeColumn nextColumn = newColumns [order [i]];
7930                                                         if (moved && !nextColumn.isDisposed ()) {
7931                                                                 nextColumn.updateToolTip (order [i]);
7932                                                                 nextColumn.sendEvent (SWT.Move);
7933                                                         }
7934                                                         if (nextColumn == column) moved = true;
7935                                                 }
7936                                         }
7937                                 }
7938                                 setScrollWidth ();
7939                         }
7940                         break;
7941                 }
7942                 case OS.HDN_ITEMCLICK: {
7943                         NMHEADER phdn = new NMHEADER ();
7944                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7945                         TreeColumn column = columns [phdn.iItem];
7946                         if (column != null) {
7947                                 column.sendSelectionEvent (SWT.Selection);
7948                         }
7949                         break;
7950                 }
7951                 case OS.HDN_ITEMDBLCLICK: {
7952                         NMHEADER phdn = new NMHEADER ();
7953                         OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7954                         TreeColumn column = columns [phdn.iItem];
7955                         if (column != null) {
7956                                 column.sendSelectionEvent (SWT.DefaultSelection);
7957                         }
7958                         break;
7959                 }
7960         }
7961         return null;
7962 }
7963
7964 LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
7965         switch (hdr.code) {
7966                 case OS.NM_CUSTOMDRAW: {
7967                         NMTTCUSTOMDRAW nmcd = new NMTTCUSTOMDRAW ();
7968                         OS.MoveMemory (nmcd, lParam, NMTTCUSTOMDRAW.sizeof);
7969                         return wmNotifyToolTip (nmcd, lParam);
7970                 }
7971                 case OS.TTN_SHOW: {
7972                         LRESULT result = super.wmNotify (hdr, wParam, lParam);
7973                         if (result != null) return result;
7974                         int pos = OS.GetMessagePos ();
7975                         POINT pt = new POINT();
7976                         OS.POINTSTOPOINT (pt, pos);
7977                         OS.ScreenToClient (handle, pt);
7978                         int [] index = new int [1];
7979                         TreeItem [] item = new TreeItem [1];
7980                         RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
7981                         if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
7982                                 RECT toolRect = toolTipRect (itemRect [0]);
7983                                 OS.MapWindowPoints (handle, 0, toolRect, 2);
7984                                 int width = toolRect.right - toolRect.left;
7985                                 int height = toolRect.bottom - toolRect.top;
7986                                 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER | OS.SWP_NOSIZE;
7987                                 if (isCustomToolTip ()) flags &= ~OS.SWP_NOSIZE;
7988                                 OS.SetWindowPos (itemToolTipHandle, 0, toolRect.left, toolRect.top, width, height, flags);
7989                                 return LRESULT.ONE;
7990                         }
7991                         return result;
7992                 }
7993         }
7994         return null;
7995 }
7996
7997 LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd, long lParam) {
7998         switch (nmcd.dwDrawStage) {
7999                 case OS.CDDS_PREPAINT: {
8000                         if (isCustomToolTip ()) {
8001                                 //TEMPORARY CODE
8002                                 //nmcd.uDrawFlags |= OS.DT_CALCRECT;
8003                                 //OS.MoveMemory (lParam, nmcd, NMTTCUSTOMDRAW.sizeof);
8004                                 return new LRESULT (OS.CDRF_NOTIFYPOSTPAINT | OS.CDRF_NEWFONT);
8005                         }
8006                         break;
8007                 }
8008                 case OS.CDDS_POSTPAINT: {
8009                         if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
8010                                 TOOLINFO lpti = new TOOLINFO ();
8011                                 lpti.cbSize = TOOLINFO.sizeof;
8012                                 if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
8013                                         int [] index = new int [1];
8014                                         TreeItem [] item = new TreeItem [1];
8015                                         RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
8016                                         int pos = OS.GetMessagePos ();
8017                                         POINT pt = new POINT();
8018                                         OS.POINTSTOPOINT (pt, pos);
8019                                         OS.ScreenToClient (handle, pt);
8020                                         if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
8021                                                 long hDC = OS.GetDC (handle);
8022                                                 long hFont = item [0].fontHandle (index [0]);
8023                                                 if (hFont == -1) hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
8024                                                 long oldFont = OS.SelectObject (hDC, hFont);
8025                                                 boolean drawForeground = true;
8026                                                 cellRect [0] = item [0].getBounds (index [0], true, true, false, false, false, hDC);
8027                                                 if (hooks (SWT.EraseItem)) {
8028                                                         Event event = sendEraseItemEvent (item [0], nmcd, index [0], cellRect [0]);
8029                                                         if (isDisposed () || item [0].isDisposed ()) break;
8030                                                         if (event.doit) {
8031                                                                 drawForeground = (event.detail & SWT.FOREGROUND) != 0;
8032                                                         } else {
8033                                                                 drawForeground = false;
8034                                                         }
8035                                                 }
8036                                                 if (drawForeground) {
8037                                                         int nSavedDC = OS.SaveDC (nmcd.hdc);
8038                                                         int gridWidth = getLinesVisible () ? Table.GRID_WIDTH : 0;
8039                                                         RECT insetRect = toolTipInset (cellRect [0]);
8040                                                         OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
8041                                                         GCData data = new GCData ();
8042                                                         data.device = display;
8043                                                         data.foreground = OS.GetTextColor (nmcd.hdc);
8044                                                         data.background = OS.GetBkColor (nmcd.hdc);
8045                                                         data.font = Font.win32_new (display, hFont);
8046                                                         GC gc = GC.win32_new (nmcd.hdc, data);
8047                                                         int x = cellRect [0].left + INSET;
8048                                                         if (index [0] != 0) x -= gridWidth;
8049                                                         Image image = item [0].getImage (index [0]);
8050                                                         if (image != null || index [0] == 0) {
8051                                                                 Point size = getImageSize ();
8052                                                                 RECT imageRect = item [0].getBounds (index [0], false, true, false, false, false, hDC);
8053                                                                 if (imageList == null) size.x = imageRect.right - imageRect.left;
8054                                                                 if (image != null) {
8055                                                                         Rectangle rect = image.getBounds (); // Points
8056                                                                         gc.drawImage (image, rect.x, rect.y, rect.width, rect.height, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(imageRect.top), DPIUtil.autoScaleDown(size.x), DPIUtil.autoScaleDown(size.y));
8057                                                                         x += INSET + (index [0] == 0 ? 1 : 0);
8058                                                                 }
8059                                                                 x += size.x;
8060                                                         } else {
8061                                                                 x += INSET;
8062                                                         }
8063                                                         String string = item [0].getText (index [0]);
8064                                                         if (string != null) {
8065                                                                 int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
8066                                                                 TreeColumn column = columns != null ? columns [index [0]] : null;
8067                                                                 if (column != null) {
8068                                                                         if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
8069                                                                         if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
8070                                                                 }
8071                                                                 char [] buffer = string.toCharArray ();
8072                                                                 RECT textRect = new RECT ();
8073                                                                 OS.SetRect (textRect, x, cellRect [0].top, cellRect [0].right, cellRect [0].bottom);
8074                                                                 OS.DrawText (nmcd.hdc, buffer, buffer.length, textRect, flags);
8075                                                         }
8076                                                         gc.dispose ();
8077                                                         OS.RestoreDC (nmcd.hdc, nSavedDC);
8078                                                 }
8079                                                 if (hooks (SWT.PaintItem)) {
8080                                                         itemRect [0] = item [0].getBounds (index [0], true, true, false, false, false, hDC);
8081                                                         sendPaintItemEvent (item [0], nmcd, index[0], itemRect [0]);
8082                                                 }
8083                                                 OS.SelectObject (hDC, oldFont);
8084                                                 OS.ReleaseDC (handle, hDC);
8085                                         }
8086                                         break;
8087                                 }
8088                         }
8089                         break;
8090                 }
8091         }
8092         return null;
8093 }
8094
8095 }