KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > Tree


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13
14
15 import org.eclipse.swt.internal.*;
16 import org.eclipse.swt.internal.win32.*;
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.events.*;
20
21 /**
22  * Instances of this class provide a selectable user interface object
23  * that displays a hierarchy of items and issues notification when an
24  * item in the hierarchy is selected.
25  * <p>
26  * The item children that may be added to instances of this class
27  * must be of type <code>TreeItem</code>.
28  * </p><p>
29  * Style <code>VIRTUAL</code> is used to create a <code>Tree</code> whose
30  * <code>TreeItem</code>s are to be populated by the client on an on-demand basis
31  * instead of up-front. This can provide significant performance improvements for
32  * trees that are very large or for which <code>TreeItem</code> population is
33  * expensive (for example, retrieving values from an external source).
34  * </p><p>
35  * Here is an example of using a <code>Tree</code> with style <code>VIRTUAL</code>:
36  * <code><pre>
37  * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
38  * tree.setItemCount(20);
39  * tree.addListener(SWT.SetData, new Listener() {
40  * public void handleEvent(Event event) {
41  * TreeItem item = (TreeItem)event.item;
42  * TreeItem parentItem = item.getParentItem();
43  * String text = null;
44  * if (parentItem == null) {
45  * text = "node " + tree.indexOf(item);
46  * } else {
47  * text = parentItem.getText() + " - " + parentItem.indexOf(item);
48  * }
49  * item.setText(text);
50  * System.out.println(text);
51  * item.setItemCount(10);
52  * }
53  * });
54  * </pre></code>
55  * </p><p>
56  * Note that although this class is a subclass of <code>Composite</code>,
57  * it does not make sense to add <code>Control</code> children to it,
58  * or set a layout on it.
59  * </p><p>
60  * <dl>
61  * <dt><b>Styles:</b></dt>
62  * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL</dd>
63  * <dt><b>Events:</b></dt>
64  * <dd>Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, EraseItem, PaintItem</dd>
65  * </dl>
66  * </p><p>
67  * Note: Only one of the styles SINGLE and MULTI may be specified.
68  * </p><p>
69  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
70  * </p>
71  */

72 public class Tree extends Composite {
73     TreeItem [] items;
74     TreeColumn [] columns;
75     ImageList imageList, headerImageList;
76     TreeItem currentItem;
77     TreeColumn sortColumn;
78     int hwndParent, hwndHeader, hAnchor, hInsert, lastID, hSelect;
79     int hFirstIndexOf, hLastIndexOf, lastIndexOf, itemCount, sortDirection;
80     boolean dragStarted, gestureCompleted, insertAfter, shrink, ignoreShrink;
81     boolean ignoreSelect, ignoreExpand, ignoreDeselect, ignoreResize;
82     boolean lockSelection, oldSelected, newSelected, ignoreColumnMove;
83     boolean linesVisible, customDraw, printClient, painted, ignoreItemHeight;
84     boolean ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus;
85     boolean ignoreDrawSelection, ignoreDrawHot, ignoreFullSelection, explorerTheme;
86     int scrollWidth, itemToolTipHandle, headerToolTipHandle, selectionForeground;
87     static final int INSET = 3;
88     static final int GRID_WIDTH = 1;
89     static final int SORT_WIDTH = 10;
90     static final int HEADER_MARGIN = 12;
91     static final int HEADER_EXTRA = 3;
92     static final int INCREMENT = 5;
93     static final int EXPLORER_EXTRA = 2;
94     static final boolean EXPLORER_THEME = true;
95     static final int TreeProc;
96     static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true);
97     static final int HeaderProc;
98     static final TCHAR HeaderClass = new TCHAR (0, OS.WC_HEADER, true);
99     static {
100         WNDCLASS lpWndClass = new WNDCLASS ();
101         OS.GetClassInfo (0, TreeClass, lpWndClass);
102         TreeProc = lpWndClass.lpfnWndProc;
103         OS.GetClassInfo (0, HeaderClass, lpWndClass);
104         HeaderProc = lpWndClass.lpfnWndProc;
105     }
106
107 /**
108  * Constructs a new instance of this class given its parent
109  * and a style value describing its behavior and appearance.
110  * <p>
111  * The style value is either one of the style constants defined in
112  * class <code>SWT</code> which is applicable to instances of this
113  * class, or must be built by <em>bitwise OR</em>'ing together
114  * (that is, using the <code>int</code> "|" operator) two or more
115  * of those <code>SWT</code> style constants. The class description
116  * lists the style constants that are applicable to the class.
117  * Style bits are also inherited from superclasses.
118  * </p>
119  *
120  * @param parent a composite control which will be the parent of the new instance (cannot be null)
121  * @param style the style of control to construct
122  *
123  * @exception IllegalArgumentException <ul>
124  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
125  * </ul>
126  * @exception SWTException <ul>
127  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
128  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
129  * </ul>
130  *
131  * @see SWT#SINGLE
132  * @see SWT#MULTI
133  * @see SWT#CHECK
134  * @see Widget#checkSubclass
135  * @see Widget#getStyle
136  */

137 public Tree (Composite parent, int style) {
138     super (parent, checkStyle (style));
139 }
140
141 static int checkStyle (int style) {
142     /*
143     * Feature in Windows. It is not possible to create
144     * a tree that scrolls and does not have scroll bars.
145     * The TVS_NOSCROLL style will remove the scroll bars
146     * but the tree will never scroll. Therefore, no matter
147     * what style bits are specified, set the H_SCROLL and
148     * V_SCROLL bits so that the SWT style will match the
149     * widget that Windows creates.
150     */

151     style |= SWT.H_SCROLL | SWT.V_SCROLL;
152     return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
153 }
154
155 void _addListener (int eventType, Listener listener) {
156     super._addListener (eventType, listener);
157     switch (eventType) {
158         case SWT.DragDetect: {
159             if ((state & DRAG_DETECT) != 0) {
160                 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
161                 bits &= ~OS.TVS_DISABLEDRAGDROP;
162                 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
163             }
164             break;
165         }
166         case SWT.MeasureItem:
167         case SWT.EraseItem:
168         case SWT.PaintItem: {
169             customDraw = true;
170             style |= SWT.DOUBLE_BUFFERED;
171             OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
172             int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
173             bits |= OS.TVS_NOTOOLTIPS;
174             if (eventType == SWT.MeasureItem) bits |= OS.TVS_NOHSCROLL;
175             /*
176             * Feature in Windows. When the tree has the style
177             * TVS_FULLROWSELECT, the background color for the
178             * entire row is filled when an item is painted,
179             * drawing on top of any custom drawing. The fix
180             * is to clear TVS_FULLROWSELECT.
181             */

182             if ((style & SWT.FULL_SELECTION) != 0) {
183                 if (eventType != SWT.MeasureItem) {
184                     if (!explorerTheme) bits &= ~OS.TVS_FULLROWSELECT;
185                 }
186             }
187             if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) {
188                 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
189                 OS.InvalidateRect (handle, null, true);
190                 /*
191                 * Bug in Windows. When TVS_NOHSCROLL is set after items
192                 * have been inserted into the tree, Windows shows the
193                 * scroll bar. The fix is to check for this case and
194                 * explicitly hide the scroll bar.
195                 */

196                 int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
197                 if (count != 0 && (bits & OS.TVS_NOHSCROLL) != 0) {
198                     if (!OS.IsWinCE) OS.ShowScrollBar (handle, OS.SB_HORZ, false);
199                 }
200             }
201             break;
202         }
203     }
204 }
205
206 TreeItem _getItem (int hItem) {
207     TVITEM tvItem = new TVITEM ();
208     tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
209     tvItem.hItem = hItem;
210     if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
211         return _getItem (tvItem.hItem, tvItem.lParam);
212     }
213     return null;
214 }
215
216 TreeItem _getItem (int hItem, int id) {
217     if ((style & SWT.VIRTUAL) == 0) return items [id];
218     return id != -1 ? items [id] : new TreeItem (this, SWT.NONE, -1, -1, hItem);
219 }
220
221 void _setBackgroundPixel (int newPixel) {
222     int oldPixel = OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0);
223     if (oldPixel != newPixel) {
224         /*
225         * Bug in Windows. When TVM_SETBKCOLOR is used more
226         * than once to set the background color of a tree,
227         * the background color of the lines and the plus/minus
228         * does not change to the new color. The fix is to set
229         * the background color to the default before setting
230         * the new color.
231         */

232         if (oldPixel != -1) {
233             OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
234         }
235
236         /* Set the background color */
237         OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, newPixel);
238         
239         /*
240         * Feature in Windows. When TVM_SETBKCOLOR is used to
241         * set the background color of a tree, the plus/minus
242         * animation draws badly. The fix is to clear the effect.
243         */

244         if (explorerTheme) {
245             int bits2 = OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
246             if (newPixel == -1 && findImageControl () == null) {
247                 bits2 |= OS.TVS_EX_FADEINOUTEXPANDOS;
248             } else {
249                 bits2 &= ~OS.TVS_EX_FADEINOUTEXPANDOS;
250             }
251             OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits2);
252         }
253
254         /* Set the checkbox image list */
255         if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
256     }
257 }
258
259 /**
260  * Adds the listener to the collection of listeners who will
261  * be notified when the user changes the receiver's selection, by sending
262  * it one of the messages defined in the <code>SelectionListener</code>
263  * interface.
264  * <p>
265  * When <code>widgetSelected</code> is called, the item field of the event object is valid.
266  * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
267  * the event object detail field contains the value <code>SWT.CHECK</code>.
268  * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
269  * The item field of the event object is valid for default selection, but the detail field is not used.
270  * </p>
271  *
272  * @param listener the listener which should be notified when the user changes the receiver's selection
273  *
274  * @exception IllegalArgumentException <ul>
275  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
276  * </ul>
277  * @exception SWTException <ul>
278  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
279  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
280  * </ul>
281  *
282  * @see SelectionListener
283  * @see #removeSelectionListener
284  * @see SelectionEvent
285  */

286 public void addSelectionListener(SelectionListener listener) {
287     checkWidget ();
288     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
289     TypedListener typedListener = new TypedListener (listener);
290     addListener (SWT.Selection, typedListener);
291     addListener (SWT.DefaultSelection, typedListener);
292 }
293
294 /**
295  * Adds the listener to the collection of listeners who will
296  * be notified when an item in the receiver is expanded or collapsed
297  * by sending it one of the messages defined in the <code>TreeListener</code>
298  * interface.
299  *
300  * @param listener the listener which should be notified
301  *
302  * @exception IllegalArgumentException <ul>
303  * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
304  * </ul>
305  * @exception SWTException <ul>
306  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
307  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
308  * </ul>
309  *
310  * @see TreeListener
311  * @see #removeTreeListener
312  */

313 public void addTreeListener(TreeListener listener) {
314     checkWidget ();
315     if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
316     TypedListener typedListener = new TypedListener (listener);
317     addListener (SWT.Expand, typedListener);
318     addListener (SWT.Collapse, typedListener);
319 }
320
321 int borderHandle () {
322     return hwndParent != 0 ? hwndParent : handle;
323 }
324
325 LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, int wParam, int lParam) {
326     if (ignoreCustomDraw) return null;
327     if (nmcd.left == nmcd.right) return new LRESULT (OS.CDRF_DODEFAULT);
328     int hDC = nmcd.hdc;
329     OS.RestoreDC (hDC, -1);
330     TreeItem item = getItem (nmcd);
331     
332     /*
333     * Feature in Windows. When a new tree item is inserted
334     * using TVM_INSERTITEM and the tree is using custom draw,
335     * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
336     * and before the item is added to the items array. The
337     * fix is to check for null.
338     *
339     * NOTE: This only happens on XP with the version 6.00 of
340     * COMCTL32.DLL,
341     */

342     if (item == null) return null;
343
344     /*
345     * Feature in Windows. Under certain circumstances, Windows
346     * sends CDDS_ITEMPOSTPAINT for an empty rectangle. This is
347     * not a problem providing that graphics do not occur outside
348     * the rectangle. The fix is to test for the rectangle and
349     * draw nothing.
350     *
351     * NOTE: This seems to happen when both I_IMAGECALLBACK
352     * and LPSTR_TEXTCALLBACK are used at the same time with
353     * TVM_SETITEM.
354     */

355     if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) return null;
356     if (!OS.IsWindowVisible (handle)) return null;
357     if ((style & SWT.FULL_SELECTION) != 0 || findImageControl () != null || ignoreDrawSelection || explorerTheme) {
358         OS.SetBkMode (hDC, OS.TRANSPARENT);
359     }
360     boolean selected = isItemSelected (nmcd);
361     boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
362     if (OS.IsWindowEnabled (handle)) {
363         if (explorerTheme) {
364             int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
365             if ((bits & OS.TVS_TRACKSELECT) != 0) {
366                 if ((style & SWT.FULL_SELECTION) != 0 && (selected || hot)) {
367                     OS.SetTextColor (hDC, OS.GetSysColor (OS.COLOR_WINDOWTEXT));
368                 } else {
369                     OS.SetTextColor (hDC, getForegroundPixel ());
370                 }
371             }
372         }
373     }
374     int count = 0;
375     int [] order = null;
376     RECT clientRect = new RECT ();
377     OS.GetClientRect (scrolledHandle (), clientRect);
378     if (hwndHeader != 0) {
379         OS.MapWindowPoints (hwndParent, handle, clientRect, 2);
380         count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
381         if (count != 0) {
382             order = new int [count];
383             OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
384         }
385     }
386     int sortIndex = -1, clrSortBk = -1;
387     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
388         if (sortColumn != null && sortDirection != SWT.NONE) {
389             if (findImageControl () == null) {
390                 sortIndex = indexOf (sortColumn);
391                 clrSortBk = getSortColumnPixel ();
392             }
393         }
394     }
395     int x = 0;
396     Point size = null;
397     for (int i=0; i<Math.max (1, count); i++) {
398         int index = order == null ? i : order [i], width = nmcd.right - nmcd.left;
399         if (count > 0 && hwndHeader != 0) {
400             HDITEM hdItem = new HDITEM ();
401             hdItem.mask = OS.HDI_WIDTH;
402             OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
403             width = hdItem.cxy;
404         }
405         if (i == 0) {
406             if ((style & SWT.FULL_SELECTION) != 0) {
407                 boolean clear = !explorerTheme && !ignoreDrawSelection && findImageControl () == null;
408                 if (clear || (selected && !ignoreDrawSelection) || (hot && !ignoreDrawHot)) {
409                     boolean draw = true;
410                     RECT pClipRect = new RECT ();
411                     OS.SetRect (pClipRect, width, nmcd.top, nmcd.right, nmcd.bottom);
412                     if (explorerTheme) {
413                         if (hooks (SWT.EraseItem)) {
414                             RECT itemRect = item.getBounds (index, true, true, false, false, true, hDC);
415                             itemRect.left -= EXPLORER_EXTRA;
416                             itemRect.right += EXPLORER_EXTRA + 1;
417                             pClipRect.left = itemRect.left;
418                             pClipRect.right = itemRect.right;
419                             if (count > 0 && hwndHeader != 0) {
420                                 HDITEM hdItem = new HDITEM ();
421                                 hdItem.mask = OS.HDI_WIDTH;
422                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
423                                 pClipRect.right = Math.min (pClipRect.right, nmcd.left + hdItem.cxy);
424                             }
425                         }
426                         RECT pRect = new RECT ();
427                         OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
428                         if (count > 0 && hwndHeader != 0) {
429                             int totalWidth = 0;
430                             HDITEM hdItem = new HDITEM ();
431                             hdItem.mask = OS.HDI_WIDTH;
432                             for (int j=0; j<count; j++) {
433                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
434                                 totalWidth += hdItem.cxy;
435                             }
436                             if (totalWidth > clientRect.right - clientRect.left) {
437                                 pRect.left = 0;
438                                 pRect.right = totalWidth;
439                             } else {
440                                 pRect.left = clientRect.left;
441                                 pRect.right = clientRect.right;
442                             }
443                         }
444                         draw = false;
445                         int hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
446                         int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
447                         if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
448                         OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
449                         OS.CloseThemeData (hTheme);
450                     }
451                     if (draw) fillBackground (hDC, OS.GetBkColor (hDC), pClipRect);
452                 }
453             } else {
454                 if (explorerTheme && hooks (SWT.EraseItem)) {
455                     if ((selected && !ignoreDrawSelection) || (hot && !ignoreDrawHot)) {
456                         RECT pRect = item.getBounds (index, true, true, false, false, false, hDC);
457                         RECT pClipRect = item.getBounds (index, true, true, false, false, true, hDC);
458                         pRect.left -= EXPLORER_EXTRA;
459                         pRect.right += EXPLORER_EXTRA;
460                         pClipRect.left -= EXPLORER_EXTRA;
461                         pClipRect.right += EXPLORER_EXTRA;
462                         int hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
463                         int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
464                         if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
465                         OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
466                         OS.CloseThemeData (hTheme);
467                     }
468                 }
469             }
470         }
471         if (x + width > clientRect.left) {
472             RECT rect = new RECT (), backgroundRect = null;
473             boolean drawItem = true, drawText = true, drawImage = true, drawBackground = false;
474             if (i == 0) {
475                 drawItem = drawImage = drawText = false;
476                 if (findImageControl () != null) {
477                     if (explorerTheme) {
478                         if (OS.IsWindowEnabled (handle) && !hooks (SWT.EraseItem)) {
479                             Image image = null;
480                             if (index == 0) {
481                                 image = item.image;
482                             } else {
483                                 Image [] images = item.images;
484                                 if (images != null) image = images [index];
485                             }
486                             if (image != null) {
487                                 Rectangle bounds = image.getBounds ();
488                                 if (size == null) size = getImageSize ();
489                                 if (!ignoreDrawForeground) {
490                                     GCData data = new GCData();
491                                     data.device = display;
492                                     GC gc = GC.win32_new (hDC, data);
493                                     RECT iconRect = item.getBounds (index, false, true, false, false, true, hDC);
494                                     gc.setClipping (iconRect.left, iconRect.top, iconRect.right - iconRect.left, iconRect.bottom - iconRect.top);
495                                     gc.drawImage (image, 0, 0, bounds.width, bounds.height, iconRect.left, iconRect.top, size.x, size.y);
496                                     OS.SelectClipRgn (hDC, 0);
497                                     gc.dispose ();
498                                 }
499                             }
500                         }
501                     } else {
502                         drawItem = drawText = drawBackground = true;
503                         rect = item.getBounds (index, true, false, false, false, true, hDC);
504                         if (linesVisible) {
505                             rect.right++;
506                             rect.bottom++;
507                         }
508                     }
509                 }
510                 if (selected && !ignoreDrawSelection && !ignoreDrawBackground) {
511                     if (!explorerTheme) fillBackground (hDC, OS.GetBkColor (hDC), rect);
512                     drawBackground = false;
513                 }
514                 backgroundRect = rect;
515                 if (hooks (SWT.EraseItem)) {
516                     drawItem = drawText = drawImage = true;
517                     rect = item.getBounds (index, true, true, false, false, true, hDC);
518                     if ((style & SWT.FULL_SELECTION) != 0) {
519                         backgroundRect = rect;
520                     } else {
521                         backgroundRect = item.getBounds (index, true, false, false, false, true, hDC);
522                     }
523                 }
524             } else {
525                 selectionForeground = -1;
526                 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = false;
527                 OS.SetRect (rect, x, nmcd.top, x + width, nmcd.bottom);
528                 backgroundRect = rect;
529             }
530             int clrText = -1, clrTextBk = -1;
531             int hFont = item.cellFont != null ? item.cellFont [index] : -1;
532             if (hFont == -1) hFont = item.font;
533             if (selectionForeground != -1) clrText = selectionForeground;
534             if (OS.IsWindowEnabled (handle)) {
535                 boolean drawForeground = false;
536                 if (selected) {
537                     if (i != 0 && (style & SWT.FULL_SELECTION) == 0) {
538                         OS.SetTextColor (hDC, getForegroundPixel ());
539                         OS.SetBkColor (hDC, getBackgroundPixel ());
540                         drawForeground = drawBackground = true;
541                     }
542                 } else {
543                     drawForeground = drawBackground = true;
544                 }
545                 if (drawForeground) {
546                     clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
547                     if (clrText == -1) clrText = item.foreground;
548                 }
549                 if (drawBackground) {
550                     clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
551                     if (clrTextBk == -1) clrTextBk = item.background;
552                     if (clrTextBk == -1 && index == sortIndex) clrTextBk = clrSortBk;
553                 }
554             } else {
555                 if (clrTextBk == -1 && index == sortIndex) {
556                     drawBackground = true;
557                     clrTextBk = clrSortBk;
558                 }
559             }
560             if (explorerTheme) {
561                 if (selected || (nmcd.uItemState & OS.CDIS_HOT) != 0) {
562                     if ((style & SWT.FULL_SELECTION) != 0) {
563                         drawBackground = false;
564                     } else {
565                         if (i == 0) {
566                             drawBackground = false;
567                             if (!hooks (SWT.EraseItem)) drawText = false;
568                         }
569                     }
570                 }
571             }
572             if (drawItem) {
573                 if (i != 0) {
574                     if (hooks (SWT.MeasureItem)) {
575                         RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
576                         int nSavedDC = OS.SaveDC (hDC);
577                         GCData data = new GCData ();
578                         data.device = display;
579                         data.hFont = hFont;
580                         GC gc = GC.win32_new (hDC, data);
581                         Event event = new Event ();
582                         event.item = item;
583                         event.index = index;
584                         event.gc = gc;
585                         event.x = itemRect.left;
586                         event.y = itemRect.top;
587                         event.width = itemRect.right - itemRect.left;
588                         event.height = itemRect.bottom - itemRect.top;
589                         sendEvent (SWT.MeasureItem, event);
590                         event.gc = null;
591                         gc.dispose ();
592                         OS.RestoreDC (hDC, nSavedDC);
593                         if (isDisposed () || item.isDisposed ()) break;
594                         if (event.height > getItemHeight ()) setItemHeight (event.height);
595                     }
596                     if (hooks (SWT.EraseItem)) {
597                         RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
598                         int nSavedDC = OS.SaveDC (hDC);
599                         GCData data = new GCData ();
600                         data.device = display;
601                         data.foreground = OS.GetTextColor (hDC);
602                         data.background = OS.GetBkColor (hDC);
603                         if (!selected || (style & SWT.FULL_SELECTION) == 0) {
604                             if (clrText != -1) data.foreground = clrText;
605                             if (clrTextBk != -1) data.background = clrTextBk;
606                         }
607                         data.hFont = hFont;
608                         data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
609                         GC gc = GC.win32_new (hDC, data);
610                         Event event = new Event ();
611                         event.item = item;
612                         event.index = index;
613                         event.gc = gc;
614                         event.detail |= SWT.FOREGROUND;
615                         if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
616                         if ((style & SWT.FULL_SELECTION) != 0) {
617                             if (hot) event.detail |= SWT.HOT;
618                             if (selected) event.detail |= SWT.SELECTED;
619                             if (!explorerTheme) {
620                                 //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
621
if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
622                                     if (handle == OS.GetFocus ()) {
623                                         int uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
624                                         if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
625                                     }
626                                 }
627                             }
628                         }
629                         event.x = cellRect.left;
630                         event.y = cellRect.top;
631                         event.width = cellRect.right - cellRect.left;
632                         event.height = cellRect.bottom - cellRect.top;
633                         gc.setClipping (event.x, event.y, event.width, event.height);
634                         sendEvent (SWT.EraseItem, event);
635                         event.gc = null;
636                         int newTextClr = data.foreground;
637                         gc.dispose ();
638                         OS.RestoreDC (hDC, nSavedDC);
639                         if (isDisposed () || item.isDisposed ()) break;
640                         if (event.doit) {
641                             ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
642                             ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
643                             if ((style & SWT.FULL_SELECTION) != 0) {
644                                 ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
645                                 ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
646                                 ignoreDrawHot = (event.detail & SWT.HOT) == 0;
647                             }
648                         } else {
649                             ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
650                         }
651                         if (selected && ignoreDrawSelection) ignoreDrawHot = true;
652                         if ((style & SWT.FULL_SELECTION) != 0) {
653                             if (ignoreDrawSelection) ignoreFullSelection = true;
654                             if (!ignoreDrawSelection || !ignoreDrawHot) {
655                                 if (!selected && !hot) {
656                                     selectionForeground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
657                                 } else {
658                                     if (!explorerTheme) {
659                                         drawBackground = true;
660                                         ignoreDrawBackground = false;
661                                         if (handle == OS.GetFocus () && OS.IsWindowEnabled (handle)) {
662                                             clrTextBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
663                                         } else {
664                                             clrTextBk = OS.GetSysColor (OS.COLOR_3DFACE);
665                                         }
666                                         if (!ignoreFullSelection && index == count - 1) {
667                                             RECT selectionRect = new RECT ();
668                                             OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, nmcd.right, backgroundRect.bottom);
669                                             backgroundRect = selectionRect;
670                                         }
671                                     } else {
672                                         RECT pRect = new RECT ();
673                                         OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
674                                         if (count > 0 && hwndHeader != 0) {
675                                             int totalWidth = 0;
676                                             HDITEM hdItem = new HDITEM ();
677                                             hdItem.mask = OS.HDI_WIDTH;
678                                             for (int j=0; j<count; j++) {
679                                                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
680                                                 totalWidth += hdItem.cxy;
681                                             }
682                                             if (totalWidth > clientRect.right - clientRect.left) {
683                                                 pRect.left = 0;
684                                                 pRect.right = totalWidth;
685                                             } else {
686                                                 pRect.left = clientRect.left;
687                                                 pRect.right = clientRect.right;
688                                             }
689                                             if (index == count - 1) {
690                                                 RECT selectionRect = new RECT ();
691                                                 OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, pRect.right, backgroundRect.bottom);
692                                                 backgroundRect = selectionRect;
693                                             }
694                                         }
695                                         int hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
696                                         int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
697                                         if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
698                                         OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, backgroundRect);
699                                         OS.CloseThemeData (hTheme);
700                                     }
701                                 }
702                             } else {
703                                 if (selected) {
704                                     selectionForeground = newTextClr;
705                                     if (!explorerTheme) {
706                                         if (clrTextBk == -1 && OS.IsWindowEnabled (handle)) {
707                                             Control control = findBackgroundControl ();
708                                             if (control == null) control = this;
709                                             clrTextBk = control.getBackgroundPixel ();
710                                         }
711                                     }
712                                 }
713                             }
714                         }
715                     }
716                     if (selectionForeground != -1) clrText = selectionForeground;
717                 }
718                 if (!ignoreDrawBackground) {
719                     if (clrTextBk != -1) {
720                         if (drawBackground) fillBackground (hDC, clrTextBk, backgroundRect);
721                     } else {
722                         Control control = findImageControl ();
723                         if (control != null) {
724                             if (i == 0) {
725                                 int right = Math.min (rect.right, width);
726                                 OS.SetRect (rect, rect.left, rect.top, right, rect.bottom);
727                                 if (drawBackground) fillImageBackground (hDC, control, rect);
728                             } else {
729                                 if (drawBackground) fillImageBackground (hDC, control, rect);
730                             }
731                         }
732                     }
733                 }
734                 rect.left += INSET - 1;
735                 if (drawImage) {
736                     Image image = null;
737                     if (index == 0) {
738                         image = item.image;
739                     } else {
740                         Image [] images = item.images;
741                         if (images != null) image = images [index];
742                     }
743                     int inset = i != 0 ? INSET : 0;
744                     int offset = i != 0 ? INSET : INSET + 2;
745                     if (image != null) {
746                         Rectangle bounds = image.getBounds ();
747                         if (size == null) size = getImageSize ();
748                         //int y = rect.top + (index == 0 ? (getItemHeight () - size.y) / 2 : 0);
749
int y = rect.top;
750                         if (!ignoreDrawForeground) {
751                             //TODO - share GC, clip the drawing for index == 0
752
GCData data = new GCData();
753                             data.device = display;
754                             GC gc = GC.win32_new (hDC, data);
755                             //if (index == 0) { //must clear
756
//gc.setClipping (rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
757
//}
758
gc.drawImage (image, 0, 0, bounds.width, bounds.height, rect.left - inset + 1, y, size.x, size.y);
759                             gc.dispose ();
760                         }
761                         OS.SetRect (rect, rect.left + size.x + offset, rect.top, rect.right - inset, rect.bottom);
762                     } else {
763                         if (i == 0) {
764                             if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) != 0) {
765                                 if (size == null) size = getImageSize ();
766                                 rect.left = Math.min (rect.left + size.x + offset, rect.right);
767                             }
768                         } else {
769                             OS.SetRect (rect, rect.left + offset, rect.top, rect.right - inset, rect.bottom);
770                         }
771                     }
772                 }
773                 if (drawText) {
774                     /*
775                     * Bug in Windows. When DrawText() is used with DT_VCENTER
776                     * and DT_ENDELLIPSIS, the ellipsis can draw outside of the
777                     * rectangle when the rectangle is empty. The fix is avoid
778                     * all text drawing for empty rectangles.
779                     */

780                     if (rect.left < rect.right) {
781                         String JavaDoc string = null;
782                         if (index == 0) {
783                             string = item.text;
784                         } else {
785                             String JavaDoc [] strings = item.strings;
786                             if (strings != null) string = strings [index];
787                         }
788                         if (string != null) {
789                             if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
790                             if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
791                             if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
792                             int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
793                             if (i != 0) flags |= OS.DT_ENDELLIPSIS;
794                             TreeColumn column = columns != null ? columns [index] : null;
795                             if (column != null) {
796                                 if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
797                                 if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
798                             }
799                             TCHAR buffer = new TCHAR (getCodePage (), string, false);
800                             if (!ignoreDrawForeground) OS.DrawText (hDC, buffer, buffer.length (), rect, flags);
801                             OS.DrawText (hDC, buffer, buffer.length (), rect, flags | OS.DT_CALCRECT);
802                             if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
803                             if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
804                             if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
805                         }
806                     }
807                 }
808             }
809             if (selectionForeground != -1) clrText = selectionForeground;
810             if (hooks (SWT.PaintItem)) {
811                 RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
812                 int nSavedDC = OS.SaveDC (hDC);
813                 GCData data = new GCData ();
814                 data.device = display;
815                 data.hFont = hFont;
816                 data.foreground = OS.GetTextColor (hDC);
817                 data.background = OS.GetBkColor (hDC);
818                 if (selected && (style & SWT.FULL_SELECTION) != 0) {
819                     if (selectionForeground != -1) data.foreground = selectionForeground;
820                 } else {
821                     if (clrText != -1) data.foreground = clrText;
822                     if (clrTextBk != -1) data.background = clrTextBk;
823                 }
824                 data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
825                 GC gc = GC.win32_new (hDC, data);
826                 Event event = new Event ();
827                 event.item = item;
828                 event.index = index;
829                 event.gc = gc;
830                 event.detail |= SWT.FOREGROUND;
831                 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
832                 if (hot) event.detail |= SWT.HOT;
833                 if (selected && (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0)) {
834                     event.detail |= SWT.SELECTED;
835                 }
836                 if (!explorerTheme) {
837                     //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
838
if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
839                         if (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0) {
840                             if (handle == OS.GetFocus ()) {
841                                 int uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
842                                 if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
843                             }
844                         }
845                     }
846                 }
847                 event.x = itemRect.left;
848                 event.y = itemRect.top;
849                 event.width = itemRect.right - itemRect.left;
850                 event.height = itemRect.bottom - itemRect.top;
851                 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
852                 int cellWidth = cellRect.right - cellRect.left;
853                 int cellHeight = cellRect.bottom - cellRect.top;
854                 gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight);
855                 sendEvent (SWT.PaintItem, event);
856                 event.gc = null;
857                 gc.dispose ();
858                 OS.RestoreDC (hDC, nSavedDC);
859                 if (isDisposed () || item.isDisposed ()) break;
860             }
861         }
862         x += width;
863         if (x > clientRect.right) break;
864     }
865     if (linesVisible) {
866         if ((style & SWT.FULL_SELECTION) != 0) {
867             if (hwndHeader != 0) {
868                 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0) != 0) {
869                     HDITEM hdItem = new HDITEM ();
870                     hdItem.mask = OS.HDI_WIDTH;
871                     OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem);
872                     RECT rect = new RECT ();
873                     OS.SetRect (rect, nmcd.left + hdItem.cxy, nmcd.top, nmcd.right, nmcd.bottom);
874                     OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
875                 }
876             }
877         }
878         RECT rect = new RECT ();
879         OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
880         OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
881     }
882     if (!explorerTheme) {
883         if (handle == OS.GetFocus ()) {
884             int uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
885             if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
886                 int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
887                 if (hItem == item.handle) {
888                     if (!ignoreDrawFocus && findImageControl () != null) {
889                         if ((style & SWT.FULL_SELECTION) != 0) {
890                             RECT focusRect = new RECT ();
891                             OS.SetRect (focusRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
892                             if (count > 0 && hwndHeader != 0) {
893                                 int width = 0;
894                                 HDITEM hdItem = new HDITEM ();
895                                 hdItem.mask = OS.HDI_WIDTH;
896                                 for (int j=0; j<count; j++) {
897                                     OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
898                                     width += hdItem.cxy;
899                                 }
900                                 focusRect.left = 0;
901                                 RECT rect = new RECT ();
902                                 OS.GetClientRect (handle, rect);
903                                 focusRect.right = Math.max (width, rect.right - OS.GetSystemMetrics (OS.SM_CXVSCROLL));
904                             }
905                             OS.DrawFocusRect (hDC, focusRect);
906                         } else {
907                             int index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
908                             RECT focusRect = item.getBounds (index, true, false, false, false, false, hDC);
909                             RECT clipRect = item.getBounds (index, true, false, false, false, true, hDC);
910                             OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
911                             OS.DrawFocusRect (hDC, focusRect);
912                             OS.SelectClipRgn (hDC, 0);
913                         }
914                     }
915                 }
916             }
917         }
918     }
919     return new LRESULT (OS.CDRF_DODEFAULT);
920 }
921
922 LRESULT CDDS_ITEMPREPAINT (NMTVCUSTOMDRAW nmcd, int wParam, int lParam) {
923     /*
924     * Even when custom draw is being ignored, the font needs
925     * to be selected into the HDC so that the item bounds are
926     * measured correctly.
927     */

928     TreeItem item = getItem (nmcd);
929     /*
930     * Feature in Windows. When a new tree item is inserted
931     * using TVM_INSERTITEM and the tree is using custom draw,
932     * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
933     * and before the item is added to the items array. The
934     * fix is to check for null.
935     *
936     * NOTE: This only happens on XP with the version 6.00 of
937     * COMCTL32.DLL,
938     */

939     if (item == null) return null;
940     int hDC = nmcd.hdc;
941     int index = hwndHeader != 0 ? OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) : 0;
942     int hFont = item.cellFont != null ? item.cellFont [index] : -1;
943     if (hFont == -1) hFont = item.font;
944     if (hFont != -1) OS.SelectObject (hDC, hFont);
945     if (ignoreCustomDraw || nmcd.left == nmcd.right) {
946         return new LRESULT (hFont == -1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT);
947     }
948     int count = 0;
949     RECT clipRect = null;
950     if (hwndHeader != 0) {
951         count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
952         if (count != 0) {
953             boolean clip = !printClient;
954             if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
955                 clip = true;
956             }
957             if (clip) {
958                 clipRect = new RECT ();
959                 HDITEM hdItem = new HDITEM ();
960                 hdItem.mask = OS.HDI_WIDTH;
961                 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
962                 OS.SetRect (clipRect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
963             }
964         }
965     }
966     int clrText = -1, clrTextBk = -1;
967     if (OS.IsWindowEnabled (handle)) {
968         clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
969         if (clrText == -1) clrText = item.foreground;
970         clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
971         if (clrTextBk == -1) clrTextBk = item.background;
972     }
973     int clrSortBk = -1;
974     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
975         if (sortColumn != null && sortDirection != SWT.NONE) {
976             if (findImageControl () == null) {
977                 if (indexOf (sortColumn) == index) {
978                     clrSortBk = getSortColumnPixel ();
979                     if (clrTextBk == -1) clrTextBk = clrSortBk;
980                 }
981             }
982         }
983     }
984     boolean selected = isItemSelected (nmcd);
985     boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
986     if (OS.IsWindowVisible (handle) && nmcd.left < nmcd.right && nmcd.top < nmcd.bottom) {
987         if (hFont != -1) OS.SelectObject (hDC, hFont);
988         if (linesVisible) {
989             RECT rect = new RECT ();
990             OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
991             OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
992         }
993         //TODO - BUG - measure and erase sent when first column is clipped
994
if (hooks (SWT.MeasureItem)) {
995             RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
996             int nSavedDC = OS.SaveDC (hDC);
997             GCData data = new GCData ();
998             data.device = display;
999             data.hFont = hFont;
1000            GC gc = GC.win32_new (hDC, data);
1001            Event event = new Event ();
1002            event.item = item;
1003            event.gc = gc;
1004            event.index = index;
1005            event.x = itemRect.left;
1006            event.y = itemRect.top;
1007            event.width = itemRect.right - itemRect.left;
1008            event.height = itemRect.bottom - itemRect.top;
1009            sendEvent (SWT.MeasureItem, event);
1010            event.gc = null;
1011            gc.dispose ();
1012            OS.RestoreDC (hDC, nSavedDC);
1013            if (isDisposed () || item.isDisposed ()) return null;
1014            if (hwndHeader != 0) {
1015                if (count == 0) {
1016                    if (event.x + event.width > scrollWidth) {
1017                        setScrollWidth (scrollWidth = event.x + event.width);
1018                    }
1019                }
1020            }
1021            if (event.height > getItemHeight ()) setItemHeight (event.height);
1022        }
1023        selectionForeground = -1;
1024        ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = ignoreFullSelection = false;
1025        if (hooks (SWT.EraseItem)) {
1026            RECT rect = new RECT ();
1027            OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1028            if (OS.IsWindowEnabled (handle) || findImageControl () != null) {
1029                drawBackground (hDC, rect);
1030            } else {
1031                fillBackground (hDC, OS.GetBkColor (hDC), rect);
1032            }
1033            RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
1034            if (clrSortBk != -1) {
1035                RECT fullRect = item.getBounds (index, true, true, true, true, true, hDC);
1036                drawBackground (hDC, fullRect, clrSortBk);
1037            }
1038            int nSavedDC = OS.SaveDC (hDC);
1039            GCData data = new GCData ();
1040            data.device = display;
1041            if (selected && explorerTheme) {
1042                data.foreground = OS.GetSysColor (OS.COLOR_WINDOWTEXT);
1043            } else {
1044                data.foreground = OS.GetTextColor (hDC);
1045            }
1046            data.background = OS.GetBkColor (hDC);
1047            if (!selected) {
1048                if (clrText != -1) data.foreground = clrText;
1049                if (clrTextBk != -1) data.background = clrTextBk;
1050            }
1051            data.uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1052            if (hFont != -1) data.hFont = hFont;
1053            GC gc = GC.win32_new (hDC, data);
1054            Event event = new Event ();
1055            event.index = index;
1056            event.item = item;
1057            event.gc = gc;
1058            event.detail |= SWT.FOREGROUND;
1059            if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
1060            if (hot) event.detail |= SWT.HOT;
1061            if (selected) event.detail |= SWT.SELECTED;
1062            if (!explorerTheme) {
1063                //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
1064
if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
1065                    if (handle == OS.GetFocus ()) {
1066                        int uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1067                        if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
1068                    }
1069                }
1070            }
1071            event.x = cellRect.left;
1072            event.y = cellRect.top;
1073            event.width = cellRect.right - cellRect.left;
1074            event.height = cellRect.bottom - cellRect.top;
1075            gc.setClipping (event.x, event.y, event.width, event.height);
1076            sendEvent (SWT.EraseItem, event);
1077            event.gc = null;
1078            int newTextClr = data.foreground;
1079            gc.dispose ();
1080            OS.RestoreDC (hDC, nSavedDC);
1081            if (isDisposed () || item.isDisposed ()) return null;
1082            if (event.doit) {
1083                ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
1084                ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
1085                ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
1086                ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
1087                ignoreDrawHot = (event.detail & SWT.HOT) == 0;
1088            } else {
1089                ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
1090            }
1091            if (selected && ignoreDrawSelection) ignoreDrawHot = true;
1092            if (!ignoreDrawBackground && clrTextBk != -1) {
1093                boolean draw = !selected && !hot;
1094                if (!explorerTheme && selected) draw = !ignoreDrawSelection;
1095                if (draw) {
1096                    if (count == 0) {
1097                        if ((style & SWT.FULL_SELECTION) != 0) {
1098                            fillBackground (hDC, clrTextBk, rect);
1099                        } else {
1100                            RECT textRect = item.getBounds (index, true, false, true, false, true, hDC);
1101                            fillBackground (hDC, clrTextBk, textRect);
1102                        }
1103                    } else {
1104                        fillBackground (hDC, clrTextBk, cellRect);
1105                    }
1106                }
1107            }
1108            if (ignoreDrawSelection) ignoreFullSelection = true;
1109            if (!ignoreDrawSelection || !ignoreDrawHot) {
1110                if (!selected && !hot) {
1111                    selectionForeground = clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
1112                }
1113                if (!explorerTheme) {
1114                    /*
1115                    * Feature in Windows. When the tree has the style
1116                    * TVS_FULLROWSELECT, the background color for the
1117                    * entire row is filled when an item is painted,
1118                    * drawing on top of any custom drawing. The fix
1119                    * is to emulate TVS_FULLROWSELECT.
1120                    */

1121                    if ((style & SWT.FULL_SELECTION) != 0) {
1122                        if ((style & SWT.FULL_SELECTION) != 0 && count == 0) {
1123                            fillBackground (hDC, OS.GetBkColor (hDC), rect);
1124                        } else {
1125                            fillBackground (hDC, OS.GetBkColor (hDC), cellRect);
1126                        }
1127                    } else {
1128                        RECT textRect = item.getBounds (index, true, false, false, false, true, hDC);
1129                        fillBackground (hDC, OS.GetBkColor (hDC), textRect);
1130                    }
1131                }
1132            } else {
1133                if (selected || hot) {
1134                    selectionForeground = clrText = newTextClr;
1135                    ignoreDrawSelection = ignoreDrawHot = true;
1136                }
1137                if (explorerTheme) {
1138                    nmcd.uItemState |= OS.CDIS_DISABLED;
1139                    /*
1140                    * Feature in Windows. On Vista only, when the text
1141                    * color is unchanged and an item is asked to draw
1142                    * disabled, it uses the disabled color. The fix is
1143                    * to modify the color so that is it no longer equal.
1144                    */

1145                    int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1146                    if (nmcd.clrText == newColor) {
1147                        nmcd.clrText |= 0x20000000;
1148                        if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1149                    } else {
1150                        nmcd.clrText = newColor;
1151                    }
1152                    OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1153                }
1154            }
1155            if (explorerTheme) {
1156                if (selected || (hot && ignoreDrawHot)) nmcd.uItemState &= ~OS.CDIS_HOT;
1157                OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1158            }
1159            RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
1160            OS.SaveDC (hDC);
1161            OS.SelectClipRgn (hDC, 0);
1162            if (explorerTheme) {
1163                itemRect.left -= EXPLORER_EXTRA;
1164                itemRect.right += EXPLORER_EXTRA;
1165            }
1166            //TODO - bug in Windows selection or SWT itemRect
1167
/*if (selected)*/ itemRect.right++;
1168            if (linesVisible) itemRect.bottom++;
1169            if (clipRect != null) {
1170                OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1171            }
1172            OS.ExcludeClipRect (hDC, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
1173            return new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1174        }
1175        /*
1176        * Feature in Windows. When the tree has the style
1177        * TVS_FULLROWSELECT, the background color for the
1178        * entire row is filled when an item is painted,
1179        * drawing on top of any custom drawing. The fix
1180        * is to emulate TVS_FULLROWSELECT.
1181        */

1182        if ((style & SWT.FULL_SELECTION) != 0) {
1183            int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1184            if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1185                RECT rect = new RECT ();
1186                OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1187                if (selected) {
1188                    fillBackground (hDC, OS.GetBkColor (hDC), rect);
1189                } else {
1190                    if (OS.IsWindowEnabled (handle)) drawBackground (hDC, rect);
1191                }
1192                nmcd.uItemState &= ~OS.CDIS_FOCUS;
1193                OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1194            }
1195        }
1196    }
1197    LRESULT result = null;
1198    if (clrText == -1 && clrTextBk == -1 && hFont == -1) {
1199        result = new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1200    } else {
1201        result = new LRESULT (OS.CDRF_NEWFONT | OS.CDRF_NOTIFYPOSTPAINT);
1202        if (hFont != -1) OS.SelectObject (hDC, hFont);
1203        if (OS.IsWindowEnabled (handle) && OS.IsWindowVisible (handle)) {
1204            /*
1205            * Feature in Windows. Windows does not fill the entire cell
1206            * with the background color when TVS_FULLROWSELECT is not set.
1207            * The fix is to fill the cell with the background color.
1208            */

1209            if (clrTextBk != -1) {
1210                int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1211                if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1212                    if (count != 0 && hwndHeader != 0) {
1213                        RECT rect = new RECT ();
1214                        HDITEM hdItem = new HDITEM ();
1215                        hdItem.mask = OS.HDI_WIDTH;
1216                        OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1217                        OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1218                        if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
1219                            RECT itemRect = new RECT ();
1220                            itemRect.left = item.handle;
1221                            if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) != 0) {
1222                                rect.left = Math.min (itemRect.left, rect.right);
1223                            }
1224                        }
1225                        if ((style & SWT.FULL_SELECTION) != 0) {
1226                            if (!selected) fillBackground (hDC, clrTextBk, rect);
1227                        } else {
1228                            if (explorerTheme) {
1229                                if (!selected && !hot) fillBackground (hDC, clrTextBk, rect);
1230                            } else {
1231                                fillBackground (hDC, clrTextBk, rect);
1232                            }
1233                        }
1234                    } else {
1235                        if ((style & SWT.FULL_SELECTION) != 0) {
1236                            RECT rect = new RECT ();
1237                            OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1238                            if (!selected) fillBackground (hDC, clrTextBk, rect);
1239                        }
1240                    }
1241                }
1242            }
1243            if (!selected) {
1244                nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
1245                nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;
1246                OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1247            }
1248        }
1249    }
1250    if (OS.IsWindowEnabled (handle)) {
1251        /*
1252        * On Vista only, when an item is asked to draw disabled,
1253        * the background of the text is not filled with the
1254        * background color of the tree. This is true for both
1255        * regular and full selection trees. In order to draw a
1256        * background image, mark the item as disabled using
1257        * CDIS_DISABLED (when not selected) and set the text
1258        * to the regular text color to avoid drawing disabled.
1259        */

1260        if (explorerTheme) {
1261            if (findImageControl () != null) {
1262                if (!selected && (nmcd.uItemState & (OS.CDIS_HOT | OS.CDIS_SELECTED)) == 0) {
1263                    nmcd.uItemState |= OS.CDIS_DISABLED;
1264                    /*
1265                    * Feature in Windows. On Vista only, when the text
1266                    * color is unchanged and an item is asked to draw
1267                    * disabled, it uses the disabled color. The fix is
1268                    * to modify the color so it is no longer equal.
1269                    */

1270                    int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1271                    if (nmcd.clrText == newColor) {
1272                        nmcd.clrText |= 0x20000000;
1273                        if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1274                    } else {
1275                        nmcd.clrText = newColor;
1276                    }
1277                    OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1278                    if (clrTextBk != -1) {
1279                        if ((style & SWT.FULL_SELECTION) != 0) {
1280                            RECT rect = new RECT ();
1281                            if (count != 0) {
1282                                HDITEM hdItem = new HDITEM ();
1283                                hdItem.mask = OS.HDI_WIDTH;
1284                                OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1285                                OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1286                            } else {
1287                                OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1288                            }
1289                            fillBackground (hDC, clrTextBk, rect);
1290                        } else {
1291                            RECT textRect = item.getBounds (index, true, false, true, false, true, hDC);
1292                            fillBackground (hDC, clrTextBk, textRect);
1293                        }
1294                    }
1295                }
1296            }
1297        }
1298    } else {
1299        /*
1300        * Feature in Windows. When the tree is disabled, it draws
1301        * with a gray background over the sort column. The fix is
1302        * to fill the background with the sort column color.
1303        */

1304        if (clrSortBk != -1) {
1305            RECT rect = new RECT ();
1306            HDITEM hdItem = new HDITEM ();
1307            hdItem.mask = OS.HDI_WIDTH;
1308            OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1309            OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1310            fillBackground (hDC, clrSortBk, rect);
1311        }
1312    }
1313    OS.SaveDC (hDC);
1314    if (clipRect != null) {
1315        int hRgn = OS.CreateRectRgn (clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1316        POINT lpPoint = new POINT ();
1317        OS.GetWindowOrgEx (hDC, lpPoint);
1318        OS.OffsetRgn (hRgn, -lpPoint.x, -lpPoint.y);
1319        OS.SelectClipRgn (hDC, hRgn);
1320        OS.DeleteObject (hRgn);
1321    }
1322    return result;
1323}
1324
1325LRESULT CDDS_POSTPAINT (NMTVCUSTOMDRAW nmcd, int wParam, int lParam) {
1326    if (ignoreCustomDraw) return null;
1327    if (OS.IsWindowVisible (handle)) {
1328        if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
1329            if (sortColumn != null && sortDirection != SWT.NONE) {
1330                if (findImageControl () == null) {
1331                    int index = indexOf (sortColumn);
1332                    if (index != -1) {
1333                        int top = nmcd.top;
1334                        /*
1335                        * Bug in Windows. For some reason, during a collapse,
1336                        * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1337                        * and the collapse causes the item being collapsed
1338                        * to become the last visible item in the tree, the
1339                        * message takes a long time to process. In order for
1340                        * the slowness to happen, the children of the item
1341                        * must have children. Times of up to 11 seconds have
1342                        * been observed with 23 children, each having one
1343                        * child. The fix is to use the bottom partially
1344                        * visible item rather than the last possible item
1345                        * that could be visible.
1346                        *
1347                        * NOTE: This problem only happens on Vista during
1348                        * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1349                        */

1350                        int hItem = 0;
1351                        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1352                            hItem = getBottomItem ();
1353                        } else {
1354                            hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1355                        }
1356                        if (hItem != 0) {
1357                            RECT rect = new RECT ();
1358                            rect.left = hItem;
1359                            if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
1360                                top = rect.bottom;
1361                            }
1362                        }
1363                        RECT rect = new RECT ();
1364                        OS.SetRect (rect, nmcd.left, top, nmcd.right, nmcd.bottom);
1365                        RECT headerRect = new RECT ();
1366                        OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
1367                        rect.left = headerRect.left;
1368                        rect.right = headerRect.right;
1369                        fillBackground (nmcd.hdc, getSortColumnPixel (), rect);
1370                    }
1371                }
1372            }
1373        }
1374        if (linesVisible) {
1375            int hDC = nmcd.hdc;
1376            if (hwndHeader != 0) {
1377                int x = 0;
1378                RECT rect = new RECT ();
1379                HDITEM hdItem = new HDITEM ();
1380                hdItem.mask = OS.HDI_WIDTH;
1381                int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
1382                for (int i=0; i<count; i++) {
1383                    int index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, i, 0);
1384                    OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1385                    OS.SetRect (rect, x, nmcd.top, x + hdItem.cxy, nmcd.bottom);
1386                    OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_RIGHT);
1387                    x += hdItem.cxy;
1388                }
1389            }
1390            int height = 0;
1391            RECT rect = new RECT ();
1392            /*
1393            * Bug in Windows. For some reason, during a collapse,
1394            * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1395            * and the collapse causes the item being collapsed
1396            * to become the last visible item in the tree, the
1397            * message takes a long time to process. In order for
1398            * the slowness to happen, the children of the item
1399            * must have children. Times of up to 11 seconds have
1400            * been observed with 23 children, each having one
1401            * child. The fix is to use the bottom partially
1402            * visible item rather than the last possible item
1403            * that could be visible.
1404            *
1405            * NOTE: This problem only happens on Vista during
1406            * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1407            */

1408            int hItem = 0;
1409            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1410                hItem = getBottomItem ();
1411            } else {
1412                hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1413            }
1414            if (hItem != 0) {
1415                rect.left = hItem;
1416                if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
1417                    height = rect.bottom - rect.top;
1418                }
1419            }
1420            if (height == 0) {
1421                height = OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
1422                OS.GetClientRect (handle, rect);
1423                OS.SetRect (rect, rect.left, rect.top, rect.right, rect.top + height);
1424                OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1425            }
1426            while (rect.bottom < nmcd.bottom) {
1427                int top = rect.top + height;
1428                OS.SetRect (rect, rect.left, top, rect.right, top + height);
1429                OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1430            }
1431        }
1432    }
1433    return new LRESULT (OS.CDRF_DODEFAULT);
1434}
1435
1436LRESULT CDDS_PREPAINT (NMTVCUSTOMDRAW nmcd, int wParam, int lParam) {
1437    if (explorerTheme) {
1438        if ((OS.IsWindowEnabled (handle) && hooks (SWT.EraseItem)) || findImageControl () != null) {
1439            RECT rect = new RECT ();
1440            OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1441            drawBackground (nmcd.hdc, rect);
1442        }
1443    }
1444    return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
1445}
1446
1447int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
1448    if (handle == 0) return 0;
1449    if (hwndParent != 0 && hwnd == hwndParent) {
1450        return OS.DefWindowProc (hwnd, msg, wParam, lParam);
1451    }
1452    if (hwndHeader != 0 && hwnd == hwndHeader) {
1453        return OS.CallWindowProc (HeaderProc, hwnd, msg, wParam, lParam);
1454    }
1455    switch (msg) {
1456        case OS.WM_SETFOCUS: {
1457            /*
1458            * Feature in Windows. When a tree control processes WM_SETFOCUS,
1459            * if no item is selected, the first item in the tree is selected.
1460            * This is unexpected and might clear the previous selection.
1461            * The fix is to detect that there is no selection and set it to
1462            * the first visible item in the tree. If the item was not selected,
1463            * only the focus is assigned.
1464            */

1465            if ((style & SWT.SINGLE) != 0) break;
1466            int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
1467            if (hItem == 0) {
1468                hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1469                if (hItem != 0) {
1470                    TVITEM tvItem = new TVITEM ();
1471                    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
1472                    tvItem.hItem = hItem;
1473                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
1474                    hSelect = hItem;
1475                    ignoreDeselect = ignoreSelect = lockSelection = true;
1476                    OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem);
1477                    ignoreDeselect = ignoreSelect = lockSelection = false;
1478                    hSelect = 0;
1479                    if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
1480                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1481                    }
1482                }
1483            }
1484            break;
1485        }
1486    }
1487    int hItem = 0;
1488    boolean redraw = false;
1489    switch (msg) {
1490        /* Keyboard messages */
1491        case OS.WM_KEYDOWN:
1492            if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1493            //FALL THROUGH
1494
case OS.WM_CHAR:
1495        case OS.WM_IME_CHAR:
1496        case OS.WM_KEYUP:
1497        case OS.WM_SYSCHAR:
1498        case OS.WM_SYSKEYDOWN:
1499        case OS.WM_SYSKEYUP:
1500            //FALL THROUGH
1501

1502        /* Scroll messages */
1503        case OS.WM_HSCROLL:
1504        case OS.WM_VSCROLL:
1505            //FALL THROUGH
1506

1507        /* Resize messages */
1508        case OS.WM_SIZE:
1509            redraw = findImageControl () != null && drawCount == 0 && OS.IsWindowVisible (handle);
1510            if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
1511            //FALL THROUGH
1512

1513        /* Mouse messages */
1514        case OS.WM_LBUTTONDBLCLK:
1515        case OS.WM_LBUTTONDOWN:
1516        case OS.WM_LBUTTONUP:
1517        case OS.WM_MBUTTONDBLCLK:
1518        case OS.WM_MBUTTONDOWN:
1519        case OS.WM_MBUTTONUP:
1520        case OS.WM_MOUSEHOVER:
1521        case OS.WM_MOUSELEAVE:
1522        case OS.WM_MOUSEMOVE:
1523        case OS.WM_MOUSEWHEEL:
1524        case OS.WM_RBUTTONDBLCLK:
1525        case OS.WM_RBUTTONDOWN:
1526        case OS.WM_RBUTTONUP:
1527        case OS.WM_XBUTTONDBLCLK:
1528        case OS.WM_XBUTTONDOWN:
1529        case OS.WM_XBUTTONUP:
1530            //FALL THROUGH
1531

1532        /* Other messages */
1533        case OS.WM_SETFONT:
1534        case OS.WM_TIMER: {
1535            if (findImageControl () != null) {
1536                hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1537            }
1538            break;
1539        }
1540    }
1541    int code = OS.CallWindowProc (TreeProc, hwnd, msg, wParam, lParam);
1542    switch (msg) {
1543        /* Keyboard messages */
1544        case OS.WM_KEYDOWN:
1545            if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1546            //FALL THROUGH
1547
case OS.WM_CHAR:
1548        case OS.WM_IME_CHAR:
1549        case OS.WM_KEYUP:
1550        case OS.WM_SYSCHAR:
1551        case OS.WM_SYSKEYDOWN:
1552        case OS.WM_SYSKEYUP:
1553            //FALL THROUGH
1554

1555        /* Scroll messages */
1556        case OS.WM_HSCROLL:
1557        case OS.WM_VSCROLL:
1558            //FALL THROUGH
1559

1560        /* Resize messages */
1561        case OS.WM_SIZE:
1562            if (redraw) {
1563                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
1564                OS.InvalidateRect (handle, null, true);
1565                if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
1566            }
1567            //FALL THROUGH
1568

1569        /* Mouse messages */
1570        case OS.WM_LBUTTONDBLCLK:
1571        case OS.WM_LBUTTONDOWN:
1572        case OS.WM_LBUTTONUP:
1573        case OS.WM_MBUTTONDBLCLK:
1574        case OS.WM_MBUTTONDOWN:
1575        case OS.WM_MBUTTONUP:
1576        case OS.WM_MOUSEHOVER:
1577        case OS.WM_MOUSELEAVE:
1578        case OS.WM_MOUSEMOVE:
1579        case OS.WM_MOUSEWHEEL:
1580        case OS.WM_RBUTTONDBLCLK:
1581        case OS.WM_RBUTTONDOWN:
1582        case OS.WM_RBUTTONUP:
1583        case OS.WM_XBUTTONDBLCLK:
1584        case OS.WM_XBUTTONDOWN:
1585        case OS.WM_XBUTTONUP:
1586            //FALL THROUGH
1587

1588        /* Other messages */
1589        case OS.WM_SETFONT:
1590        case OS.WM_TIMER: {
1591            if (findImageControl () != null) {
1592                if (hItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) {
1593                    OS.InvalidateRect (handle, null, true);
1594                }
1595            }
1596            updateScrollBar ();
1597            break;
1598        }
1599        
1600        case OS.WM_PAINT:
1601            painted = true;
1602            break;
1603    }
1604    return code;
1605}
1606
1607void checkBuffered () {
1608    super.checkBuffered ();
1609    if ((style & SWT.VIRTUAL) != 0) {
1610        style |= SWT.DOUBLE_BUFFERED;
1611        OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
1612    }
1613    if (EXPLORER_THEME) {
1614        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1615            int exStyle = OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
1616            if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) style |= SWT.DOUBLE_BUFFERED;
1617        }
1618    }
1619}
1620
1621boolean checkData (TreeItem item, boolean redraw) {
1622    if ((style & SWT.VIRTUAL) == 0) return true;
1623    TreeItem parentItem = item.getParentItem ();
1624    return checkData (item, parentItem == null ? indexOf (item) : parentItem.indexOf (item), redraw);
1625}
1626
1627boolean checkData (TreeItem item, int index, boolean redraw) {
1628    if ((style & SWT.VIRTUAL) == 0) return true;
1629    if (!item.cached) {
1630        item.cached = true;
1631        Event event = new Event ();
1632        event.item = item;
1633        event.index = index;
1634        TreeItem oldItem = currentItem;
1635        currentItem = item;
1636        sendEvent (SWT.SetData, event);
1637        //widget could be disposed at this point
1638
currentItem = oldItem;
1639        if (isDisposed () || item.isDisposed ()) return false;
1640        if (redraw) item.redraw ();
1641    }
1642    return true;
1643}
1644
1645boolean checkHandle (int hwnd) {
1646    return hwnd == handle || (hwndParent != 0 && hwnd == hwndParent) || (hwndHeader != 0 && hwnd == hwndHeader);
1647}
1648
1649boolean checkScroll (int hItem) {
1650    /*
1651    * Feature in Windows. If redraw is turned off using WM_SETREDRAW
1652    * and a tree item that is not a child of the first root is selected or
1653    * scrolled using TVM_SELECTITEM or TVM_ENSUREVISIBLE, then scrolling
1654    * does not occur. The fix is to detect this case, and make sure
1655    * that redraw is temporarily enabled. To avoid flashing, DefWindowProc()
1656    * is called to disable redrawing.
1657    *
1658    * NOTE: The code that actually works around the problem is in the
1659    * callers of this method.
1660    */

1661    if (drawCount == 0) return false;
1662    int hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1663    int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
1664    while (hParent != hRoot && hParent != 0) {
1665        hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hParent);
1666    }
1667    return hParent == 0;
1668}
1669
1670protected void checkSubclass () {
1671    if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
1672}
1673
1674/**
1675 * Clears the item at the given zero-relative index in the receiver.
1676 * The text, icon and other attributes of the item are set to the default
1677 * value. If the tree was created with the <code>SWT.VIRTUAL</code> style,
1678 * these attributes are requested again as needed.
1679 *
1680 * @param index the index of the item to clear
1681 * @param all <code>true</code> if all child items of the indexed item should be
1682 * cleared recursively, and <code>false</code> otherwise
1683 *
1684 * @exception IllegalArgumentException <ul>
1685 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1686 * </ul>
1687 * @exception SWTException <ul>
1688 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1689 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1690 * </ul>
1691 *
1692 * @see SWT#VIRTUAL
1693 * @see SWT#SetData
1694 *
1695 * @since 3.2
1696 */

1697public void clear (int index, boolean all) {
1698    checkWidget ();
1699    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1700    if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1701    hItem = findItem (hItem, index);
1702    if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1703    TVITEM tvItem = new TVITEM ();
1704    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1705    clear (hItem, tvItem);
1706    if (all) {
1707        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1708        clearAll (hItem, tvItem, all);
1709    }
1710}
1711
1712void clear (int hItem, TVITEM tvItem) {
1713    tvItem.hItem = hItem;
1714    TreeItem item = null;
1715    if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
1716        item = tvItem.lParam != -1 ? items [tvItem.lParam] : null;
1717    }
1718    if (item != null) {
1719        item.clear ();
1720        item.redraw ();
1721    }
1722}
1723
1724/**
1725 * Clears all the items in the receiver. The text, icon and other
1726 * attributes of the items are set to their default values. If the
1727 * tree was created with the <code>SWT.VIRTUAL</code> style, these
1728 * attributes are requested again as needed.
1729 *
1730 * @param all <code>true</code> if all child items should be cleared
1731 * recursively, and <code>false</code> otherwise
1732 *
1733 * @exception SWTException <ul>
1734 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1735 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1736 * </ul>
1737 *
1738 * @see SWT#VIRTUAL
1739 * @see SWT#SetData
1740 *
1741 * @since 3.2
1742 */

1743public void clearAll (boolean all) {
1744    checkWidget ();
1745    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1746    if (hItem == 0) return;
1747    TVITEM tvItem = new TVITEM ();
1748    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1749    clearAll (hItem, tvItem, all);
1750}
1751
1752void clearAll (int hItem, TVITEM tvItem, boolean all) {
1753    while (hItem != 0) {
1754        clear (hItem, tvItem);
1755        int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1756        if (all) clearAll (hFirstItem, tvItem, all);
1757        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
1758    }
1759}
1760
1761int CompareFunc (int lParam1, int lParam2, int lParamSort) {
1762    TreeItem item1 = items [lParam1], item2 = items [lParam2];
1763    String JavaDoc text1 = item1.getText (lParamSort), text2 = item2.getText (lParamSort);
1764    return sortDirection == SWT.UP ? text1.compareTo (text2) : text2.compareTo (text1);
1765}
1766
1767public Point computeSize (int wHint, int hHint, boolean changed) {
1768    checkWidget ();
1769    int width = 0, height = 0;
1770    if (hwndHeader != 0) {
1771        HDITEM hdItem = new HDITEM ();
1772        hdItem.mask = OS.HDI_WIDTH;
1773        int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
1774        for (int i=0; i<count; i++) {
1775            OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
1776            width += hdItem.cxy;
1777        }
1778        RECT rect = new RECT ();
1779        OS.GetWindowRect (hwndHeader, rect);
1780        height += rect.bottom - rect.top;
1781    }
1782    RECT rect = new RECT ();
1783    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1784    while (hItem != 0) {
1785        if ((style & SWT.VIRTUAL) == 0 && !painted) {
1786            TVITEM tvItem = new TVITEM ();
1787            tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1788            tvItem.hItem = hItem;
1789            tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1790            ignoreCustomDraw = true;
1791            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1792            ignoreCustomDraw = false;
1793        }
1794        rect.left = hItem;
1795        if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, rect) != 0) {
1796            width = Math.max (width, rect.right);
1797            height += rect.bottom - rect.top;
1798        }
1799        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
1800    }
1801    if (width == 0) width = DEFAULT_WIDTH;
1802    if (height == 0) height = DEFAULT_HEIGHT;
1803    if (wHint != SWT.DEFAULT) width = wHint;
1804    if (hHint != SWT.DEFAULT) height = hHint;
1805    int border = getBorderWidth ();
1806    width += border * 2;
1807    height += border * 2;
1808    if ((style & SWT.V_SCROLL) != 0) {
1809        width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
1810    }
1811    if ((style & SWT.H_SCROLL) != 0) {
1812        height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
1813    }
1814    return new Point (width, height);
1815}
1816
1817void createHandle () {
1818    super.createHandle ();
1819    state &= ~(CANVAS | THEME_BACKGROUND);
1820
1821    /* Use the Explorer theme */
1822    if (EXPLORER_THEME) {
1823        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1824            explorerTheme = true;
1825            OS.SetWindowTheme (handle, Display.EXPLORER, null);
1826            int bits = OS.TVS_EX_DOUBLEBUFFER | OS.TVS_EX_FADEINOUTEXPANDOS | OS.TVS_EX_RICHTOOLTIP;
1827            if ((style & SWT.FULL_SELECTION) == 0) bits |= OS.TVS_EX_AUTOHSCROLL;
1828            OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits);
1829            /*
1830            * Bug in Windows. When the tree is using the explorer
1831            * theme, it does not use COLOR_WINDOW_TEXT for the
1832            * default foreground color. The fix is to explicitly
1833            * set the foreground.
1834            */

1835            setForegroundPixel (-1);
1836        }
1837    }
1838
1839    /*
1840    * Feature in Windows. In version 5.8 of COMCTL32.DLL,
1841    * if the font is changed for an item, the bounds for the
1842    * item are not updated, causing the text to be clipped.
1843    * The fix is to detect the version of COMCTL32.DLL, and
1844    * if it is one of the versions with the problem, then
1845    * use version 5.00 of the control (a version that does
1846    * not have the problem). This is the recommended work
1847    * around from the MSDN.
1848    */

1849    if (!OS.IsWinCE) {
1850        if (OS.COMCTL32_MAJOR < 6) {
1851            OS.SendMessage (handle, OS.CCM_SETVERSION, 5, 0);
1852        }
1853    }
1854        
1855    /* Set the checkbox image list */
1856    if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
1857    
1858    /*
1859    * Feature in Windows. When the control is created,
1860    * it does not use the default system font. A new HFONT
1861    * is created and destroyed when the control is destroyed.
1862    * This means that a program that queries the font from
1863    * this control, uses the font in another control and then
1864    * destroys this control will have the font unexpectedly
1865    * destroyed in the other control. The fix is to assign
1866    * the font ourselves each time the control is created.
1867    * The control will not destroy a font that it did not
1868    * create.
1869    */

1870    int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
1871    OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
1872}
1873
1874void createHeaderToolTips () {
1875    if (OS.IsWinCE) return;
1876    if (headerToolTipHandle != 0) return;
1877    headerToolTipHandle = OS.CreateWindowEx (
1878        0,
1879        new TCHAR (0, OS.TOOLTIPS_CLASS, true),
1880        null,
1881        0,
1882        OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
1883        handle,
1884        0,
1885        OS.GetModuleHandle (null),
1886        null);
1887    if (headerToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
1888    /*
1889    * Feature in Windows. Despite the fact that the
1890    * tool tip text contains \r\n, the tooltip will
1891    * not honour the new line unless TTM_SETMAXTIPWIDTH
1892    * is set. The fix is to set TTM_SETMAXTIPWIDTH to
1893    * a large value.
1894    */

1895    OS.SendMessage (headerToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
1896}
1897
1898void createItem (TreeColumn column, int index) {
1899    if (hwndHeader == 0) createParent ();
1900    int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
1901    if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
1902    if (columnCount == columns.length) {
1903        TreeColumn [] newColumns = new TreeColumn [columns.length + 4];
1904        System.arraycopy (columns, 0, newColumns, 0, columns.length);
1905        columns = newColumns;
1906    }
1907    for (int i=0; i<items.length; i++) {
1908        TreeItem item = items [i];
1909        if (item != null) {
1910            String JavaDoc [] strings = item.strings;
1911            if (strings != null) {
1912                String JavaDoc [] temp = new String JavaDoc [columnCount + 1];
1913                System.arraycopy (strings, 0, temp, 0, index);
1914                System.arraycopy (strings, index, temp, index + 1, columnCount - index);
1915                item.strings = temp;
1916            }
1917            Image [] images = item.images;
1918            if (images != null) {
1919                Image [] temp = new Image [columnCount + 1];
1920                System.arraycopy (images, 0, temp, 0, index);
1921                System.arraycopy (images, index, temp, index + 1, columnCount - index);
1922                item.images = temp;
1923            }
1924            if (index == 0) {
1925                if (columnCount != 0) {
1926                    if (strings == null) {
1927                        item.strings = new String JavaDoc [columnCount + 1];
1928                        item.strings [1] = item.text;
1929                    }
1930                    item.text = "";
1931                    if (images == null) {
1932                        item.images = new Image [columnCount + 1];
1933                        item.images [1] = item.image;
1934                    }
1935                    item.image = null;
1936                }
1937            }
1938            if (item.cellBackground != null) {
1939                int [] cellBackground = item.cellBackground;
1940                int [] temp = new int [columnCount + 1];
1941                System.arraycopy (cellBackground, 0, temp, 0, index);
1942                System.arraycopy (cellBackground, index, temp, index + 1, columnCount - index);
1943                temp [index] = -1;
1944                item.cellBackground = temp;
1945            }
1946            if (item.cellForeground != null) {
1947                int [] cellForeground = item.cellForeground;
1948                int [] temp = new int [columnCount + 1];
1949                System.arraycopy (cellForeground, 0, temp, 0, index);
1950                System.arraycopy (cellForeground, index, temp, index + 1, columnCount - index);
1951                temp [index] = -1;
1952                item.cellForeground = temp;
1953            }
1954            if (item.cellFont != null) {
1955                int [] cellFont = item.cellFont;
1956                int [] temp = new int [columnCount + 1];
1957                System.arraycopy (cellFont, 0, temp, 0, index);
1958                System.arraycopy (cellFont, index, temp, index + 1, columnCount- index);
1959                temp [index] = -1;
1960                item.cellFont = temp;
1961            }
1962        }
1963    }
1964    System.arraycopy (columns, index, columns, index + 1, columnCount - index);
1965    columns [index] = column;
1966    
1967    /*
1968    * Bug in Windows. For some reason, when HDM_INSERTITEM
1969    * is used to insert an item into a header without text,
1970    * if is not possible to set the text at a later time.
1971    * The fix is to insert the item with an empty string.
1972    */

1973    int hHeap = OS.GetProcessHeap ();
1974    int pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
1975    HDITEM hdItem = new HDITEM ();
1976    hdItem.mask = OS.HDI_TEXT | OS.HDI_FORMAT;
1977    hdItem.pszText = pszText;
1978    if ((column.style & SWT.LEFT) == SWT.LEFT) hdItem.fmt = OS.HDF_LEFT;
1979    if ((column.style & SWT.CENTER) == SWT.CENTER) hdItem.fmt = OS.HDF_CENTER;
1980    if ((column.style & SWT.RIGHT) == SWT.RIGHT) hdItem.fmt = OS.HDF_RIGHT;
1981    OS.SendMessage (hwndHeader, OS.HDM_INSERTITEM, index, hdItem);
1982    if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
1983    
1984    /* When the first column is created, hide the horizontal scroll bar */
1985    if (columnCount == 0) {
1986        scrollWidth = 0;
1987        int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1988        bits |= OS.TVS_NOHSCROLL;
1989        OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
1990        /*
1991        * Bug in Windows. When TVS_NOHSCROLL is set after items
1992        * have been inserted into the tree, Windows shows the
1993        * scroll bar. The fix is to check for this case and
1994        * explicitly hide the scroll bar explicitly.
1995        */

1996        int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
1997        if (count != 0) {
1998            if (!OS.IsWinCE) OS.ShowScrollBar (handle, OS.SB_HORZ, false);
1999        }
2000    }
2001    setScrollWidth ();
2002    updateImageList ();
2003    updateScrollBar ();
2004    
2005    /* Redraw to hide the items when the first column is created */
2006    if (columnCount == 0 && OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) != 0) {
2007        OS.InvalidateRect (handle, null, true);
2008    }
2009    
2010    /* Add the tool tip item for the header */
2011    if (headerToolTipHandle != 0) {
2012        RECT rect = new RECT ();
2013        if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, rect) != 0) {
2014            TOOLINFO lpti = new TOOLINFO ();
2015            lpti.cbSize = TOOLINFO.sizeof;
2016            lpti.uFlags = OS.TTF_SUBCLASS;
2017            lpti.hwnd = hwndHeader;
2018            lpti.uId = column.id = display.nextToolTipId++;
2019            lpti.left = rect.left;
2020            lpti.top = rect.top;
2021            lpti.right = rect.right;
2022            lpti.bottom = rect.bottom;
2023            lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2024            OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2025        }
2026    }
2027}
2028
2029void createItem (TreeItem item, int hParent, int hInsertAfter, int hItem) {
2030    int id = -1;
2031    if (item != null) {
2032        id = lastID < items.length ? lastID : 0;
2033        while (id < items.length && items [id] != null) id++;
2034        if (id == items.length) {
2035            /*
2036            * Grow the array faster when redraw is off or the
2037            * table is not visible. When the table is painted,
2038            * the items array is resized to be smaller to reduce
2039            * memory usage.
2040            */

2041            int length = 0;
2042            if (drawCount == 0 && OS.IsWindowVisible (handle)) {
2043                length = items.length + 4;
2044            } else {
2045                shrink = true;
2046                length = Math.max (4, items.length * 3 / 2);
2047            }
2048            TreeItem [] newItems = new TreeItem [length];
2049            System.arraycopy (items, 0, newItems, 0, items.length);
2050            items = newItems;
2051        }
2052        lastID = id + 1;
2053    }
2054    int hNewItem = 0;
2055    int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
2056    boolean fixParent = hFirstItem == 0;
2057    if (hItem == 0) {
2058        TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
2059        tvInsert.hParent = hParent;
2060        tvInsert.hInsertAfter = hInsertAfter;
2061        tvInsert.lParam = id;
2062        tvInsert.pszText = OS.LPSTR_TEXTCALLBACK;
2063        tvInsert.iImage = tvInsert.iSelectedImage = OS.I_IMAGECALLBACK;
2064        tvInsert.mask = OS.TVIF_TEXT | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE | OS.TVIF_HANDLE | OS.TVIF_PARAM;
2065        if ((style & SWT.CHECK) != 0) {
2066            tvInsert.mask = tvInsert.mask | OS.TVIF_STATE;
2067            tvInsert.state = 1 << 12;
2068            tvInsert.stateMask = OS.TVIS_STATEIMAGEMASK;
2069        }
2070        ignoreCustomDraw = true;
2071        hNewItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
2072        ignoreCustomDraw = false;
2073        if (hNewItem == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
2074        /*
2075        * This code is intentionally commented.
2076        */

2077// if (hParent != 0) {
2078
// int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2079
// bits |= OS.TVS_LINESATROOT;
2080
// OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2081
// }
2082
} else {
2083        TVITEM tvItem = new TVITEM ();
2084        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
2085        tvItem.hItem = hNewItem = hItem;
2086        tvItem.lParam = id;
2087        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2088    }
2089    if (item != null) {
2090        item.handle = hNewItem;
2091        items [id] = item;
2092    }
2093    if (hFirstItem == 0) {
2094        switch (hInsertAfter) {
2095            case OS.TVI_FIRST:
2096            case OS.TVI_LAST:
2097                hFirstIndexOf = hLastIndexOf = hFirstItem = hNewItem;
2098                itemCount = lastIndexOf = 0;
2099        }
2100    }
2101    if (hFirstItem == hFirstIndexOf && itemCount != -1) itemCount++;
2102    if (hItem == 0) {
2103        /*
2104        * Bug in Windows. When a child item is added to a parent item
2105        * that has no children outside of WM_NOTIFY with control code
2106        * TVN_ITEMEXPANDED, the tree widget does not redraw the +/-
2107        * indicator. The fix is to detect the case when the first
2108        * child is added to a visible parent item and redraw the parent.
2109        */

2110        if (fixParent) {
2111            if (drawCount == 0 && OS.IsWindowVisible (handle)) {
2112                RECT rect = new RECT ();
2113                rect.left = hParent;
2114                if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
2115                    OS.InvalidateRect (handle, rect, true);
2116                }
2117            }
2118        }
2119        /*
2120        * Bug in Windows. When a new item is added while Windows
2121        * is requesting data a tree item using TVN_GETDISPINFO,
2122        * outstanding damage for items that are below the new item
2123        * is not scrolled. The fix is to explicitly damage the
2124        * new area.
2125        */

2126        if ((style & SWT.VIRTUAL) != 0) {
2127            if (currentItem != null) {
2128                RECT rect = new RECT ();
2129                rect.left = hNewItem;
2130                if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
2131                    RECT damageRect = new RECT ();
2132                    boolean damaged = OS.GetUpdateRect (handle, damageRect, true);
2133                    if (damaged && damageRect.top < rect.bottom) {
2134                        if (OS.IsWinCE) {
2135                            OS.OffsetRect (damageRect, 0, rect.bottom - rect.top);
2136                            OS.InvalidateRect (handle, damageRect, true);
2137                        } else {
2138                            int rgn = OS.CreateRectRgn (0, 0, 0, 0);
2139                            int result = OS.GetUpdateRgn (handle, rgn, true);
2140                            if (result != OS.NULLREGION) {
2141                                OS.OffsetRgn (rgn, 0, rect.bottom - rect.top);
2142                                OS.InvalidateRgn (handle, rgn, true);
2143                            }
2144                            OS.DeleteObject (rgn);
2145                        }
2146                    }
2147                }
2148            }
2149        }
2150        updateScrollBar ();
2151    }
2152}
2153
2154void createItemToolTips () {
2155    if (OS.IsWinCE) return;
2156    if (itemToolTipHandle != 0) return;
2157    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2158    bits |= OS.TVS_NOTOOLTIPS;
2159    OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2160    itemToolTipHandle = OS.CreateWindowEx (
2161        0,
2162        new TCHAR (0, OS.TOOLTIPS_CLASS, true),
2163        null,
2164        0,
2165        OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
2166        handle,
2167        0,
2168        OS.GetModuleHandle (null),
2169        null);
2170    if (itemToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
2171    /*
2172    * Feature in Windows. Despite the fact that the
2173    * tool tip text contains \r\n, the tooltip will
2174    * not honour the new line unless TTM_SETMAXTIPWIDTH
2175    * is set. The fix is to set TTM_SETMAXTIPWIDTH to
2176    * a large value.
2177    */

2178    OS.SendMessage (itemToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
2179    TOOLINFO lpti = new TOOLINFO ();
2180    lpti.cbSize = TOOLINFO.sizeof;
2181    lpti.hwnd = handle;
2182    lpti.uId = handle;
2183    lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
2184    lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2185    OS.SendMessage (itemToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2186}
2187
2188void createParent () {
2189    forceResize ();
2190    RECT rect = new RECT ();
2191    OS.GetWindowRect (handle, rect);
2192    OS.MapWindowPoints (0, parent.handle, rect, 2);
2193    int oldStyle = OS.GetWindowLong (handle, OS.GWL_STYLE);
2194    int newStyle = super.widgetStyle () & ~OS.WS_VISIBLE;
2195    if ((oldStyle & OS.WS_DISABLED) != 0) newStyle |= OS.WS_DISABLED;
2196// if ((oldStyle & OS.WS_VISIBLE) != 0) newStyle |= OS.WS_VISIBLE;
2197
hwndParent = OS.CreateWindowEx (
2198        super.widgetExtStyle (),
2199        super.windowClass (),
2200        null,
2201        newStyle,
2202        rect.left,
2203        rect.top,
2204        rect.right - rect.left,
2205        rect.bottom - rect.top,
2206        parent.handle,
2207        0,
2208        OS.GetModuleHandle (null),
2209        null);
2210    if (hwndParent == 0) error (SWT.ERROR_NO_HANDLES);
2211    OS.SetWindowLong (hwndParent, OS.GWL_ID, hwndParent);
2212    int bits = 0;
2213    if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
2214        bits |= OS.WS_EX_NOINHERITLAYOUT;
2215        if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
2216    }
2217    hwndHeader = OS.CreateWindowEx (
2218        bits,
2219        HeaderClass,
2220        null,
2221        OS.HDS_BUTTONS | OS.HDS_FULLDRAG | OS.HDS_DRAGDROP | OS.HDS_HIDDEN | OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
2222        0, 0, 0, 0,
2223        hwndParent,
2224        0,
2225        OS.GetModuleHandle (null),
2226        null);
2227    if (hwndHeader == 0) error (SWT.ERROR_NO_HANDLES);
2228    OS.SetWindowLong (hwndHeader, OS.GWL_ID, hwndHeader);
2229    if (OS.IsDBLocale) {
2230        int hIMC = OS.ImmGetContext (handle);
2231        OS.ImmAssociateContext (hwndParent, hIMC);
2232        OS.ImmAssociateContext (hwndHeader, hIMC);
2233        OS.ImmReleaseContext (handle, hIMC);
2234    }
2235    //This code is intentionally commented
2236
// if (!OS.IsPPC) {
2237
// if ((style & SWT.BORDER) != 0) {
2238
// int oldExStyle = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
2239
// oldExStyle &= ~OS.WS_EX_CLIENTEDGE;
2240
// OS.SetWindowLong (handle, OS.GWL_EXSTYLE, oldExStyle);
2241
// }
2242
// }
2243
int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
2244    if (hFont != 0) OS.SendMessage (hwndHeader, OS.WM_SETFONT, hFont, 0);
2245    int hwndInsertAfter = OS.GetWindow (handle, OS.GW_HWNDPREV);
2246    int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
2247    SetWindowPos (hwndParent, hwndInsertAfter, 0, 0, 0, 0, flags);
2248    SCROLLINFO info = new SCROLLINFO ();
2249    info.cbSize = SCROLLINFO.sizeof;
2250    info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
2251    OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
2252    info.nPage = info.nMax + 1;
2253    OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
2254    OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
2255    info.nPage = info.nMax + 1;
2256    OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
2257    customDraw = true;
2258    deregister ();
2259    if ((oldStyle & OS.WS_VISIBLE) != 0) {
2260        OS.ShowWindow (hwndParent, OS.SW_SHOW);
2261    }
2262    int hwndFocus = OS.GetFocus ();
2263    if (hwndFocus == handle) OS.SetFocus (hwndParent);
2264    OS.SetParent (handle, hwndParent);
2265    if (hwndFocus == handle) OS.SetFocus (handle);
2266    register ();
2267    subclass ();
2268    createItemToolTips ();
2269}
2270
2271void createWidget () {
2272    super.createWidget ();
2273    items = new TreeItem [4];
2274    columns = new TreeColumn [4];
2275    itemCount = -1;
2276}
2277
2278int defaultBackground () {
2279    return OS.GetSysColor (OS.COLOR_WINDOW);
2280}
2281
2282void deregister () {
2283    super.deregister ();
2284    if (hwndParent != 0) display.removeControl (hwndParent);
2285    if (hwndHeader != 0) display.removeControl (hwndHeader);
2286}
2287
2288void deselect (int hItem, TVITEM tvItem, int hIgnoreItem) {
2289    while (hItem != 0) {
2290        if (hItem != hIgnoreItem) {
2291            tvItem.hItem = hItem;
2292            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2293        }
2294        int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
2295        deselect (hFirstItem, tvItem, hIgnoreItem);
2296        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
2297    }
2298}
2299
2300/**
2301 * Deselects all selected items in the receiver.
2302 *
2303 * @exception SWTException <ul>
2304 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2305 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2306 * </ul>
2307 */

2308public void deselectAll () {
2309    checkWidget ();
2310    TVITEM tvItem = new TVITEM ();
2311    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
2312    tvItem.stateMask = OS.TVIS_SELECTED;
2313    if ((style & SWT.SINGLE) != 0) {
2314        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2315        if (hItem != 0) {
2316            tvItem.hItem = hItem;
2317            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2318        }
2319    } else {
2320        int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
2321        OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
2322        if ((style & SWT.VIRTUAL) != 0) {
2323            int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
2324            deselect (hItem, tvItem, 0);
2325        } else {
2326            for (int i=0; i<items.length; i++) {
2327                TreeItem item = items [i];
2328                if (item != null) {
2329                    tvItem.hItem = item.handle;
2330                    OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2331                }
2332            }
2333        }
2334        OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
2335    }
2336}
2337
2338void destroyItem (TreeColumn column) {
2339    if (hwndHeader == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
2340    int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
2341    int index = 0;
2342    while (index < columnCount) {
2343        if (columns [index] == column) break;
2344        index++;
2345    }
2346    int [] oldOrder = new int [columnCount];
2347    OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder);
2348    int orderIndex = 0;
2349    while (orderIndex < columnCount) {
2350        if (oldOrder [orderIndex] == index) break;
2351        orderIndex++;
2352    }
2353    RECT headerRect = new RECT ();
2354    OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
2355    if (OS.SendMessage (hwndHeader, OS.HDM_DELETEITEM, index, 0) == 0) {
2356        error (SWT.ERROR_ITEM_NOT_REMOVED);
2357    }
2358    System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
2359    columns [columnCount] = null;
2360    for (int i=0; i<items.length; i++) {
2361        TreeItem item = items [i];
2362        if (item != null) {
2363            if (columnCount == 0) {
2364                item.strings = null;
2365                item.images = null;
2366                item.cellBackground = null;
2367                item.cellForeground = null;
2368                item.cellFont = null;
2369            } else {
2370                if (item.strings != null) {
2371                    String JavaDoc [] strings = item.strings;
2372                    if (index == 0) {
2373                        item.text = strings [1] != null ? strings [1] : "";
2374                    }
2375                    String JavaDoc [] temp = new String JavaDoc [columnCount];
2376                    System.arraycopy (strings, 0, temp, 0, index);
2377                    System.arraycopy (strings, index + 1, temp, index, columnCount - index);
2378                    item.strings = temp;
2379                } else {
2380                    if (index == 0) item.text = "";
2381                }
2382                if (item.images != null) {
2383                    Image [] images = item.images;
2384                    if (index == 0) item.image = images [1];
2385                    Image [] temp = new Image [columnCount];
2386                    System.arraycopy (images, 0, temp, 0, index);
2387                    System.arraycopy (images, index + 1, temp, index, columnCount - index);
2388                    item.images = temp;
2389                } else {
2390                    if (index == 0) item.image = null;
2391                }
2392                if (item.cellBackground != null) {
2393                    int [] cellBackground = item.cellBackground;
2394                    int [] temp = new int [columnCount];
2395                    System.arraycopy (cellBackground, 0, temp, 0, index);
2396                    System.arraycopy (cellBackground, index + 1, temp, index, columnCount - index);
2397                    item.cellBackground = temp;
2398                }
2399                if (item.cellForeground != null) {
2400                    int [] cellForeground = item.cellForeground;
2401                    int [] temp = new int [columnCount];
2402                    System.arraycopy (cellForeground, 0, temp, 0, index);
2403                    System.arraycopy (cellForeground, index + 1, temp, index, columnCount - index);
2404                    item.cellForeground = temp;
2405                }
2406                if (item.cellFont != null) {
2407                    int [] cellFont = item.cellFont;
2408                    int [] temp = new int [columnCount];
2409                    System.arraycopy (cellFont, 0, temp, 0, index);
2410                    System.arraycopy (cellFont, index + 1, temp, index, columnCount - index);
2411                    item.cellFont = temp;
2412                }
2413            }
2414        }
2415    }
2416
2417    /*
2418    * When the last column is deleted, show the horizontal
2419    * scroll bar. Otherwise, left align the first column
2420    * and redraw the columns to the right.
2421    */

2422    if (columnCount == 0) {
2423        scrollWidth = 0;
2424        if (!hooks (SWT.MeasureItem)) {
2425            int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2426            bits &= ~OS.TVS_NOHSCROLL;
2427            OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2428            OS.InvalidateRect (handle, null, true);
2429        }
2430    } else {
2431        if (index == 0) {
2432            columns [0].style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
2433            columns [0].style |= SWT.LEFT;
2434            HDITEM hdItem = new HDITEM ();
2435            hdItem.mask = OS.HDI_FORMAT | OS.HDI_IMAGE;
2436            OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
2437            hdItem.fmt &= ~OS.HDF_JUSTIFYMASK;
2438            hdItem.fmt |= OS.HDF_LEFT;
2439            OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, hdItem);
2440        }
2441        RECT rect = new RECT ();
2442        OS.GetClientRect (handle, rect);
2443        rect.left = headerRect.left;
2444        OS.InvalidateRect (handle, rect, true);
2445    }
2446    setScrollWidth ();
2447    updateImageList ();
2448    updateScrollBar ();
2449    if (columnCount != 0) {
2450        int [] newOrder = new int [columnCount];
2451        OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, newOrder);
2452        TreeColumn [] newColumns = new TreeColumn [columnCount - orderIndex];
2453        for (int i=orderIndex; i<newOrder.length; i++) {
2454            newColumns [i - orderIndex] = columns [newOrder [i]];
2455            newColumns [i - orderIndex].updateToolTip (newOrder [i]);
2456        }
2457        for (int i=0; i<newColumns.length; i++) {
2458            if (!newColumns [i].isDisposed ()) {
2459                newColumns [i].sendEvent (SWT.Move);
2460            }
2461        }
2462    }
2463
2464    /* Remove the tool tip item for the header */
2465    if (headerToolTipHandle != 0) {
2466        TOOLINFO lpti = new TOOLINFO ();
2467        lpti.cbSize = TOOLINFO.sizeof;
2468        lpti.uId = column.id;
2469        lpti.hwnd = hwndHeader;
2470        OS.SendMessage (headerToolTipHandle, OS.TTM_DELTOOL, 0, lpti);
2471    }
2472}
2473
2474void destroyItem (TreeItem item, int hItem) {
2475    hFirstIndexOf = hLastIndexOf = 0;
2476    itemCount = -1;
2477    /*
2478    * Feature in Windows. When an item is removed that is not
2479    * visible in the tree because it belongs to a collapsed branch,
2480    * Windows redraws the tree causing a flash for each item that
2481    * is removed. The fix is to detect whether the item is visible,
2482    * force the widget to be fully painted, turn off redraw, remove
2483    * the item and validate the damage caused by the removing of
2484    * the item.
2485    *
2486    * NOTE: This fix is not necessary when double buffering and
2487    * can cause problems for virtual trees due to the call to
2488    * UpdateWindow() that flushes outstanding WM_PAINT events,
2489    * allowing application code to add or remove items during
2490    * this remove operation.
2491    */

2492    int hParent = 0;
2493    boolean fixRedraw = false;
2494    if ((style & SWT.DOUBLE_BUFFERED) == 0) {
2495        if (drawCount == 0 && OS.IsWindowVisible (handle)) {
2496            RECT rect = new RECT ();
2497            rect.left = hItem;
2498            fixRedraw = OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) == 0;
2499        }
2500    }
2501    if (fixRedraw) {
2502        hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
2503        OS.UpdateWindow (handle);
2504        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
2505        /*
2506        * This code is intentionally commented.
2507        */

2508// OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
2509
}
2510    if ((style & SWT.MULTI) != 0) {
2511        ignoreDeselect = ignoreSelect = lockSelection = true;
2512    }
2513
2514    /*
2515    * Feature in Windows. When an item is deleted and a tool tip
2516    * is showing, Window requests the new text for the new item
2517    * that is under the cursor right away. This means that when
2518    * multiple items are deleted, the tool tip flashes, showing
2519    * each new item in the tool tip as it is scrolled into view.
2520    * The fix is to hide tool tips when any item is deleted.
2521    *
2522    * NOTE: This only happens on Vista.
2523    */

2524    if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
2525        int hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
2526        if (hwndToolTip != 0) OS.SendMessage (hwndToolTip, OS.TTM_POP, 0 ,0);
2527    }
2528    
2529    shrink = ignoreShrink = true;
2530    OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
2531    ignoreShrink = false;
2532    if ((style & SWT.MULTI) != 0) {
2533        ignoreDeselect = ignoreSelect = lockSelection = false;
2534    }
2535    if (fixRedraw) {
2536        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
2537        OS.ValidateRect (handle, null);
2538        /*
2539        * If the item that was deleted was the last child of a tree item that
2540        * is visible, redraw the parent item to force the +/- to be updated.
2541        */

2542        if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent) == 0) {
2543            RECT rect = new RECT ();
2544            rect.left = hParent;
2545            if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect) != 0) {
2546                OS.InvalidateRect (handle, rect, true);
2547            }
2548        }
2549    }
2550    int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
2551    if (count == 0) {
2552        if (imageList != null) {
2553            OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
2554            display.releaseImageList (imageList);
2555        }
2556        imageList = null;
2557        if (hwndParent == 0 && !linesVisible) {
2558            if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
2559                customDraw = false;
2560            }
2561        }
2562        items = new TreeItem [4];
2563        scrollWidth = 0;
2564        setScrollWidth ();
2565    }
2566    updateScrollBar ();
2567}
2568
2569void enableDrag (boolean enabled) {
2570    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2571    if (enabled && hooks (SWT.DragDetect)) {
2572        bits &= ~OS.TVS_DISABLEDRAGDROP;
2573    } else {
2574        bits |= OS.TVS_DISABLEDRAGDROP;
2575    }
2576    OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2577}
2578
2579void enableWidget (boolean enabled) {
2580    super.enableWidget (enabled);
2581    /*
2582    * Feature in Windows. When a tree is given a background color
2583    * using TVM_SETBKCOLOR and the tree is disabled, Windows draws
2584    * the tree using the background color rather than the disabled
2585    * colors. This is different from the table which draws grayed.
2586    * The fix is to set the default background color while the tree
2587    * is disabled and restore it when enabled.
2588    */

2589    Control control = findBackgroundControl ();
2590    /*
2591    * Bug in Windows. On Vista only, Windows does not draw using
2592    * the background color when the tree is disabled. The fix is
2593    * to set the default color, even when the color has not been
2594    * changed, causing Windows to draw correctly.
2595    */

2596    if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
2597        if (control == null) control = this;
2598    }
2599    if (control != null) {
2600        if (control.backgroundImage == null) {
2601            _setBackgroundPixel (enabled ? control.getBackgroundPixel () : -1);
2602        }
2603    }
2604    if (hwndParent != 0) OS.EnableWindow (hwndParent, enabled);
2605
2606    /*
2607    * Feature in Windows. When the tree has the style
2608    * TVS_FULLROWSELECT, the background color for the
2609    * entire row is filled when an item is painted,
2610    * drawing on top of the sort column color. The fix
2611    * is to clear TVS_FULLROWSELECT when a their is
2612    * as sort column.
2613    */

2614    updateFullSelection ();
2615}
2616
2617int findIndex (int hFirstItem, int hItem) {
2618    if (hFirstItem == 0) return -1;
2619    if (hFirstItem == hFirstIndexOf) {
2620        if (hFirstIndexOf == hItem) {
2621            hLastIndexOf = hFirstIndexOf;
2622            return lastIndexOf = 0;
2623        }
2624        if (hLastIndexOf == hItem) return lastIndexOf;
2625        int hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2626        if (hPrevItem == hItem) {
2627            hLastIndexOf = hPrevItem;
2628            return --lastIndexOf;
2629        }
2630        int hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2631        if (hNextItem == hItem) {
2632            hLastIndexOf = hNextItem;
2633            return ++lastIndexOf;
2634        }
2635        int previousIndex = lastIndexOf - 1;
2636        while (hPrevItem != 0 && hPrevItem != hItem) {
2637            hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2638            --previousIndex;
2639        }
2640        if (hPrevItem == hItem) {
2641            hLastIndexOf = hPrevItem;
2642            return lastIndexOf = previousIndex;
2643        }
2644        int nextIndex = lastIndexOf + 1;
2645        while (hNextItem != 0 && hNextItem != hItem) {
2646            hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2647            nextIndex++;
2648        }
2649        if (hNextItem == hItem) {
2650            hLastIndexOf = hNextItem;
2651            return lastIndexOf = nextIndex;
2652        }
2653        return -1;
2654    }
2655    int index = 0, hNextItem = hFirstItem;
2656    while (hNextItem != 0 && hNextItem != hItem) {
2657        hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2658        index++;
2659    }
2660    if (hNextItem == hItem) {
2661        itemCount = -1;
2662        hFirstIndexOf = hFirstItem;
2663        hLastIndexOf = hNextItem;
2664        return lastIndexOf = index;
2665    }
2666    return -1;
2667}
2668
2669Widget findItem (int hItem) {
2670    return _getItem (hItem);
2671}
2672
2673int findItem (int hFirstItem, int index) {
2674    if (hFirstItem == 0) return 0;
2675    if (hFirstItem == hFirstIndexOf) {
2676        if (index == 0) {
2677            lastIndexOf = 0;
2678            return hLastIndexOf = hFirstIndexOf;
2679        }
2680        if (lastIndexOf == index) return hLastIndexOf;
2681        if (lastIndexOf - 1 == index) {
2682            --lastIndexOf;
2683            return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2684        }
2685        if (lastIndexOf + 1 == index) {
2686            lastIndexOf++;
2687            return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2688        }
2689        if (index < lastIndexOf) {
2690            int previousIndex = lastIndexOf - 1;
2691            int hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2692            while (hPrevItem != 0 && index < previousIndex) {
2693                hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2694                --previousIndex;
2695            }
2696            if (index == previousIndex) {
2697                lastIndexOf = previousIndex;
2698                return hLastIndexOf = hPrevItem;
2699            }
2700        } else {
2701            int nextIndex = lastIndexOf + 1;
2702            int hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2703            while (hNextItem != 0 && nextIndex < index) {
2704                hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2705                nextIndex++;
2706            }
2707            if (index == nextIndex) {
2708                lastIndexOf = nextIndex;
2709                return hLastIndexOf = hNextItem;
2710            }
2711        }
2712        return 0;
2713    }
2714    int nextIndex = 0, hNextItem = hFirstItem;
2715    while (hNextItem != 0 && nextIndex < index) {
2716        hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2717        nextIndex++;
2718    }
2719    if (index == nextIndex) {
2720        itemCount = -1;
2721        lastIndexOf = nextIndex;
2722        hFirstIndexOf = hFirstItem;
2723        return hLastIndexOf = hNextItem;
2724    }
2725    return 0;
2726}
2727
2728TreeItem getFocusItem () {
2729// checkWidget ();
2730
int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2731    return hItem != 0 ? _getItem (hItem) : null;
2732}
2733
2734/**
2735 * Returns the width in pixels of a grid line.
2736 *
2737 * @return the width of a grid line in pixels
2738 *
2739 * @exception SWTException <ul>
2740 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2741 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2742 * </ul>
2743 *
2744 * @since 3.1
2745 */

2746public int getGridLineWidth () {
2747    checkWidget ();
2748    return GRID_WIDTH;
2749}
2750
2751/**
2752 * Returns the height of the receiver's header
2753 *
2754 * @return the height of the header or zero if the header is not visible
2755 *
2756 * @exception SWTException <ul>
2757 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2758 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2759 * </ul>
2760 *
2761 * @since 3.1
2762 */

2763public int getHeaderHeight () {
2764    checkWidget ();
2765    if (hwndHeader == 0) return 0;
2766    RECT rect = new RECT ();
2767    OS.GetWindowRect (hwndHeader, rect);
2768    return rect.bottom - rect.top;
2769}
2770
2771/**
2772 * Returns <code>true</code> if the receiver's header is visible,
2773 * and <code>false</code> otherwise.
2774 * <p>
2775 * If one of the receiver's ancestors is not visible or some
2776 * other condition makes the receiver not visible, this method
2777 * may still indicate that it is considered visible even though
2778 * it may not actually be showing.
2779 * </p>
2780 *
2781 * @return the receiver's header's visibility state
2782 *
2783 * @exception SWTException <ul>
2784 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2785 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2786 * </ul>
2787 *
2788 * @since 3.1
2789 */

2790public boolean getHeaderVisible () {
2791    checkWidget ();
2792    if (hwndHeader == 0) return false;
2793    int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
2794    return (bits & OS.WS_VISIBLE) != 0;
2795}
2796
2797Point getImageSize () {
2798    if (imageList != null) return imageList.getImageSize ();
2799    return new Point (0, getItemHeight ());
2800}
2801
2802int getBottomItem () {
2803    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
2804    if (hItem == 0) return 0;
2805    int index = 0, count = OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
2806    while (index < count) {
2807        int hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
2808        if (hNextItem == 0) return hItem;
2809        hItem = hNextItem;
2810        index++;
2811    }
2812    return hItem;
2813}
2814
2815/**
2816 * Returns the column at the given, zero-relative index in the
2817 * receiver. Throws an exception if the index is out of range.
2818 * Columns are returned in the order that they were created.
2819 * If no <code>TreeColumn</code>s were created by the programmer,
2820 * this method will throw <code>ERROR_INVALID_RANGE</code> despite
2821 * the fact that a single column of data may be visible in the tree.
2822 * This occurs when the programmer uses the tree like a list, adding
2823 * items but never creating a column.
2824 *
2825 * @param index the index of the column to return
2826 * @return the column at the given index
2827 *
2828 * @exception IllegalArgumentException <ul>
2829 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
2830 * </ul>
2831 * @exception SWTException <ul>
2832 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2833 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2834 * </ul>
2835 *
2836 * @see Tree#getColumnOrder()
2837 * @see Tree#setColumnOrder(int[])
2838 * @see TreeColumn#getMoveable()
2839 * @see TreeColumn#setMoveable(boolean)
2840 * @see SWT#Move
2841 *
2842 * @since 3.1
2843 */

2844public TreeColumn getColumn (int index) {
2845    checkWidget ();
2846    if (hwndHeader == 0) error (SWT.ERROR_INVALID_RANGE);
2847    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
2848    if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
2849    return columns [index];
2850}
2851
2852/**
2853 * Returns the number of columns contained in the receiver.
2854 * If no <code>TreeColumn</code>s were created by the programmer,
2855 * this value is zero, despite the fact that visually, one column
2856 * of items may be visible. This occurs when the programmer uses
2857 * the tree like a list, adding items but never creating a column.
2858 *
2859 * @return the number of columns
2860 *
2861 * @exception SWTException <ul>
2862 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2863 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2864 * </ul>
2865 *
2866 * @since 3.1
2867 */

2868public int getColumnCount () {
2869    checkWidget ();
2870    if (hwndHeader == 0) return 0;
2871    return OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
2872}
2873
2874/**
2875 * Returns an array of zero-relative integers that map
2876 * the creation order of the receiver's items to the
2877 * order in which they are currently being displayed.
2878 * <p>
2879 * Specifically, the indices of the returned array represent
2880 * the current visual order of the items, and the contents
2881 * of the array represent the creation order of the items.
2882 * </p><p>
2883 * Note: This is not the actual structure used by the receiver
2884 * to maintain its list of items, so modifying the array will
2885 * not affect the receiver.
2886 * </p>
2887 *
2888 * @return the current visual order of the receiver's items
2889 *
2890 * @exception SWTException <ul>
2891 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2892 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2893 * </ul>
2894 *
2895 * @see Tree#setColumnOrder(int[])
2896 * @see TreeColumn#getMoveable()
2897 * @see TreeColumn#setMoveable(boolean)
2898 * @see SWT#Move
2899 *
2900 * @since 3.2
2901 */

2902public int[] getColumnOrder () {
2903    checkWidget ();
2904    if (hwndHeader == 0) return new int [0];
2905    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
2906    int [] order = new int [count];
2907    OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
2908    return order;
2909}
2910
2911/**
2912 * Returns an array of <code>TreeColumn</code>s which are the
2913 * columns in the receiver. Columns are returned in the order
2914 * that they were created. If no <code>TreeColumn</code>s were
2915 * created by the programmer, the array is empty, despite the fact
2916 * that visually, one column of items may be visible. This occurs
2917 * when the programmer uses the tree like a list, adding items but
2918 * never creating a column.
2919 * <p>
2920 * Note: This is not the actual structure used by the receiver
2921 * to maintain its list of items, so modifying the array will
2922 * not affect the receiver.
2923 * </p>
2924 *
2925 * @return the items in the receiver
2926 *
2927 * @exception SWTException <ul>
2928 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2929 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2930 * </ul>
2931 *
2932 * @see Tree#getColumnOrder()
2933 * @see Tree#setColumnOrder(int[])
2934 * @see TreeColumn#getMoveable()
2935 * @see TreeColumn#setMoveable(boolean)
2936 * @see SWT#Move
2937 *
2938 * @since 3.1
2939 */

2940public TreeColumn [] getColumns () {
2941    checkWidget ();
2942    if (hwndHeader == 0) return new TreeColumn [0];
2943    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
2944    TreeColumn [] result = new TreeColumn [count];
2945    System.arraycopy (columns, 0, result, 0, count);
2946    return result;
2947}
2948
2949/**
2950 * Returns the item at the given, zero-relative index in the
2951 * receiver. Throws an exception if the index is out of range.
2952 *
2953 * @param index the index of the item to return
2954 * @return the item at the given index
2955 *
2956 * @exception IllegalArgumentException <ul>
2957 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
2958 * </ul>
2959 * @exception SWTException <ul>
2960 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2961 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2962 * </ul>
2963 *
2964 * @since 3.1
2965 */

2966public TreeItem getItem (int index) {
2967    checkWidget ();
2968    if (index < 0) error (SWT.ERROR_INVALID_RANGE);
2969    int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
2970    if (hFirstItem == 0) error (SWT.ERROR_INVALID_RANGE);
2971    int hItem = findItem (hFirstItem, index);
2972    if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
2973    return _getItem (hItem);
2974}
2975
2976TreeItem getItem (NMTVCUSTOMDRAW nmcd) {
2977    /*
2978    * Bug in Windows. If the lParam field of TVITEM
2979    * is changed during custom draw using TVM_SETITEM,
2980    * the lItemlParam field of the NMTVCUSTOMDRAW struct
2981    * is not updated until the next custom draw. The
2982    * fix is to query the field from the item instead
2983    * of using the struct.
2984    */

2985    int id = nmcd.lItemlParam;
2986    if ((style & SWT.VIRTUAL) != 0) {
2987        if (id == -1) {
2988            TVITEM tvItem = new TVITEM ();
2989            tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
2990            tvItem.hItem = nmcd.dwItemSpec;
2991            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
2992            id = tvItem.lParam;
2993        }
2994    }
2995    return _getItem (nmcd.dwItemSpec, id);
2996}
2997
2998/**
2999 * Returns the item at the given point in the receiver
3000 * or null if no such item exists. The point is in the
3001 * coordinate system of the receiver.
3002 * <p>
3003 * The item that is returned represents an item that could be selected by the user.
3004 * For example, if selection only occurs in items in the first column, then null is
3005 * returned if the point is outside of the item.
3006 * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
3007 * determines the extent of the selection.
3008 * </p>
3009 *
3010 * @param point the point used to locate the item
3011 * @return the item at the given point, or null if the point is not in a selectable item
3012 *
3013 * @exception IllegalArgumentException <ul>
3014 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
3015 * </ul>
3016 * @exception SWTException <ul>
3017 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3018 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3019 * </ul>
3020 */

3021public TreeItem getItem (Point point) {
3022    checkWidget ();
3023    if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
3024    TVHITTESTINFO lpht = new TVHITTESTINFO ();
3025    lpht.x = point.x;
3026    lpht.y = point.y;
3027    OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
3028    if (lpht.hItem != 0) {
3029        if ((style & SWT.FULL_SELECTION) != 0 || (lpht.flags & OS.TVHT_ONITEM) != 0) {
3030            return _getItem (lpht.hItem);
3031        }
3032    }
3033    return null;
3034}
3035
3036/**
3037 * Returns the number of items contained in the receiver
3038 * that are direct item children of the receiver. The
3039 * number that is returned is the number of roots in the
3040 * tree.
3041 *
3042 * @return the number of items
3043 *
3044 * @exception SWTException <ul>
3045 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3046 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3047 * </ul>
3048 */

3049public int getItemCount () {
3050    checkWidget ();
3051    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3052    if (hItem == 0) return 0;
3053    return getItemCount (hItem);
3054}
3055
3056int getItemCount (int hItem) {
3057    int count = 0, hFirstItem = hItem;
3058    if (hItem == hFirstIndexOf) {
3059        if (itemCount != -1) return itemCount;
3060        hFirstItem = hLastIndexOf;
3061        count = lastIndexOf;
3062    }
3063    while (hFirstItem != 0) {
3064        hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hFirstItem);
3065        count++;
3066    }
3067    if (hItem == hFirstIndexOf) itemCount = count;
3068    return count;
3069}
3070
3071/**
3072 * Returns the height of the area which would be used to
3073 * display <em>one</em> of the items in the tree.
3074 *
3075 * @return the height of one item
3076 *
3077 * @exception SWTException <ul>
3078 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3079 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3080 * </ul>
3081 */

3082public int getItemHeight () {
3083    checkWidget ();
3084    return OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
3085}
3086
3087/**
3088 * Returns a (possibly empty) array of items contained in the
3089 * receiver that are direct item children of the receiver. These
3090 * are the roots of the tree.
3091 * <p>
3092 * Note: This is not the actual structure used by the receiver
3093 * to maintain its list of items, so modifying the array will
3094 * not affect the receiver.
3095 * </p>
3096 *
3097 * @return the items
3098 *
3099 * @exception SWTException <ul>
3100 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3101 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3102 * </ul>
3103 */

3104public TreeItem [] getItems () {
3105    checkWidget ();
3106    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3107    if (hItem == 0) return new TreeItem [0];
3108    return getItems (hItem);
3109}
3110
3111TreeItem [] getItems (int hTreeItem) {
3112    int count = 0, hItem = hTreeItem;
3113    while (hItem != 0) {
3114        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3115        count++;
3116    }
3117    int index = 0;
3118    TreeItem [] result = new TreeItem [count];
3119    TVITEM tvItem = new TVITEM ();
3120    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3121    tvItem.hItem = hTreeItem;
3122    /*
3123    * Feature in Windows. In some cases an expand or collapse message
3124    * can occur from within TVM_DELETEITEM. When this happens, the item
3125    * being destroyed has been removed from the list of items but has not
3126    * been deleted from the tree. The fix is to check for null items and
3127    * remove them from the list.
3128    */

3129    while (tvItem.hItem != 0) {
3130        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3131        TreeItem item = _getItem (tvItem.hItem, tvItem.lParam);
3132        if (item != null) result [index++] = item;
3133        tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem);
3134    }
3135    if (index != count) {
3136        TreeItem [] newResult = new TreeItem [index];
3137        System.arraycopy (result, 0, newResult, 0, index);
3138        result = newResult;
3139    }
3140    return result;
3141}
3142
3143/**
3144 * Returns <code>true</code> if the receiver's lines are visible,
3145 * and <code>false</code> otherwise.
3146 * <p>
3147 * If one of the receiver's ancestors is not visible or some
3148 * other condition makes the receiver not visible, this method
3149 * may still indicate that it is considered visible even though
3150 * it may not actually be showing.
3151 * </p>
3152 *
3153 * @return the visibility state of the lines
3154 *
3155 * @exception SWTException <ul>
3156 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3157 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3158 * </ul>
3159 *
3160 * @since 3.1
3161 */

3162public boolean getLinesVisible () {
3163    checkWidget ();
3164    return linesVisible;
3165}
3166
3167int getNextSelection (int hItem, TVITEM tvItem) {
3168    while (hItem != 0) {
3169        int state = 0;
3170        if (OS.IsWinCE) {
3171            tvItem.hItem = hItem;
3172            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3173            state = tvItem.state;
3174        } else {
3175            state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3176        }
3177        if ((state & OS.TVIS_SELECTED) != 0) return hItem;
3178        int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3179        int hSelected = getNextSelection (hFirstItem, tvItem);
3180        if (hSelected != 0) return hSelected;
3181        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3182    }
3183    return 0;
3184}
3185
3186/**
3187 * Returns the receiver's parent item, which must be a
3188 * <code>TreeItem</code> or null when the receiver is a
3189 * root.
3190 *
3191 * @return the receiver's parent item
3192 *
3193 * @exception SWTException <ul>
3194 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3195 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3196 * </ul>
3197 */

3198public TreeItem getParentItem () {
3199    checkWidget ();
3200    return null;
3201}
3202
3203int getSelection (int hItem, TVITEM tvItem, TreeItem [] selection, int index, int count, boolean bigSelection, boolean all) {
3204    while (hItem != 0) {
3205        if (OS.IsWinCE || bigSelection) {
3206            tvItem.hItem = hItem;
3207            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3208            if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
3209                if (selection != null && index < selection.length) {
3210                    selection [index] = _getItem (hItem, tvItem.lParam);
3211                }
3212                index++;
3213            }
3214        } else {
3215            int state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3216            if ((state & OS.TVIS_SELECTED) != 0) {
3217                if (tvItem != null && selection != null && index < selection.length) {
3218                    tvItem.hItem = hItem;
3219                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3220                    selection [index] = _getItem (hItem, tvItem.lParam);
3221                }
3222                index++;
3223            }
3224        }
3225        if (index == count) break;
3226        if (all) {
3227            int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3228            if ((index = getSelection (hFirstItem, tvItem, selection, index, count, bigSelection, all)) == count) {
3229                break;
3230            }
3231            hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3232        } else {
3233            hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3234        }
3235    }
3236    return index;
3237}
3238
3239/**
3240 * Returns an array of <code>TreeItem</code>s that are currently
3241 * selected in the receiver. The order of the items is unspecified.
3242 * An empty array indicates that no items are selected.
3243 * <p>
3244 * Note: This is not the actual structure used by the receiver
3245 * to maintain its selection, so modifying the array will
3246 * not affect the receiver.
3247 * </p>
3248 * @return an array representing the selection
3249 *
3250 * @exception SWTException <ul>
3251 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3252 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3253 * </ul>
3254 */

3255public TreeItem [] getSelection () {
3256    checkWidget ();
3257    if ((style & SWT.SINGLE) != 0) {
3258        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3259        if (hItem == 0) return new TreeItem [0];
3260        TVITEM tvItem = new TVITEM ();
3261        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3262        tvItem.hItem = hItem;
3263        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3264        if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0];
3265        return new TreeItem [] {_getItem (tvItem.hItem, tvItem.lParam)};
3266    }
3267    int count = 0;
3268    TreeItem [] guess = new TreeItem [(style & SWT.VIRTUAL) != 0 ? 8 : 1];
3269    int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
3270    OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
3271    if ((style & SWT.VIRTUAL) != 0) {
3272        TVITEM tvItem = new TVITEM ();
3273        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3274        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3275        count = getSelection (hItem, tvItem, guess, 0, -1, false, true);
3276    } else {
3277        TVITEM tvItem = null;
3278        if (OS.IsWinCE) {
3279            tvItem = new TVITEM ();
3280            tvItem.mask = OS.TVIF_STATE;
3281        }
3282        for (int i=0; i<items.length; i++) {
3283            TreeItem item = items [i];
3284            if (item != null) {
3285                int hItem = item.handle, state = 0;
3286                if (OS.IsWinCE) {
3287                    tvItem.hItem = hItem;
3288                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3289                    state = tvItem.state;
3290                } else {
3291                    state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3292                }
3293                if ((state & OS.TVIS_SELECTED) != 0) {
3294                    if (count < guess.length) guess [count] = item;
3295                    count++;
3296                }
3297            }
3298        }
3299    }
3300    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
3301    if (count == 0) return new TreeItem [0];
3302    if (count == guess.length) return guess;
3303    TreeItem [] result = new TreeItem [count];
3304    if (count < guess.length) {
3305        System.arraycopy (guess, 0, result, 0, count);
3306        return result;
3307    }
3308    OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
3309    TVITEM tvItem = new TVITEM ();
3310    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3311    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3312    int itemCount = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
3313    boolean bigSelection = result.length > itemCount / 2;
3314    if (count != getSelection (hItem, tvItem, result, 0, count, bigSelection, false)) {
3315        getSelection (hItem, tvItem, result, 0, count, bigSelection, true);
3316    }
3317    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
3318    return result;
3319}
3320
3321/**
3322 * Returns the number of selected items contained in the receiver.
3323 *
3324 * @return the number of selected items
3325 *
3326 * @exception SWTException <ul>
3327 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3328 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3329 * </ul>
3330 */

3331public int getSelectionCount () {
3332    checkWidget ();
3333    if ((style & SWT.SINGLE) != 0) {
3334        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3335        if (hItem == 0) return 0;
3336        int state = 0;
3337        if (OS.IsWinCE) {
3338            TVITEM tvItem = new TVITEM ();
3339            tvItem.hItem = hItem;
3340            tvItem.mask = OS.TVIF_STATE;
3341            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3342            state = tvItem.state;
3343        } else {
3344            state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3345        }
3346        return (state & OS.TVIS_SELECTED) == 0 ? 0 : 1;
3347    }
3348    int count = 0;
3349    int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
3350    TVITEM tvItem = null;
3351    if (OS.IsWinCE) {
3352        tvItem = new TVITEM ();
3353        tvItem.mask = OS.TVIF_STATE;
3354    }
3355    OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
3356    if ((style & SWT.VIRTUAL) != 0) {
3357        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3358        count = getSelection (hItem, tvItem, null, 0, -1, false, true);
3359    } else {
3360        for (int i=0; i<items.length; i++) {
3361            TreeItem item = items [i];
3362            if (item != null) {
3363                int hItem = item.handle, state = 0;
3364                if (OS.IsWinCE) {
3365                    tvItem.hItem = hItem;
3366                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3367                    state = tvItem.state;
3368                } else {
3369                    state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3370                }
3371                if ((state & OS.TVIS_SELECTED) != 0) count++;
3372            }
3373        }
3374    }
3375    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
3376    return count;
3377}
3378
3379/**
3380 * Returns the column which shows the sort indicator for
3381 * the receiver. The value may be null if no column shows
3382 * the sort indicator.
3383 *
3384 * @return the sort indicator
3385 *
3386 * @exception SWTException <ul>
3387 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3388 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3389 * </ul>
3390 *
3391 * @see #setSortColumn(TreeColumn)
3392 *
3393 * @since 3.2
3394 */

3395public TreeColumn getSortColumn () {
3396    checkWidget ();
3397    return sortColumn;
3398}
3399
3400int getSortColumnPixel () {
3401    int pixel = OS.IsWindowEnabled (handle) ? getBackgroundPixel () : OS.GetSysColor (OS.COLOR_3DFACE);
3402    int red = pixel & 0xFF;
3403    int green = (pixel & 0xFF00) >> 8;
3404    int blue = (pixel & 0xFF0000) >> 16;
3405    if (red > 240 && green > 240 && blue > 240) {
3406        red -= 8;
3407        green -= 8;
3408        blue -= 8;
3409    } else {
3410        red = Math.min (0xFF, (red / 10) + red);
3411        green = Math.min (0xFF, (green / 10) + green);
3412        blue = Math.min (0xFF, (blue / 10) + blue);
3413    }
3414    return (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
3415}
3416
3417/**
3418 * Returns the direction of the sort indicator for the receiver.
3419 * The value will be one of <code>UP</code>, <code>DOWN</code>
3420 * or <code>NONE</code>.
3421 *
3422 * @return the sort direction
3423 *
3424 * @exception SWTException <ul>
3425 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3426 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3427 * </ul>
3428 *
3429 * @see #setSortDirection(int)
3430 *
3431 * @since 3.2
3432 */

3433public int getSortDirection () {
3434    checkWidget ();
3435    return sortDirection;
3436}
3437
3438/**
3439 * Returns the item which is currently at the top of the receiver.
3440 * This item can change when items are expanded, collapsed, scrolled
3441 * or new items are added or removed.
3442 *
3443 * @return the item at the top of the receiver
3444 *
3445 * @exception SWTException <ul>
3446 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3447 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3448 * </ul>
3449 *
3450 * @since 2.1
3451 */

3452public TreeItem getTopItem () {
3453    checkWidget ();
3454    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3455    return hItem != 0 ? _getItem (hItem) : null;
3456}
3457
3458int imageIndex (Image image, int index) {
3459    if (image == null) return OS.I_IMAGENONE;
3460    if (imageList == null) {
3461        Rectangle bounds = image.getBounds ();
3462        imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3463    }
3464    int imageIndex = imageList.indexOf (image);
3465    if (imageIndex == -1) imageIndex = imageList.add (image);
3466    if (hwndHeader == 0 || OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) == index) {
3467        int hImageList = imageList.getHandle ();
3468        int hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
3469        if (hOldImageList != hImageList) {
3470            OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
3471            updateScrollBar ();
3472        }
3473    }
3474    return imageIndex;
3475}
3476
3477int imageIndexHeader (Image image) {
3478    if (image == null) return OS.I_IMAGENONE;
3479    if (headerImageList == null) {
3480        Rectangle bounds = image.getBounds ();
3481        headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3482        int index = headerImageList.indexOf (image);
3483        if (index == -1) index = headerImageList.add (image);
3484        int hImageList = headerImageList.getHandle ();
3485        if (hwndHeader != 0) {
3486            OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageList);
3487        }
3488        updateScrollBar ();
3489        return index;
3490    }
3491    int index = headerImageList.indexOf (image);
3492    if (index != -1) return index;
3493    return headerImageList.add (image);
3494}
3495
3496/**
3497 * Searches the receiver's list starting at the first column
3498 * (index 0) until a column is found that is equal to the
3499 * argument, and returns the index of that column. If no column
3500 * is found, returns -1.
3501 *
3502 * @param column the search column
3503 * @return the index of the column
3504 *
3505 * @exception IllegalArgumentException <ul>
3506 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
3507 * </ul>
3508 * @exception SWTException <ul>
3509 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3510 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3511 * </ul>
3512 *
3513 * @since 3.1
3514 */

3515public int indexOf (TreeColumn column) {
3516    checkWidget ();
3517    if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
3518    if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3519    if (hwndHeader == 0) return -1;
3520    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
3521    for (int i=0; i<count; i++) {
3522        if (columns [i] == column) return i;
3523    }
3524    return -1;
3525}
3526
3527/**
3528 * Searches the receiver's list starting at the first item
3529 * (index 0) until an item is found that is equal to the
3530 * argument, and returns the index of that item. If no item
3531 * is found, returns -1.
3532 *
3533 * @param item the search item
3534 * @return the index of the item
3535 *
3536 * @exception IllegalArgumentException <ul>
3537 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
3538 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
3539 * </ul>
3540 * @exception SWTException <ul>
3541 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3542 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3543 * </ul>
3544 *
3545 * @since 3.1
3546 */

3547public int indexOf (TreeItem item) {
3548    checkWidget ();
3549    if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
3550    if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3551    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3552    return hItem == 0 ? -1 : findIndex (hItem, item.handle);
3553}
3554
3555boolean isItemSelected (NMTVCUSTOMDRAW nmcd) {
3556    boolean selected = false;
3557    if (OS.IsWindowEnabled (handle)) {
3558        TVITEM tvItem = new TVITEM ();
3559        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
3560        tvItem.hItem = nmcd.dwItemSpec;
3561        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3562        if ((tvItem.state & (OS.TVIS_SELECTED | OS.TVIS_DROPHILITED)) != 0) {
3563            selected = true;
3564            /*
3565            * Feature in Windows. When the mouse is pressed and the
3566            * selection is first drawn for a tree, the previously
3567            * selected item is redrawn but the the TVIS_SELECTED bits
3568            * are not cleared. When the user moves the mouse slightly
3569            * and a drag and drop operation is not started, the item is
3570            * drawn again and this time with TVIS_SELECTED is cleared.
3571            * This means that an item that contains colored cells will
3572            * not draw with the correct background until the mouse is
3573            * moved. The fix is to test for the selection colors and
3574            * guess that the item is not selected.
3575            *
3576            * NOTE: This code does not work when the foreground and
3577            * background of the tree are set to the selection colors
3578            * but this does not happen in a regular application.
3579            */

3580            if (handle == OS.GetFocus ()) {
3581                if (OS.GetTextColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3582                    selected = false;
3583                } else {
3584                    if (OS.GetBkColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3585                        selected = false;
3586                    }
3587                }
3588            }
3589        } else {
3590            if (nmcd.dwDrawStage == OS.CDDS_ITEMPOSTPAINT) {
3591                /*
3592                * Feature in Windows. When the mouse is pressed and the
3593                * selection is first drawn for a tree, the item is drawn
3594                * selected, but the TVIS_SELECTED bits for the item are
3595                * not set. When the user moves the mouse slightly and
3596                * a drag and drop operation is not started, the item is
3597                * drawn again and this time TVIS_SELECTED is set. This
3598                * means that an item that is in a tree that has the style
3599                * TVS_FULLROWSELECT and that also contains colored cells
3600                * will not draw the entire row selected until the user
3601                * moves the mouse. The fix is to test for the selection
3602                * colors and guess that the item is selected.
3603                *
3604                * NOTE: This code does not work when the foreground and
3605                * background of the tree are set to the selection colors
3606                * but this does not happen in a regular application.
3607                */

3608                if (OS.GetTextColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3609                    if (OS.GetBkColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3610                        selected = true;
3611                    }
3612                }
3613            }
3614        }
3615    }
3616    return selected;
3617}
3618
3619void redrawSelection () {
3620    if ((style & SWT.SINGLE) != 0) {
3621        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3622        if (hItem != 0) {
3623            RECT rect = new RECT ();
3624            rect.left = hItem;
3625            OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect);
3626            OS.InvalidateRect (handle, rect, true);
3627        }
3628    } else {
3629        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3630        if (hItem != 0) {
3631            TVITEM tvItem = null;
3632            if (OS.IsWinCE) {
3633                tvItem = new TVITEM ();
3634                tvItem.mask = OS.TVIF_STATE;
3635            }
3636            RECT rect = new RECT ();
3637            int index = 0, count = OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
3638            while (index < count && hItem != 0) {
3639                int state = 0;
3640                if (OS.IsWinCE) {
3641                    tvItem.hItem = hItem;
3642                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3643                    state = tvItem.state;
3644                } else {
3645                    state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3646                }
3647                if ((state & OS.TVIS_SELECTED) != 0) {
3648                    rect.left = hItem;
3649                    OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect);
3650                    OS.InvalidateRect (handle, rect, true);
3651                }
3652                hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3653                index++;
3654            }
3655        }
3656    }
3657}
3658
3659void register () {
3660    super.register ();
3661    if (hwndParent != 0) display.addControl (hwndParent, this);
3662    if (hwndHeader != 0) display.addControl (hwndHeader, this);
3663}
3664
3665void releaseItem (int hItem, TVITEM tvItem, boolean release) {
3666    if (hItem == hAnchor) hAnchor = 0;
3667    if (hItem == hInsert) hInsert = 0;
3668    tvItem.hItem = hItem;
3669    if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
3670        if (tvItem.lParam != -1) {
3671            if (tvItem.lParam < lastID) lastID = tvItem.lParam;
3672            if (release) {
3673                TreeItem item = items [tvItem.lParam];
3674                if (item != null) item.release (false);
3675            }
3676            items [tvItem.lParam] = null;
3677        }
3678    }
3679}
3680
3681void releaseItems (int hItem, TVITEM tvItem) {
3682    hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3683    while (hItem != 0) {
3684        releaseItems (hItem, tvItem);
3685        releaseItem (hItem, tvItem, true);
3686        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3687    }
3688}
3689
3690void releaseHandle () {
3691    super.releaseHandle ();
3692    hwndParent = hwndHeader = 0;
3693}
3694
3695void releaseChildren (boolean destroy) {
3696    if (items != null) {
3697        for (int i=0; i<items.length; i++) {
3698            TreeItem item = items [i];
3699            if (item != null && !item.isDisposed ()) {
3700                item.release (false);
3701            }
3702        }
3703        items = null;
3704    }
3705    if (columns != null) {
3706        for (int i=0; i<columns.length; i++) {
3707            TreeColumn column = columns [i];
3708            if (column != null && !column.isDisposed ()) {
3709                column.release (false);
3710            }
3711        }
3712        columns = null;
3713    }
3714    super.releaseChildren (destroy);
3715}
3716
3717void releaseWidget () {
3718    super.releaseWidget ();
3719    /*
3720    * Feature in Windows. For some reason, when TVM_GETIMAGELIST
3721    * or TVM_SETIMAGELIST is sent, the tree issues NM_CUSTOMDRAW
3722    * messages. This behavior is unwanted when the tree is being
3723    * disposed. The fix is to ignore NM_CUSTOMDRAW messages by
3724    * clearing the custom draw flag.
3725    *
3726    * NOTE: This only happens on Windows XP.
3727    */

3728    customDraw = false;
3729    if (imageList != null) {
3730        OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0);
3731        display.releaseImageList (imageList);
3732    }
3733    if (headerImageList != null) {
3734        if (hwndHeader != 0) {
3735            OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, 0);
3736        }
3737        display.releaseImageList (headerImageList);
3738    }
3739    imageList = headerImageList = null;
3740    int hStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
3741    OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, 0);
3742    if (hStateList != 0) OS.ImageList_Destroy (hStateList);
3743    if (itemToolTipHandle != 0) OS.DestroyWindow (itemToolTipHandle);
3744    if (headerToolTipHandle != 0) OS.DestroyWindow (headerToolTipHandle);
3745    itemToolTipHandle = headerToolTipHandle = 0;
3746    if (display.isXMouseActive ()) {
3747        Shell shell = getShell ();
3748        if (shell.lockToolTipControl == this) {
3749            shell.lockToolTipControl = null;
3750        }
3751    }
3752}
3753
3754/**
3755 * Removes all of the items from the receiver.
3756 *
3757 * @exception SWTException <ul>
3758 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3759 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3760 * </ul>
3761 */

3762public void removeAll () {
3763    checkWidget ();
3764    hFirstIndexOf = hLastIndexOf = 0;
3765    itemCount = -1;
3766    for (int i=0; i<items.length; i++) {
3767        TreeItem item = items [i];
3768        if (item != null && !item.isDisposed ()) {
3769            item.release (false);
3770        }
3771    }
3772    ignoreDeselect = ignoreSelect = true;
3773    boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
3774    if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
3775    shrink = ignoreShrink = true;
3776    int result = OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, OS.TVI_ROOT);
3777    ignoreShrink = false;
3778    if (redraw) {
3779        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
3780        OS.InvalidateRect (handle, null, true);
3781    }
3782    ignoreDeselect = ignoreSelect = false;
3783    if (result == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
3784    if (imageList != null) {
3785        OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
3786        display.releaseImageList (imageList);
3787    }
3788    imageList = null;
3789    if (hwndParent == 0 && !linesVisible) {
3790        if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
3791            customDraw = false;
3792        }
3793    }
3794    hAnchor = hInsert = hFirstIndexOf = hLastIndexOf = 0;
3795    itemCount = -1;
3796    items = new TreeItem [4];
3797    scrollWidth = 0;
3798    setScrollWidth ();
3799    updateScrollBar ();
3800}
3801
3802/**
3803 * Removes the listener from the collection of listeners who will
3804 * be notified when the user changes the receiver's selection.
3805 *
3806 * @param listener the listener which should no longer be notified
3807 *
3808 * @exception IllegalArgumentException <ul>
3809 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3810 * </ul>
3811 * @exception SWTException <ul>
3812 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3813 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3814 * </ul>
3815 *
3816 * @see SelectionListener
3817 * @see #addSelectionListener
3818 */

3819public void removeSelectionListener (SelectionListener listener) {
3820    checkWidget ();
3821    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
3822    eventTable.unhook (SWT.Selection, listener);
3823    eventTable.unhook (SWT.DefaultSelection, listener);
3824}
3825
3826/**
3827 * Removes the listener from the collection of listeners who will
3828 * be notified when items in the receiver are expanded or collapsed.
3829 *
3830 * @param listener the listener which should no longer be notified
3831 *
3832 * @exception IllegalArgumentException <ul>
3833 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
3834 * </ul>
3835 * @exception SWTException <ul>
3836 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3837 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3838 * </ul>
3839 *
3840 * @see TreeListener
3841 * @see #addTreeListener
3842 */

3843public void removeTreeListener(TreeListener listener) {
3844    checkWidget ();
3845    if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
3846    if (eventTable == null) return;
3847    eventTable.unhook (SWT.Expand, listener);
3848    eventTable.unhook (SWT.Collapse, listener);
3849}
3850
3851/**
3852 * Display a mark indicating the point at which an item will be inserted.
3853 * The drop insert item has a visual hint to show where a dragged item
3854 * will be inserted when dropped on the tree.
3855 *
3856 * @param item the insert item. Null will clear the insertion mark.
3857 * @param before true places the insert mark above 'item'. false places
3858 * the insert mark below 'item'.
3859 *
3860 * @exception IllegalArgumentException <ul>
3861 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
3862 * </ul>
3863 * @exception SWTException <ul>
3864 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3865 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3866 * </ul>
3867 */

3868public void setInsertMark (TreeItem item, boolean before) {
3869    checkWidget ();
3870    int hItem = 0;
3871    if (item != null) {
3872        if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3873        hItem = item.handle;
3874    }
3875    hInsert = hItem;
3876    insertAfter = !before;
3877    OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
3878}
3879
3880/**
3881 * Sets the number of root-level items contained in the receiver.
3882 *
3883 * @param count the number of items
3884 *
3885 * @exception SWTException <ul>
3886 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3887 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3888 * </ul>
3889 *
3890 * @since 3.2
3891 */

3892public void setItemCount (int count) {
3893    checkWidget ();
3894    count = Math.max (0, count);
3895    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3896    setItemCount (count, OS.TVGN_ROOT, hItem);
3897}
3898
3899void setItemCount (int count, int hParent, int hItem) {
3900    boolean redraw = false;
3901    if (OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) == 0) {
3902        redraw = drawCount == 0 && OS.IsWindowVisible (handle);
3903        if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
3904    }
3905    int itemCount = 0;
3906    while (hItem != 0 && itemCount < count) {
3907        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3908        itemCount++;
3909    }
3910    TVITEM tvItem = new TVITEM ();
3911    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3912    while (hItem != 0) {
3913        tvItem.hItem = hItem;
3914        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3915        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3916        TreeItem item = tvItem.lParam != -1 ? items [tvItem.lParam] : null;
3917        if (item != null && !item.isDisposed ()) {
3918            item.dispose ();
3919        } else {
3920            releaseItem (tvItem.hItem, tvItem, false);
3921            destroyItem (null, tvItem.hItem);
3922        }
3923    }
3924    if ((style & SWT.VIRTUAL) != 0) {
3925        for (int i=itemCount; i<count; i++) {
3926            createItem (null, hParent, OS.TVI_LAST, 0);
3927        }
3928    } else {
3929        shrink = true;
3930        int extra = Math.max (4, (count + 3) / 4 * 4);
3931        TreeItem [] newItems = new TreeItem [items.length + extra];
3932        System.arraycopy (items, 0, newItems, 0, items.length);
3933        items = newItems;
3934        for (int i=itemCount; i<count; i++) {
3935            new TreeItem (this, SWT.NONE, hParent, OS.TVI_LAST, 0);
3936        }
3937    }
3938    if (redraw) {
3939        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
3940        OS.InvalidateRect (handle, null, true);
3941    }
3942}
3943
3944/**
3945 * Sets the height of the area which would be used to
3946 * display <em>one</em> of the items in the tree.
3947 *
3948 * @param itemHeight the height of one item
3949 *
3950 * @exception SWTException <ul>
3951 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3952 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3953 * </ul>
3954 *
3955 * @since 3.2
3956 */

3957/*public*/ void setItemHeight (int itemHeight) {
3958    checkWidget ();
3959    if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT);
3960    OS.SendMessage (handle, OS.TVM_SETITEMHEIGHT, itemHeight, 0);
3961}
3962
3963/**
3964 * Marks the receiver's lines as visible if the argument is <code>true</code>,
3965 * and marks it invisible otherwise.
3966 * <p>
3967 * If one of the receiver's ancestors is not visible or some
3968 * other condition makes the receiver not visible, marking
3969 * it visible may not actually cause it to be displayed.
3970 * </p>
3971 *
3972 * @param show the new visibility state
3973 *
3974 * @exception SWTException <ul>
3975 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3976 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3977 * </ul>
3978 *
3979 * @since 3.1
3980 */

3981public void setLinesVisible (boolean show) {
3982    checkWidget ();
3983    if (linesVisible == show) return;
3984    linesVisible = show;
3985    if (hwndParent == 0 && linesVisible) customDraw = true;
3986    OS.InvalidateRect (handle, null, true);
3987}
3988
3989int scrolledHandle () {
3990    if (hwndHeader == 0) return handle;
3991    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
3992    return count == 0 ? handle : hwndParent;
3993}
3994
3995void select (int hItem, TVITEM tvItem) {
3996    while (hItem != 0) {
3997        tvItem.hItem = hItem;
3998        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
3999        int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4000        select (hFirstItem, tvItem);
4001        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4002    }
4003}
4004
4005/**
4006 * Selects all of the items in the receiver.
4007 * <p>
4008 * If the receiver is single-select, do nothing.
4009 * </p>
4010 *
4011 * @exception SWTException <ul>
4012 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4013 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4014 * </ul>
4015 */

4016public void selectAll () {
4017    checkWidget ();
4018    if ((style & SWT.SINGLE) != 0) return;
4019    TVITEM tvItem = new TVITEM ();
4020    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4021    tvItem.state = OS.TVIS_SELECTED;
4022    tvItem.stateMask = OS.TVIS_SELECTED;
4023    int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
4024    OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
4025    if ((style & SWT.VIRTUAL) != 0) {
4026        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4027        select (hItem, tvItem);
4028    } else {
4029        for (int i=0; i<items.length; i++) {
4030            TreeItem item = items [i];
4031            if (item != null) {
4032                tvItem.hItem = item.handle;
4033                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4034            }
4035        }
4036    }
4037    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
4038}
4039
4040void setBackgroundImage (int hBitmap) {
4041    super.setBackgroundImage (hBitmap);
4042    if (hBitmap != 0) {
4043        /*
4044        * Feature in Windows. If TVM_SETBKCOLOR is never
4045        * used to set the background color of a tree, the
4046        * background color of the lines and the plus/minus
4047        * will be drawn using the default background color,
4048        * not the HBRUSH returned from WM_CTLCOLOR. The fix
4049        * is to set the background color to the default (when
4050        * it is already the default) to make Windows use the
4051        * brush.
4052        */

4053        if (OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0) == -1) {
4054            OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
4055        }
4056        _setBackgroundPixel (-1);
4057    } else {
4058        Control control = findBackgroundControl ();
4059        if (control == null) control = this;
4060        if (control.backgroundImage == null) {
4061            setBackgroundPixel (control.getBackgroundPixel ());
4062        }
4063    }
4064    /*
4065    * Feature in Windows. When the tree has the style
4066    * TVS_FULLROWSELECT, the background color for the
4067    * entire row is filled when an item is painted,
4068    * drawing on top of the background image. The fix
4069    * is to clear TVS_FULLROWSELECT when a background
4070    * image is set.
4071    */

4072    updateFullSelection ();
4073}
4074
4075void setBackgroundPixel (int pixel) {
4076    Control control = findImageControl ();
4077    if (control != null) {
4078        setBackgroundImage (control.backgroundImage);
4079        return;
4080    }
4081    /*
4082    * Feature in Windows. When a tree is given a background color
4083    * using TVM_SETBKCOLOR and the tree is disabled, Windows draws
4084    * the tree using the background color rather than the disabled
4085    * colors. This is different from the table which draws grayed.
4086    * The fix is to set the default background color while the tree
4087    * is disabled and restore it when enabled.
4088    */

4089    if (OS.IsWindowEnabled (handle)) _setBackgroundPixel (pixel);
4090
4091    /*
4092    * Feature in Windows. When the tree has the style
4093    * TVS_FULLROWSELECT, the background color for the
4094    * entire row is filled when an item is painted,
4095    * drawing on top of the background image. The fix
4096    * is to restore TVS_FULLROWSELECT when a background
4097    * color is set.
4098    */

4099    updateFullSelection ();
4100}
4101
4102void setBounds (int x, int y, int width, int height, int flags) {
4103    /*
4104    * Ensure that the selection is visible when the tree is resized
4105    * from a zero size to a size that can show the selection.
4106    */

4107    boolean fixSelection = false;
4108    if ((flags & OS.SWP_NOSIZE) == 0 && (width != 0 || height != 0)) {
4109        if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
4110            fixSelection = true;
4111        }
4112    }
4113    super.setBounds (x, y, width, height, flags);
4114    if (fixSelection) {
4115        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
4116        if (hItem != 0) showItem (hItem);
4117    }
4118}
4119
4120void setCursor () {
4121    /*
4122    * Bug in Windows. Under certain circumstances, when WM_SETCURSOR
4123    * is sent from SendMessage(), Windows GP's in the window proc for
4124    * the tree. The fix is to avoid calling the tree window proc and
4125    * set the cursor for the tree outside of WM_SETCURSOR.
4126    *
4127    * NOTE: This code assumes that the default cursor for the tree
4128    * is IDC_ARROW.
4129    */

4130    Cursor cursor = findCursor ();
4131    int hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : cursor.handle;
4132    OS.SetCursor (hCursor);
4133}
4134
4135/**
4136 * Sets the order that the items in the receiver should
4137 * be displayed in to the given argument which is described
4138 * in terms of the zero-relative ordering of when the items
4139 * were added.
4140 *
4141 * @param order the new order to display the items
4142 *
4143 * @exception SWTException <ul>
4144 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4145 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4146 * </ul>
4147 * @exception IllegalArgumentException <ul>
4148 * <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
4149 * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
4150 * </ul>
4151 *
4152 * @see Tree#getColumnOrder()
4153 * @see TreeColumn#getMoveable()
4154 * @see TreeColumn#setMoveable(boolean)
4155 * @see SWT#Move
4156 *
4157 * @since 3.2
4158 */

4159public void setColumnOrder (int [] order) {
4160    checkWidget ();
4161    if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
4162    int count = 0;
4163    if (hwndHeader != 0) {
4164        count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
4165    }
4166    if (count == 0) {
4167        if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
4168        return;
4169    }
4170    if (order.length != count) error (SWT.ERROR_INVALID_ARGUMENT);
4171    int [] oldOrder = new int [count];
4172    OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, oldOrder);
4173    boolean reorder = false;
4174    boolean [] seen = new boolean [count];
4175    for (int i=0; i<order.length; i++) {
4176        int index = order [i];
4177        if (index < 0 || index >= count) error (SWT.ERROR_INVALID_RANGE);
4178        if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
4179        seen [index] = true;
4180        if (index != oldOrder [i]) reorder = true;
4181    }
4182    if (reorder) {
4183        RECT [] oldRects = new RECT [count];
4184        for (int i=0; i<count; i++) {
4185            oldRects [i] = new RECT ();
4186            OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, oldRects [i]);
4187        }
4188        OS.SendMessage (hwndHeader, OS.HDM_SETORDERARRAY, order.length, order);
4189        OS.InvalidateRect (handle, null, true);
4190        updateImageList ();
4191        TreeColumn [] newColumns = new TreeColumn [count];
4192        System.arraycopy (columns, 0, newColumns, 0, count);
4193        RECT newRect = new RECT ();
4194        for (int i=0; i<count; i++) {
4195            TreeColumn column = newColumns [i];
4196            if (!column.isDisposed ()) {
4197                OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, newRect);
4198                if (newRect.left != oldRects [i].left) {
4199                    column.updateToolTip (i);
4200                    column.sendEvent (SWT.Move);
4201                }
4202            }
4203        }
4204    }
4205}
4206
4207void setCheckboxImageList () {
4208    if ((style & SWT.CHECK) == 0) return;
4209    int count = 5, flags = 0;
4210    if (OS.IsWinCE) {
4211        flags |= OS.ILC_COLOR;
4212    } else {
4213        if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
4214            flags |= OS.ILC_COLOR32;
4215        } else {
4216            int hDC = OS.GetDC (handle);
4217            int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
4218            int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
4219            OS.ReleaseDC (handle, hDC);
4220            int depth = bits * planes;
4221            switch (depth) {
4222                case 4: flags |= OS.ILC_COLOR4; break;
4223                case 8: flags |= OS.ILC_COLOR8; break;
4224                case 16: flags |= OS.ILC_COLOR16; break;
4225                case 24: flags |= OS.ILC_COLOR24; break;
4226                case 32: flags |= OS.ILC_COLOR32; break;
4227                default: flags |= OS.ILC_COLOR; break;
4228            }
4229            flags |= OS.ILC_MASK;
4230        }
4231    }
4232    if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.ILC_MIRROR;
4233    int height = OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0), width = height;
4234    int hStateList = OS.ImageList_Create (width, height, flags, count, count);
4235    int hDC = OS.GetDC (handle);
4236    int memDC = OS.CreateCompatibleDC (hDC);
4237    int hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height);
4238    int hOldBitmap = OS.SelectObject (memDC, hBitmap);
4239    RECT rect = new RECT ();
4240    OS.SetRect (rect, 0, 0, width * count, height);
4241    /*
4242    * NOTE: DrawFrameControl() draws a black and white
4243    * mask when not drawing a push button. In order to
4244    * make the box surrounding the check mark transparent,
4245    * fill it with a color that is neither black or white.
4246    */

4247    int clrBackground = 0;
4248    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
4249        Control control = findBackgroundControl ();
4250        if (control == null) control = this;
4251        clrBackground = control.getBackgroundPixel ();
4252    } else {
4253        clrBackground = 0x020000FF;
4254        if ((clrBackground & 0xFFFFFF) == OS.GetSysColor (OS.COLOR_WINDOW)) {
4255            clrBackground = 0x0200FF00;
4256        }
4257    }
4258    int hBrush = OS.CreateSolidBrush (clrBackground);
4259    OS.FillRect (memDC, rect, hBrush);
4260    OS.DeleteObject (hBrush);
4261    int oldFont = OS.SelectObject (hDC, defaultFont ());
4262    TEXTMETRIC tm = OS.IsUnicode ? (TEXTMETRIC) new TEXTMETRICW () : new TEXTMETRICA ();
4263    OS.GetTextMetrics (hDC, tm);
4264    OS.SelectObject (hDC, oldFont);
4265    int itemWidth = Math.min (tm.tmHeight, width);
4266    int itemHeight = Math.min (tm.tmHeight, height);
4267    int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1;
4268    OS.SetRect (rect, left + width, top, left + width + itemWidth, top + itemHeight);
4269    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
4270        int hTheme = display.hButtonTheme ();
4271        OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4272        rect.left += width; rect.right += width;
4273        OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_CHECKEDNORMAL, rect, null);
4274        rect.left += width; rect.right += width;
4275        OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4276        rect.left += width; rect.right += width;
4277        OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_MIXEDNORMAL, rect, null);
4278    } else {
4279        OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT);
4280        rect.left += width; rect.right += width;
4281        OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT);
4282        rect.left += width; rect.right += width;
4283        OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4284        rect.left += width; rect.right += width;
4285        OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4286    }
4287    OS.SelectObject (memDC, hOldBitmap);
4288    OS.DeleteDC (memDC);
4289    OS.ReleaseDC (handle, hDC);
4290    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
4291        OS.ImageList_Add (hStateList, hBitmap, 0);
4292    } else {
4293        OS.ImageList_AddMasked (hStateList, hBitmap, clrBackground);
4294    }
4295    OS.DeleteObject (hBitmap);
4296    int hOldStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
4297    OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, hStateList);
4298    if (hOldStateList != 0) OS.ImageList_Destroy (hOldStateList);
4299}
4300
4301public void setFont (Font font) {
4302    checkWidget ();
4303    super.setFont (font);
4304    if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
4305}
4306
4307void setForegroundPixel (int pixel) {
4308    /*
4309    * Bug in Windows. When the tree is using the explorer
4310    * theme, it does not use COLOR_WINDOW_TEXT for the
4311    * foreground. When TVM_SETTEXTCOLOR is called with -1,
4312    * it resets the color to black, not COLOR_WINDOW_TEXT.
4313    * The fix is to explicitly set the color.
4314    */

4315    if (explorerTheme) {
4316        if (pixel == -1) pixel = defaultForeground ();
4317    }
4318    OS.SendMessage (handle, OS.TVM_SETTEXTCOLOR, 0, pixel);
4319}
4320
4321/**
4322 * Marks the receiver's header as visible if the argument is <code>true</code>,
4323 * and marks it invisible otherwise.
4324 * <p>
4325 * If one of the receiver's ancestors is not visible or some
4326 * other condition makes the receiver not visible, marking
4327 * it visible may not actually cause it to be displayed.
4328 * </p>
4329 *
4330 * @param show the new visibility state
4331 *
4332 * @exception SWTException <ul>
4333 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4334 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4335 * </ul>
4336 *
4337 * @since 3.1
4338 */

4339public void setHeaderVisible (boolean show) {
4340    checkWidget ();
4341    if (hwndHeader == 0) {
4342        if (!show) return;
4343        createParent ();
4344    }
4345    int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
4346    if (show) {
4347        if ((bits & OS.HDS_HIDDEN) == 0) return;
4348        bits &= ~OS.HDS_HIDDEN;
4349        OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4350        OS.ShowWindow (hwndHeader, OS.SW_SHOW);
4351    } else {
4352        if ((bits & OS.HDS_HIDDEN) != 0) return;
4353        bits |= OS.HDS_HIDDEN;
4354        OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4355        OS.ShowWindow (hwndHeader, OS.SW_HIDE);
4356    }
4357    setScrollWidth ();
4358    updateHeaderToolTips ();
4359    updateScrollBar ();
4360}
4361
4362public void setRedraw (boolean redraw) {
4363    checkWidget ();
4364    /*
4365    * Feature in Windows. When WM_SETREDRAW is used to
4366    * turn off redraw, the scroll bars are updated when
4367    * items are added and removed. The fix is to call
4368    * the default window proc to stop all drawing.
4369    *
4370    * Bug in Windows. For some reason, when WM_SETREDRAW
4371    * is used to turn redraw on for a tree and the tree
4372    * contains no items, the last item in the tree does
4373    * not redraw properly. If the tree has only one item,
4374    * that item is not drawn. If another window is dragged
4375    * on top of the item, parts of the item are redrawn
4376    * and erased at random. The fix is to ensure that this
4377    * case doesn't happen by inserting and deleting an item
4378    * when redraw is turned on and there are no items in
4379    * the tree.
4380    */

4381    int hItem = 0;
4382    if (redraw) {
4383        if (drawCount == 1) {
4384            int count = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
4385            if (count == 0) {
4386                TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
4387                tvInsert.hInsertAfter = OS.TVI_FIRST;
4388                hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
4389            }
4390            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4391        }
4392    }
4393    super.setRedraw (redraw);
4394    if (!redraw) {
4395        if (drawCount == 1) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4396    }
4397    if (hItem != 0) {
4398        ignoreShrink = true;
4399        OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
4400        ignoreShrink = false;
4401    }
4402}
4403
4404void setScrollWidth () {
4405    if (hwndHeader == 0 || hwndParent == 0) return;
4406    int width = 0;
4407    HDITEM hdItem = new HDITEM ();
4408    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
4409    for (int i=0; i<count; i++) {
4410        hdItem.mask = OS.HDI_WIDTH;
4411        OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
4412        width += hdItem.cxy;
4413    }
4414    setScrollWidth (Math.max (scrollWidth, width));
4415}
4416
4417void setScrollWidth (int width) {
4418    if (hwndHeader == 0 || hwndParent == 0) return;
4419    //TEMPORARY CODE
4420
//scrollWidth = width;
4421
int left = 0;
4422    RECT rect = new RECT ();
4423    SCROLLINFO info = new SCROLLINFO ();
4424    info.cbSize = SCROLLINFO.sizeof;
4425    info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
4426    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
4427    if (count == 0 && width == 0) {
4428        OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4429        info.nPage = info.nMax + 1;
4430        OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4431        OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
4432        info.nPage = info.nMax + 1;
4433        OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
4434    } else {
4435        OS.GetClientRect (hwndParent, rect);
4436        OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4437        info.nMax = width;
4438        info.nPage = rect.right - rect.left + 1;
4439        OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4440        info.fMask = OS.SIF_POS;
4441        OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4442        left = info.nPos;
4443    }
4444    if (horizontalBar != null) {
4445        horizontalBar.setIncrement (INCREMENT);
4446        horizontalBar.setPageIncrement (info.nPage);
4447    }
4448    OS.GetClientRect (hwndParent, rect);
4449    int hHeap = OS.GetProcessHeap ();
4450    HDLAYOUT playout = new HDLAYOUT ();
4451    playout.prc = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, RECT.sizeof);
4452    playout.pwpos = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, WINDOWPOS.sizeof);
4453    OS.MoveMemory (playout.prc, rect, RECT.sizeof);
4454    OS.SendMessage (hwndHeader, OS.HDM_LAYOUT, 0, playout);
4455    WINDOWPOS pos = new WINDOWPOS ();
4456    OS.MoveMemory (pos, playout.pwpos, WINDOWPOS.sizeof);
4457    if (playout.prc != 0) OS.HeapFree (hHeap, 0, playout.prc);
4458    if (playout.pwpos != 0) OS.HeapFree (hHeap, 0, playout.pwpos);
4459    SetWindowPos (hwndHeader, OS.HWND_TOP, pos.x - left, pos.y, pos.cx + left, pos.cy, OS.SWP_NOACTIVATE);
4460    int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
4461    int b = (bits & OS.WS_EX_CLIENTEDGE) != 0 ? OS.GetSystemMetrics (OS.SM_CXEDGE) : 0;
4462    int w = pos.cx + (count == 0 && width == 0 ? 0 : OS.GetSystemMetrics (OS.SM_CXVSCROLL));
4463    int h = rect.bottom - rect.top - pos.cy;
4464    boolean oldIgnore = ignoreResize;
4465    ignoreResize = true;
4466    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);
4467    ignoreResize = oldIgnore;
4468}
4469
4470void setSelection (int hItem, TVITEM tvItem, TreeItem [] selection) {
4471    while (hItem != 0) {
4472        int index = 0;
4473        while (index < selection.length) {
4474            TreeItem item = selection [index];
4475            if (item != null && item.handle == hItem) break;
4476            index++;
4477        }
4478        tvItem.hItem = hItem;
4479        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4480        if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
4481            if (index == selection.length) {
4482                tvItem.state = 0;
4483                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4484            }
4485        } else {
4486            if (index != selection.length) {
4487                tvItem.state = OS.TVIS_SELECTED;
4488                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4489            }
4490        }
4491        int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4492        setSelection (hFirstItem, tvItem, selection);
4493        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4494    }
4495}
4496
4497/**
4498 * Sets the receiver's selection to the given item.
4499 * The current selection is cleared before the new item is selected.
4500 * <p>
4501 * If the item is not in the receiver, then it is ignored.
4502 * </p>
4503 *
4504 * @param item the item to select
4505 *
4506 * @exception IllegalArgumentException <ul>
4507 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4508 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4509 * </ul>
4510 * @exception SWTException <ul>
4511 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4512 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4513 * </ul>
4514 *
4515 * @since 3.2
4516 */

4517public void setSelection (TreeItem item) {
4518    checkWidget ();
4519    if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4520    setSelection (new TreeItem [] {item});
4521}
4522
4523/**
4524 * Sets the receiver's selection to be the given array of items.
4525 * The current selection is cleared before the new items are selected.
4526 * <p>
4527 * Items that are not in the receiver are ignored.
4528 * If the receiver is single-select and multiple items are specified,
4529 * then all items are ignored.
4530 * </p>
4531 *
4532 * @param items the array of items
4533 *
4534 * @exception IllegalArgumentException <ul>
4535 * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
4536 * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
4537 * </ul>
4538 * @exception SWTException <ul>
4539 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4540 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4541 * </ul>
4542 *
4543 * @see Tree#deselectAll()
4544 */

4545public void setSelection (TreeItem [] items) {
4546    checkWidget ();
4547    if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
4548    int length = items.length;
4549    if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) {
4550        deselectAll();
4551        return;
4552    }
4553        
4554    /* Select/deselect the first item */
4555    TreeItem item = items [0];
4556    if (item != null) {
4557        if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
4558        int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
4559        int hNewItem = hAnchor = item.handle;
4560        
4561        /*
4562        * Bug in Windows. When TVM_SELECTITEM is used to select and
4563        * scroll an item to be visible and the client area of the tree
4564        * is smaller that the size of one item, TVM_SELECTITEM makes
4565        * the next item in the tree visible by making it the top item
4566        * instead of making the desired item visible. The fix is to
4567        * detect the case when the client area is too small and make
4568        * the desired visible item be the top item in the tree.
4569        *
4570        * Note that TVM_SELECTITEM when called with TVGN_FIRSTVISIBLE
4571        * also requires the work around for scrolling.
4572        */

4573        boolean fixScroll = checkScroll (hNewItem);
4574        if (fixScroll) {
4575            OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
4576            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4577        }
4578        ignoreSelect = true;
4579        OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
4580        ignoreSelect = false;
4581        if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
4582            OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hNewItem);
4583            int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hNewItem);
4584            if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
4585        }
4586        if (fixScroll) {
4587            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4588            OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
4589        }
4590        
4591        /*
4592        * Feature in Windows. When the old and new focused item
4593        * are the same, Windows does not check to make sure that
4594        * the item is actually selected, not just focused. The
4595        * fix is to force the item to draw selected by setting
4596        * the state mask, and to ensure that it is visible.
4597        */

4598        if (hOldItem == hNewItem) {
4599            TVITEM tvItem = new TVITEM ();
4600            tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4601            tvItem.state = OS.TVIS_SELECTED;
4602            tvItem.stateMask = OS.TVIS_SELECTED;
4603            tvItem.hItem = hNewItem;
4604            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4605            showItem (hNewItem);
4606        }
4607    }
4608    if ((style & SWT.SINGLE) != 0) return;
4609
4610    /* Select/deselect the rest of the items */
4611    TVITEM tvItem = new TVITEM ();
4612    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4613    tvItem.stateMask = OS.TVIS_SELECTED;
4614    int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
4615    OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
4616    if ((style & SWT.VIRTUAL) != 0) {
4617        int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4618        setSelection (hItem, tvItem, items);
4619    } else {
4620        for (int i=0; i<this.items.length; i++) {
4621            item = this.items [i];
4622            if (item != null) {
4623                int index = 0;
4624                while (index < length) {
4625                    if (items [index] == item) break;
4626                    index++;
4627                }
4628                tvItem.hItem = item.handle;
4629                OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4630                if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
4631                    if (index == length) {
4632                        tvItem.state = 0;
4633                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4634                    }
4635                } else {
4636                    if (index != length) {
4637                        tvItem.state = OS.TVIS_SELECTED;
4638                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4639                    }
4640                }
4641            }
4642        }
4643    }
4644    OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
4645}
4646
4647/**
4648 * Sets the column used by the sort indicator for the receiver. A null
4649 * value will clear the sort indicator. The current sort column is cleared
4650 * before the new column is set.
4651 *
4652 * @param column the column used by the sort indicator or <code>null</code>
4653 *
4654 * @exception IllegalArgumentException <ul>
4655 * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
4656 * </ul>
4657 * @exception SWTException <ul>
4658 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4659 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4660 * </ul>
4661 *
4662 * @since 3.2
4663 */

4664public void setSortColumn (TreeColumn column) {
4665    checkWidget ();
4666    if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
4667    if (sortColumn != null && !sortColumn.isDisposed ()) {
4668        sortColumn.setSortDirection (SWT.NONE);
4669    }
4670    sortColumn = column;
4671    if (sortColumn != null && sortDirection != SWT.NONE) {
4672        sortColumn.setSortDirection (sortDirection);
4673    }
4674}
4675
4676/**
4677 * Sets the direction of the sort indicator for the receiver. The value
4678 * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
4679 *
4680 * @param direction the direction of the sort indicator
4681 *
4682 * @exception SWTException <ul>
4683 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4684 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4685 * </ul>
4686 *
4687 * @since 3.2
4688 */

4689public void setSortDirection (int direction) {
4690    checkWidget ();
4691    if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) return;
4692    sortDirection = direction;
4693    if (sortColumn != null && !sortColumn.isDisposed ()) {
4694        sortColumn.setSortDirection (direction);
4695    }
4696}
4697
4698/**
4699 * Sets the item which is currently at the top of the receiver.
4700 * This item can change when items are expanded, collapsed, scrolled
4701 * or new items are added or removed.
4702 *
4703 * @param item the item to be shown
4704 *
4705 * @exception IllegalArgumentException <ul>
4706 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4707 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4708 * </ul>
4709 * @exception SWTException <ul>
4710 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4711 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4712 * </ul>
4713 *
4714 * @see Tree#getTopItem()
4715 *
4716 * @since 2.1
4717 */

4718public void setTopItem (TreeItem item) {
4719    checkWidget ();
4720    if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
4721    if (item.isDisposed ()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
4722    int hItem = item.handle;
4723    int hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
4724    if (hItem == hTopItem) return;
4725    boolean fixScroll = checkScroll (hItem), redraw = false;
4726    if (fixScroll) {
4727        OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
4728        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4729    } else {
4730        redraw = drawCount == 0 && OS.IsWindowVisible (handle);
4731        if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4732    }
4733    OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
4734    int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
4735    if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
4736    if (fixScroll) {
4737        OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4738        OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
4739    } else {
4740        if (redraw) {
4741            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4742            OS.InvalidateRect (handle, null, true);
4743        }
4744    }
4745    updateScrollBar ();
4746}
4747
4748void showItem (int hItem) {
4749    /*
4750    * Bug in Windows. When TVM_ENSUREVISIBLE is used to ensure
4751    * that an item is visible and the client area of the tree is
4752    * smaller that the size of one item, TVM_ENSUREVISIBLE makes
4753    * the next item in the tree visible by making it the top item
4754    * instead of making the desired item visible. The fix is to
4755    * detect the case when the client area is too small and make
4756    * the desired visible item be the top item in the tree.
4757    */

4758    if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
4759        boolean fixScroll = checkScroll (hItem);
4760        if (fixScroll) {
4761            OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
4762            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4763        }
4764        OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
4765        /* This code is intentionally commented */
4766        //int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
4767
//if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
4768
OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
4769        if (fixScroll) {
4770            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4771            OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
4772        }
4773    } else {
4774        boolean scroll = true;
4775        RECT itemRect = new RECT ();
4776        itemRect.left = hItem;
4777        if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) != 0) {
4778            forceResize ();
4779            RECT rect = new RECT ();
4780            OS.GetClientRect (handle, rect);
4781            POINT pt = new POINT ();
4782            pt.x = itemRect.left;
4783            pt.y = itemRect.top;
4784            if (OS.PtInRect (rect, pt)) {
4785                pt.y = itemRect.bottom;
4786                if (OS.PtInRect (rect, pt)) scroll = false;
4787            }
4788        }
4789        if (scroll) {
4790            boolean fixScroll = checkScroll (hItem);
4791            if (fixScroll) {
4792                OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
4793                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4794            }
4795            OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
4796            if (fixScroll) {
4797                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4798                OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
4799            }
4800        }
4801    }
4802    if (hwndParent != 0) {
4803        RECT itemRect = new RECT ();
4804        itemRect.left = hItem;
4805        if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 1, itemRect) != 0) {
4806            forceResize ();
4807            RECT rect = new RECT ();
4808            OS.GetClientRect (hwndParent, rect);
4809            OS.MapWindowPoints (hwndParent, handle, rect, 2);
4810            POINT pt = new POINT ();
4811            pt.x = itemRect.left;
4812            pt.y = itemRect.top;
4813            if (!OS.PtInRect (rect, pt)) {
4814                pt.y = itemRect.bottom;
4815                if (!OS.PtInRect (rect, pt)) {
4816                    SCROLLINFO info = new SCROLLINFO ();
4817                    info.cbSize = SCROLLINFO.sizeof;
4818                    info.fMask = OS.SIF_POS;
4819                    info.nPos = Math.max (0, pt.x - Tree.INSET / 2);
4820                    OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4821                    setScrollWidth ();
4822                }
4823            }
4824        }
4825    }
4826    updateScrollBar ();
4827}
4828
4829/**
4830 * Shows the column. If the column is already showing in the receiver,
4831 * this method simply returns. Otherwise, the columns are scrolled until
4832 * the column is visible.
4833 *
4834 * @param column the column to be shown
4835 *
4836 * @exception IllegalArgumentException <ul>
4837 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4838 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4839 * </ul>
4840 * @exception SWTException <ul>
4841 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4842 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4843 * </ul>
4844 *
4845 * @since 3.1
4846 */

4847public void showColumn (TreeColumn column) {
4848    checkWidget ();
4849    if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
4850    if (column.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
4851    if (column.parent != this) return;
4852    int index = indexOf (column);
4853    if (index == -1) return;
4854    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
4855    if (0 <= index && index < count) {
4856        if (hwndParent != 0) {
4857            forceResize ();
4858            RECT rect = new RECT ();
4859            OS.GetClientRect (hwndParent, rect);
4860            OS.MapWindowPoints (hwndParent, handle, rect, 2);
4861            RECT headerRect = new RECT ();
4862            OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
4863            boolean scroll = headerRect.left < rect.left;
4864            if (!scroll) {
4865                int width = Math.min (rect.right - rect.left, headerRect.right - headerRect.left);
4866                scroll = headerRect.left + width > rect.right;
4867            }
4868            if (scroll) {
4869                SCROLLINFO info = new SCROLLINFO ();
4870                info.cbSize = SCROLLINFO.sizeof;
4871                info.fMask = OS.SIF_POS;
4872                info.nPos = Math.max (0, headerRect.left - Tree.INSET / 2);
4873                OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4874                setScrollWidth ();
4875            }
4876        }
4877    }
4878}
4879
4880/**
4881 * Shows the item. If the item is already showing in the receiver,
4882 * this method simply returns. Otherwise, the items are scrolled
4883 * and expanded until the item is visible.
4884 *
4885 * @param item the item to be shown
4886 *
4887 * @exception IllegalArgumentException <ul>
4888 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4889 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4890 * </ul>
4891 * @exception SWTException <ul>
4892 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4893 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4894 * </ul>
4895 *
4896 * @see Tree#showSelection()
4897 */

4898public void showItem (TreeItem item) {
4899    checkWidget ();
4900    if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4901    if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
4902    showItem (item.handle);
4903}
4904
4905/**
4906 * Shows the selection. If the selection is already showing in the receiver,
4907 * this method simply returns. Otherwise, the items are scrolled until
4908 * the selection is visible.
4909 *
4910 * @exception SWTException <ul>
4911 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4912 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4913 * </ul>
4914 *
4915 * @see Tree#showItem(TreeItem)
4916 */

4917public void showSelection () {
4918    checkWidget ();
4919    int hItem = 0;
4920    if ((style & SWT.SINGLE) != 0) {
4921        hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
4922        if (hItem == 0) return;
4923        int state = 0;
4924        if (OS.IsWinCE) {
4925            TVITEM tvItem = new TVITEM ();
4926            tvItem.hItem = hItem;
4927            tvItem.mask = OS.TVIF_STATE;
4928            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4929            state = tvItem.state;
4930        } else {
4931            state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
4932        }
4933        if ((state & OS.TVIS_SELECTED) == 0) return;
4934    } else {
4935        int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
4936        OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
4937        TVITEM tvItem = null;
4938        if (OS.IsWinCE) {
4939            tvItem = new TVITEM ();
4940            tvItem.mask = OS.TVIF_STATE;
4941        }
4942        if ((style & SWT.VIRTUAL) != 0) {
4943            int hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4944            hItem = getNextSelection (hRoot, tvItem);
4945        } else {
4946            //FIXME - this code expands first selected item it finds
4947
int index = 0;
4948            while (index <items.length) {
4949                TreeItem item = items [index];
4950                if (item != null) {
4951                    int state = 0;
4952                    if (OS.IsWinCE) {
4953                        tvItem.hItem = item.handle;
4954                        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4955                        state = tvItem.state;
4956                    } else {
4957                        state = OS.SendMessage (handle, OS.TVM_GETITEMSTATE, item.handle, OS.TVIS_SELECTED);
4958                    }
4959                    if ((state & OS.TVIS_SELECTED) != 0) {
4960                        hItem = item.handle;
4961                        break;
4962                    }
4963                }
4964                index++;
4965            }
4966        }
4967        OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
4968    }
4969    if (hItem != 0) showItem (hItem);
4970}
4971
4972/*public*/ void sort () {
4973    checkWidget ();
4974    if ((style & SWT.VIRTUAL) != 0) return;
4975    sort (OS.TVI_ROOT, false);
4976}
4977
4978void sort (int hParent, boolean all) {
4979    int itemCount = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
4980    if (itemCount == 0 || itemCount == 1) return;
4981    hFirstIndexOf = hLastIndexOf = 0;
4982    itemCount = -1;
4983    if (sortDirection == SWT.UP || sortDirection == SWT.NONE) {
4984        OS.SendMessage (handle, OS.TVM_SORTCHILDREN, all ? 1 : 0, hParent);
4985    } else {
4986        Callback compareCallback = new Callback (this, "CompareFunc", 3);
4987        int lpfnCompare = compareCallback.getAddress ();
4988        TVSORTCB psort = new TVSORTCB ();
4989        psort.hParent = hParent;
4990        psort.lpfnCompare = lpfnCompare;
4991        psort.lParam = sortColumn == null ? 0 : indexOf (sortColumn);
4992        OS.SendMessage (handle, OS.TVM_SORTCHILDRENCB, all ? 1 : 0, psort);
4993        compareCallback.dispose ();
4994    }
4995}
4996
4997void subclass () {
4998    super.subclass ();
4999    if (hwndHeader != 0) {
5000        OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, display.windowProc);
5001    }
5002}
5003
5004String JavaDoc toolTipText (NMTTDISPINFO hdr) {
5005    int hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
5006    if (hwndToolTip == hdr.hwndFrom && toolTipText != null) return ""; //$NON-NLS-1$
5007
if (headerToolTipHandle == hdr.hwndFrom) {
5008        int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
5009        for (int i=0; i<count; i++) {
5010            TreeColumn column = columns [i];
5011            if (column.id == hdr.idFrom) return column.toolTipText;
5012        }
5013        return super.toolTipText (hdr);
5014    }
5015    if (itemToolTipHandle == hdr.hwndFrom && hwndHeader != 0) {
5016        if (toolTipText != null) return "";
5017        if (!hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
5018            int pos = OS.GetMessagePos ();
5019            POINT pt = new POINT();
5020            pt.x = (short) (pos & 0xFFFF);
5021            pt.y = (short) (pos >> 16);
5022            OS.ScreenToClient (handle, pt);
5023            TVHITTESTINFO lpht = new TVHITTESTINFO ();
5024            lpht.x = pt.x;
5025            lpht.y = pt.y;
5026            OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
5027            if (lpht.hItem != 0) {
5028                int hDC = OS.GetDC (handle);
5029                int oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
5030                if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
5031                RECT rect = new RECT ();
5032                OS.GetClientRect (hwndParent, rect);
5033                OS.MapWindowPoints (hwndParent, handle, rect, 2);
5034                TreeItem item = _getItem (lpht.hItem);
5035                String JavaDoc text = null;
5036                int index = 0, count = Math.max (1, OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0));
5037                int [] order = new int [count];
5038                OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
5039                while (index < count) {
5040                    int hFont = item.cellFont != null ? item.cellFont [order [index]] : -1;
5041                    if (hFont == -1) hFont = item.font;
5042                    if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
5043                    RECT cellRect = item.getBounds (order [index], true, false, true, false, true, hDC);
5044                    if (hFont != -1) OS.SelectObject (hDC, hFont);
5045                    if (cellRect.left > rect.right) break;
5046                    cellRect.right = Math.min (cellRect.right, rect.right);
5047                    if (OS.PtInRect (cellRect, pt)) {
5048                        RECT textRect = item.getBounds (order [index], true, false, false, false, false, hDC);
5049                        if (textRect.right > cellRect.right) {
5050                            if (order [index] == 0) {
5051                                text = item.text;
5052                            } else {
5053                                String JavaDoc[] strings = item.strings;
5054                                if (strings != null) text = strings [order [index]];
5055                            }
5056                        }
5057                        break;
5058                    }
5059                    index++;
5060                }
5061                if (newFont != 0) OS.SelectObject (hDC, oldFont);
5062                OS.ReleaseDC (handle, hDC);
5063                if (text != null) return text;
5064            }
5065        }
5066    }
5067    return super.toolTipText (hdr);
5068}
5069
5070int topHandle () {
5071    return hwndParent != 0 ? hwndParent : handle;
5072}
5073
5074void updateFullSelection () {
5075    if ((style & SWT.FULL_SELECTION) != 0) {
5076        int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
5077        if ((newBits & OS.TVS_FULLROWSELECT) != 0) {
5078            if (!OS.IsWindowEnabled (handle) || findImageControl () != null) {
5079                if (!explorerTheme) newBits &= ~OS.TVS_FULLROWSELECT;
5080            }
5081        } else {
5082            if (OS.IsWindowEnabled (handle) && findImageControl () == null) {
5083                if (!hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
5084                    newBits |= OS.TVS_FULLROWSELECT;
5085                }
5086            }
5087        }
5088        if (newBits != oldBits) {
5089            OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
5090            OS.InvalidateRect (handle, null, true);
5091        }
5092    }
5093}
5094
5095void updateHeaderToolTips () {
5096    if (headerToolTipHandle == 0) return;
5097    RECT rect = new RECT ();
5098    TOOLINFO lpti = new TOOLINFO ();
5099    lpti.cbSize = TOOLINFO.sizeof;
5100    lpti.uFlags = OS.TTF_SUBCLASS;
5101    lpti.hwnd = hwndHeader;
5102    lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
5103    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
5104    for (int i=0; i<count; i++) {
5105        TreeColumn column = columns [i];
5106        if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, rect) != 0) {
5107            lpti.uId = column.id = display.nextToolTipId++;
5108            lpti.left = rect.left;
5109            lpti.top = rect.top;
5110            lpti.right = rect.right;
5111            lpti.bottom = rect.bottom;
5112            OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
5113        }
5114    }
5115}
5116
5117void updateImageList () {
5118    if (imageList == null) return;
5119    if (hwndHeader == 0) return;
5120    int i = 0, index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
5121    while (i < items.length) {
5122        TreeItem item = items [i];
5123        if (item != null) {
5124            Image image = null;
5125            if (index == 0) {
5126                image = item.image;
5127            } else {
5128                Image [] images = item.images;
5129                if (images != null) image = images [index];
5130            }
5131            if (image != null) break;
5132        }
5133        i++;
5134    }
5135    /*
5136    * Feature in Windows. When setting the same image list multiple
5137    * times, Windows does work making this operation slow. The fix
5138    * is to test for the same image list before setting the new one.
5139    */

5140    int hImageList = i == items.length ? 0 : imageList.getHandle ();
5141    int hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
5142    if (hImageList != hOldImageList) {
5143        OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
5144    }
5145}
5146
5147void updateImages () {
5148    if (sortColumn != null && !sortColumn.isDisposed ()) {
5149        if (OS.COMCTL32_MAJOR < 6) {
5150            switch (sortDirection) {
5151                case SWT.UP:
5152                case SWT.DOWN:
5153                    sortColumn.setImage (display.getSortImage (sortDirection), true, true);
5154                    break;
5155            }
5156        }
5157    }
5158}
5159
5160void updateScrollBar () {
5161    if (hwndParent != 0) {
5162        int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
5163        if (columnCount != 0 || scrollWidth != 0) {
5164            SCROLLINFO info = new SCROLLINFO ();
5165            info.cbSize = SCROLLINFO.sizeof;
5166            info.fMask = OS.SIF_ALL;
5167            int itemCount = OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
5168            if (itemCount == 0) {
5169                OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5170                info.nPage = info.nMax + 1;
5171                OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5172            } else {
5173                OS.GetScrollInfo (handle, OS.SB_VERT, info);
5174                if (info.nPage == 0) info.nPage = info.nMax + 1;
5175                OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5176            }
5177        }
5178    }
5179}
5180
5181void unsubclass () {
5182    super.unsubclass ();
5183    if (hwndHeader != 0) {
5184        OS.SetWindowLong (hwndHeader, OS.GWL_WNDPROC, HeaderProc);
5185    }
5186}
5187
5188int widgetStyle () {
5189    int bits = super.widgetStyle () | OS.TVS_SHOWSELALWAYS | OS.TVS_LINESATROOT | OS.TVS_HASBUTTONS | OS.TVS_NONEVENHEIGHT;
5190    if (EXPLORER_THEME && !OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
5191        bits |= OS.TVS_TRACKSELECT;
5192        if ((style & SWT.FULL_SELECTION) != 0) bits |= OS.TVS_FULLROWSELECT;
5193    } else {
5194        if ((style & SWT.FULL_SELECTION) != 0) {
5195            bits |= OS.TVS_FULLROWSELECT;
5196        } else {
5197            bits |= OS.TVS_HASLINES;
5198        }
5199    }
5200// bits |= OS.TVS_NOTOOLTIPS | OS.TVS_DISABLEDRAGDROP;
5201
return bits | OS.TVS_DISABLEDRAGDROP;
5202}
5203
5204TCHAR windowClass () {
5205    return TreeClass;
5206}
5207
5208int windowProc () {
5209    return TreeProc;
5210}
5211
5212int windowProc (int hwnd, int msg, int wParam, int lParam) {
5213    if (hwndHeader != 0 && hwnd == hwndHeader) {
5214        switch (msg) {
5215            /* This code is intentionally commented */
5216// case OS.WM_CONTEXTMENU: {
5217
// LRESULT result = wmContextMenu (hwnd, wParam, lParam);
5218
// if (result != null) return result.value;
5219
// break;
5220
// }
5221
case OS.WM_CAPTURECHANGED: {
5222                /*
5223                * Bug in Windows. When the capture changes during a
5224                * header drag, Windows does not redraw the header item
5225                * such that the header remains pressed. For example,
5226                * when focus is assigned to a push button, the mouse is
5227                * pressed (but not released), then the SPACE key is
5228                * pressed to activate the button, the capture changes,
5229                * the header not notified and NM_RELEASEDCAPTURE is not
5230                * sent. The fix is to redraw the header when the capture
5231                * changes to another control.
5232                *
5233                * This does not happen on XP.
5234                */

5235                if (OS.COMCTL32_MAJOR < 6) {
5236                    if (lParam != 0 && lParam != hwndHeader) {
5237                        OS.InvalidateRect (hwndHeader, null, true);
5238                    }
5239                }
5240                break;
5241            }
5242            case OS.WM_MOUSELEAVE: {
5243                /*
5244                * Bug in Windows. On XP, when a tooltip is hidden
5245                * due to a time out or mouse press, the tooltip
5246                * remains active although no longer visible and
5247                * won't show again until another tooltip becomes
5248                * active. The fix is to reset the tooltip bounds.
5249                */

5250                if (OS.COMCTL32_MAJOR >= 6) updateHeaderToolTips ();
5251                updateHeaderToolTips ();
5252                break;
5253            }
5254            case OS.WM_NOTIFY: {
5255                NMHDR hdr = new NMHDR ();
5256                OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
5257                switch (hdr.code) {
5258                    case OS.TTN_SHOW:
5259                    case OS.TTN_POP:
5260                    case OS.TTN_GETDISPINFOA:
5261                    case OS.TTN_GETDISPINFOW:
5262                        return OS.SendMessage (handle, msg, wParam, lParam);
5263                }
5264                break;
5265            }
5266            case OS.WM_SETCURSOR: {
5267                if (wParam == hwnd) {
5268                    int hitTest = (short) (lParam & 0xFFFF);
5269                    if (hitTest == OS.HTCLIENT) {
5270                        HDHITTESTINFO pinfo = new HDHITTESTINFO ();
5271                        int pos = OS.GetMessagePos ();
5272                        POINT pt = new POINT ();
5273                        pt.x = (short) (pos & 0xFFFF);
5274                        pt.y = (short) (pos >> 16);
5275                        OS.ScreenToClient (hwnd, pt);
5276                        pinfo.x = pt.x;
5277                        pinfo.y = pt.y;
5278                        int columnCount = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
5279                        int index = OS.SendMessage (hwndHeader, OS.HDM_HITTEST, 0, pinfo);
5280                        if (0 <= index && index < columnCount && !columns [index].resizable) {
5281                            if ((pinfo.flags & (OS.HHT_ONDIVIDER | OS.HHT_ONDIVOPEN)) != 0) {
5282                                OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
5283                                return 1;
5284                            }
5285                        }
5286                    }
5287                }
5288                break;
5289            }
5290        }
5291        return callWindowProc (hwnd, msg, wParam, lParam);
5292    }
5293    if (hwndParent != 0 && hwnd == hwndParent) {
5294        switch (msg) {
5295            case OS.WM_MOVE: {
5296                sendEvent (SWT.Move);
5297                return 0;
5298            }
5299            case OS.WM_SIZE: {
5300                setScrollWidth ();
5301                if (ignoreResize) return 0;
5302                setResizeChildren (false);
5303                int code = callWindowProc (hwnd, OS.WM_SIZE, wParam, lParam);
5304                sendEvent (SWT.Resize);
5305                if (isDisposed ()) return 0;
5306                if (layout != null) {
5307                    markLayout (false, false);
5308                    updateLayout (false, false);
5309                }
5310                setResizeChildren (true);
5311                updateScrollBar ();
5312                return code;
5313            }
5314            case OS.WM_NCPAINT: {
5315                LRESULT result = wmNCPaint (hwnd, wParam, lParam);
5316                if (result != null) return result.value;
5317                break;
5318            }
5319            case OS.WM_PRINT: {
5320                LRESULT result = wmPrint (hwnd, wParam, lParam);
5321                if (result != null) return result.value;
5322                break;
5323            }
5324            case OS.WM_COMMAND:
5325            case OS.WM_NOTIFY:
5326            case OS.WM_SYSCOLORCHANGE: {
5327                return OS.SendMessage (handle, msg, wParam, lParam);
5328            }
5329            case OS.WM_HSCROLL: {
5330                /*
5331                * Bug on WinCE. lParam should be NULL when the message is not sent
5332                * by a scroll bar control, but it contains the handle to the window.
5333                * When the message is sent by a scroll bar control, it correctly
5334                * contains the handle to the scroll bar. The fix is to check for
5335                * both.
5336                */

5337                if (horizontalBar != null && (lParam == 0 || lParam == hwndParent)) {
5338                    wmScroll (horizontalBar, true, hwndParent, OS.WM_HSCROLL, wParam, lParam);
5339                }
5340                setScrollWidth ();
5341                break;
5342            }
5343            case OS.WM_VSCROLL: {
5344                SCROLLINFO info = new SCROLLINFO ();
5345                info.cbSize = SCROLLINFO.sizeof;
5346                info.fMask = OS.SIF_ALL;
5347                OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5348                /*
5349                * Update the nPos field to match the nTrackPos field
5350                * so that the tree scrolls when the scroll bar of the
5351                * parent is dragged.
5352                *
5353                * NOTE: For some reason, this code is only necessary
5354                * on Windows Vista.
5355                */

5356                if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
5357                    if ((wParam & 0xFFFF) == OS.SB_THUMBTRACK) {
5358                        info.nPos = info.nTrackPos;
5359                    }
5360                }
5361                OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
5362                int code = OS.SendMessage (handle, OS.WM_VSCROLL, wParam, lParam);
5363                OS.GetScrollInfo (handle, OS.SB_VERT, info);
5364                OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5365                return code;
5366            }
5367        }
5368        return callWindowProc (hwnd, msg, wParam, lParam);
5369    }
5370    return super.windowProc (hwnd, msg, wParam, lParam);
5371}
5372
5373LRESULT WM_CHAR (int wParam, int lParam) {
5374    LRESULT result = super.WM_CHAR (wParam, lParam);
5375    if (result != null) return result;
5376    /*
5377    * Feature in Windows. The tree control beeps
5378    * in WM_CHAR when the search for the item that
5379    * matches the key stroke fails. This is the
5380    * standard tree behavior but is unexpected when
5381    * the key that was typed was ESC, CR or SPACE.
5382    * The fix is to avoid calling the tree window
5383    * proc in these cases.
5384    */

5385    switch (wParam) {
5386        case ' ': {
5387            int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5388            if (hItem != 0) {
5389                hAnchor = hItem;
5390                OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
5391                TVITEM tvItem = new TVITEM ();
5392                tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE | OS.TVIF_PARAM;
5393                tvItem.hItem = hItem;
5394                if ((style & SWT.CHECK) != 0) {
5395                    tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
5396                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5397                    int state = tvItem.state >> 12;
5398                    if ((state & 0x1) != 0) {
5399                        state++;
5400                    } else {
5401                        --state;
5402                    }
5403                    tvItem.state = state << 12;
5404                    OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5405                    if (!OS.IsWinCE) {
5406                        int id = hItem;
5407                        if (OS.COMCTL32_MAJOR >= 6) {
5408                            id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, hItem, 0);
5409                        }
5410                        OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, id);
5411                    }
5412                }
5413                tvItem.stateMask = OS.TVIS_SELECTED;
5414                OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5415                if ((style & SWT.MULTI) != 0 && OS.GetKeyState (OS.VK_CONTROL) < 0) {
5416                    if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
5417                        tvItem.state &= ~OS.TVIS_SELECTED;
5418                    } else {
5419                        tvItem.state |= OS.TVIS_SELECTED;
5420                    }
5421                } else {
5422                    tvItem.state |= OS.TVIS_SELECTED;
5423                }
5424                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5425                TreeItem item = _getItem (hItem, tvItem.lParam);
5426                Event event = new Event ();
5427                event.item = item;
5428                postEvent (SWT.Selection, event);
5429                if ((style & SWT.CHECK) != 0) {
5430                    event = new Event ();
5431                    event.item = item;
5432                    event.detail = SWT.CHECK;
5433                    postEvent (SWT.Selection, event);
5434                }
5435            }
5436            return LRESULT.ZERO;
5437        }
5438        case SWT.CR: {
5439            /*
5440            * Feature in Windows. Windows sends NM_RETURN from WM_KEYDOWN
5441            * instead of using WM_CHAR. This means that application code
5442            * that expects to consume the key press and therefore avoid a
5443            * SWT.DefaultSelection event from WM_CHAR will fail. The fix
5444            * is to implement SWT.DefaultSelection in WM_CHAR instead of
5445            * using NM_RETURN.
5446            */

5447            Event event = new Event ();
5448            int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5449            if (hItem != 0) event.item = _getItem (hItem);
5450            postEvent (SWT.DefaultSelection, event);
5451            return LRESULT.ZERO;
5452        }
5453        case SWT.ESC:
5454            return LRESULT.ZERO;
5455    }
5456    return result;
5457}
5458
5459LRESULT WM_ERASEBKGND (int wParam, int lParam) {
5460    LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
5461    if ((style & SWT.DOUBLE_BUFFERED) != 0) return LRESULT.ONE;
5462    if (findImageControl () != null) return LRESULT.ONE;
5463    return result;
5464}
5465
5466LRESULT WM_GETOBJECT (int wParam, int lParam) {
5467    /*
5468    * Ensure that there is an accessible object created for this
5469    * control because support for checked item and tree column
5470    * accessibility is temporarily implemented in the accessibility
5471    * package.
5472    */

5473    if ((style & SWT.CHECK) != 0 || hwndParent != 0) {
5474        if (accessible == null) accessible = new_Accessible (this);
5475    }
5476    return super.WM_GETOBJECT (wParam, lParam);
5477}
5478
5479LRESULT WM_KEYDOWN (int wParam, int lParam) {
5480    LRESULT result = super.WM_KEYDOWN (wParam, lParam);
5481    if (result != null) return result;
5482    switch (wParam) {
5483        case OS.VK_SPACE:
5484            /*
5485            * Ensure that the window proc does not process VK_SPACE
5486            * so that it can be handled in WM_CHAR. This allows the
5487            * application to cancel an operation that is normally
5488            * performed in WM_KEYDOWN from WM_CHAR.
5489            */

5490            return LRESULT.ZERO;
5491        case OS.VK_ADD:
5492            if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
5493                if (hwndHeader != 0) {
5494                    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
5495                    TreeColumn [] newColumns = new TreeColumn [count];
5496                    System.arraycopy (columns, 0, newColumns, 0, count);
5497                    for (int i=0; i<count; i++) {
5498                        TreeColumn column = newColumns [i];
5499                        if (!column.isDisposed () && column.getResizable ()) {
5500                            column.pack ();
5501                        }
5502                    }
5503                }
5504            }
5505            break;
5506        case OS.VK_UP:
5507        case OS.VK_DOWN:
5508        case OS.VK_PRIOR:
5509        case OS.VK_NEXT:
5510        case OS.VK_HOME:
5511        case OS.VK_END: {
5512            OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
5513            if ((style & SWT.SINGLE) != 0) break;
5514            if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
5515                int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5516                if (hItem != 0) {
5517                    if (hAnchor == 0) hAnchor = hItem;
5518                    ignoreSelect = ignoreDeselect = true;
5519                    int code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
5520                    ignoreSelect = ignoreDeselect = false;
5521                    int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5522                    TVITEM tvItem = new TVITEM ();
5523                    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5524                    tvItem.stateMask = OS.TVIS_SELECTED;
5525                    int hDeselectItem = hItem;
5526                    RECT rect1 = new RECT ();
5527                    rect1.left = hAnchor;
5528                    OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect1);
5529                    RECT rect2 = new RECT ();
5530                    rect2.left = hDeselectItem;
5531                    OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect2);
5532                    int flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
5533                    while (hDeselectItem != hAnchor) {
5534                        tvItem.hItem = hDeselectItem;
5535                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5536                        hDeselectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hDeselectItem);
5537                    }
5538                    int hSelectItem = hAnchor;
5539                    rect1.left = hNewItem;
5540                    OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect1);
5541                    rect2.left = hSelectItem;
5542                    OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect2);
5543                    tvItem.state = OS.TVIS_SELECTED;
5544                    flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
5545                    while (hSelectItem != hNewItem) {
5546                        tvItem.hItem = hSelectItem;
5547                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5548                        hSelectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hSelectItem);
5549                    }
5550                    tvItem.hItem = hNewItem;
5551                    OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5552                    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
5553                    tvItem.hItem = hNewItem;
5554                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5555                    Event event = new Event ();
5556                    event.item = _getItem (hNewItem, tvItem.lParam);
5557                    postEvent (SWT.Selection, event);
5558                    return new LRESULT (code);
5559                }
5560            }
5561            if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
5562                int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5563                if (hItem != 0) {
5564                    TVITEM tvItem = new TVITEM ();
5565                    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5566                    tvItem.stateMask = OS.TVIS_SELECTED;
5567                    tvItem.hItem = hItem;
5568                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5569                    boolean oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
5570                    int hNewItem = 0;
5571                    switch (wParam) {
5572                        case OS.VK_UP:
5573                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUSVISIBLE, hItem);
5574                            break;
5575                        case OS.VK_DOWN:
5576                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
5577                            break;
5578                        case OS.VK_HOME:
5579                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
5580                            break;
5581                        case OS.VK_PRIOR:
5582                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5583                            if (hNewItem == hItem) {
5584                                OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEUP, 0);
5585                                hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5586                            }
5587                            break;
5588                        case OS.VK_NEXT:
5589                            RECT rect = new RECT (), clientRect = new RECT ();
5590                            OS.GetClientRect (handle, clientRect);
5591                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5592                            do {
5593                                int hVisible = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNewItem);
5594                                if (hVisible == 0) break;
5595                                rect.left = hVisible;
5596                                OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect);
5597                                if (rect.bottom > clientRect.bottom) break;
5598                                if ((hNewItem = hVisible) == hItem) {
5599                                    OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEDOWN, 0);
5600                                }
5601                            } while (hNewItem != 0);
5602                            break;
5603                        case OS.VK_END:
5604                            hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
5605                            break;
5606                    }
5607                    if (hNewItem != 0) {
5608                        OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hNewItem);
5609                        tvItem.hItem = hNewItem;
5610                        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5611                        boolean newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
5612                        boolean redraw = !newSelected && drawCount == 0 && OS.IsWindowVisible (handle);
5613                        if (redraw) {
5614                            OS.UpdateWindow (handle);
5615                            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5616                        }
5617                        hSelect = hNewItem;
5618                        ignoreSelect = true;
5619                        OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
5620                        ignoreSelect = false;
5621                        hSelect = 0;
5622                        if (oldSelected) {
5623                            tvItem.state = OS.TVIS_SELECTED;
5624                            tvItem.hItem = hItem;
5625                            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5626                        }
5627                        if (!newSelected) {
5628                            tvItem.state = 0;
5629                            tvItem.hItem = hNewItem;
5630                            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5631                        }
5632                        if (redraw) {
5633                            RECT rect1 = new RECT (), rect2 = new RECT ();
5634                            rect1.left = hItem; rect2.left = hNewItem;
5635                            int fItemRect = (style & SWT.FULL_SELECTION) != 0 ? 0 : 1;
5636                            if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) fItemRect = 0;
5637                            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) fItemRect = 0;
5638                            OS.SendMessage (handle, OS.TVM_GETITEMRECT, fItemRect, rect1);
5639                            OS.SendMessage (handle, OS.TVM_GETITEMRECT, fItemRect, rect2);
5640                            OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5641                            OS.InvalidateRect (handle, rect1, true);
5642                            OS.InvalidateRect (handle, rect2, true);
5643                            OS.UpdateWindow (handle);
5644                        }
5645                        return LRESULT.ZERO;
5646                    }
5647                }
5648            }
5649            int code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
5650            hAnchor = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5651            return new LRESULT (code);
5652        }
5653    }
5654    return result;
5655}
5656
5657LRESULT WM_KILLFOCUS (int wParam, int lParam) {
5658    /*
5659    * Bug in Windows. When a tree item that has an image
5660    * with alpha is expanded or collapsed, the area where
5661    * the image is drawn is not erased before it is drawn.
5662    * This means that the image gets darker each time.
5663    * The fix is to redraw the selection.
5664    *
5665    * Feature in Windows. When multiple item have
5666    * the TVIS_SELECTED state, Windows redraws only
5667    * the focused item in the color used to show the
5668    * selection when the tree loses or gains focus.
5669    * The fix is to force Windows to redraw the
5670    * selection when focus is gained or lost.
5671    */

5672    boolean redraw = (style & SWT.MULTI) != 0;
5673    if (!redraw) {
5674        if (!OS.IsWinCE && OS.COMCTL32_MAJOR >= 6) {
5675            if (imageList != null) {
5676                int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
5677                if ((bits & OS.TVS_FULLROWSELECT) == 0) {
5678                    redraw = true;
5679                }
5680            }
5681        }
5682    }
5683    if (redraw) redrawSelection ();
5684    return super.WM_KILLFOCUS (wParam, lParam);
5685}
5686
5687LRESULT WM_LBUTTONDBLCLK (int wParam, int lParam) {
5688    TVHITTESTINFO lpht = new TVHITTESTINFO ();
5689    lpht.x = (short) (lParam & 0xFFFF);
5690    lpht.y = (short) (lParam >> 16);
5691    OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
5692    if (lpht.hItem != 0) {
5693        if ((style & SWT.CHECK) != 0) {
5694            if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
5695                Display display = this.display;
5696                display.captureChanged = false;
5697                sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
5698                if (!sendMouseEvent (SWT.MouseDoubleClick, 1, handle, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
5699                    if (!display.captureChanged && !isDisposed ()) {
5700                        if (OS.GetCapture () != handle) OS.SetCapture (handle);
5701                    }
5702                    return LRESULT.ZERO;
5703                }
5704                if (!display.captureChanged && !isDisposed ()) {
5705                    if (OS.GetCapture () != handle) OS.SetCapture (handle);
5706                }
5707                OS.SetFocus (handle);
5708                TVITEM tvItem = new TVITEM ();
5709                tvItem.hItem = lpht.hItem;
5710                tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
5711                tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
5712                OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5713                int state = tvItem.state >> 12;
5714                if ((state & 0x1) != 0) {
5715                    state++;
5716                } else {
5717                    --state;
5718                }
5719                tvItem.state = state << 12;
5720                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5721                if (!OS.IsWinCE) {
5722                    int id = tvItem.hItem;
5723                    if (OS.COMCTL32_MAJOR >= 6) {
5724                        id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
5725                    }
5726                    OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, id);
5727                }
5728                Event event = new Event ();
5729                event.item = _getItem (tvItem.hItem, tvItem.lParam);
5730                event.detail = SWT.CHECK;
5731                postEvent (SWT.Selection, event);
5732                return LRESULT.ZERO;
5733            }
5734        }
5735    }
5736    LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
5737    if (result == LRESULT.ZERO) return result;
5738    if (lpht.hItem != 0) {
5739        if ((style & SWT.FULL_SELECTION) != 0 || (lpht.flags & OS.TVHT_ONITEM) != 0) {
5740            Event event = new Event ();
5741            event.item = _getItem (lpht.hItem);
5742            postEvent (SWT.DefaultSelection, event);
5743        }
5744    }
5745    return result;
5746}
5747
5748LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
5749    /*
5750    * In a multi-select tree, if the user is collapsing a subtree that
5751    * contains selected items, clear the selection from these items and
5752    * issue a selection event. Only items that are selected and visible
5753    * are cleared. This code also runs in the case when the white space
5754    * below the last item is selected.
5755    */

5756    TVHITTESTINFO lpht = new TVHITTESTINFO ();
5757    lpht.x = (short) (lParam & 0xFFFF);
5758    lpht.y = (short) (lParam >> 16);
5759    OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
5760    if (lpht.hItem == 0 || (lpht.flags & OS.TVHT_ONITEMBUTTON) != 0) {
5761        Display display = this.display;
5762        display.captureChanged = false;
5763        if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
5764            if (!display.captureChanged && !isDisposed ()) {
5765                if (OS.GetCapture () != handle) OS.SetCapture (handle);
5766            }
5767            return LRESULT.ZERO;
5768        }
5769        boolean fixSelection = false, deselected = false;
5770        if (lpht.hItem != 0 && (style & SWT.MULTI) != 0) {
5771            int hSelection = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5772            if (hSelection != 0) {
5773                TVITEM tvItem = new TVITEM ();
5774                tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5775                tvItem.hItem = lpht.hItem;
5776                OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5777                if ((tvItem.state & OS.TVIS_EXPANDED) != 0) {
5778                    fixSelection = true;
5779                    tvItem.stateMask = OS.TVIS_SELECTED;
5780                    int hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, lpht.hItem);
5781                    while (hNext != 0) {
5782                        tvItem.hItem = hNext;
5783                        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5784                        if ((tvItem.state & OS.TVIS_SELECTED) != 0) deselected = true;
5785                        tvItem.state = 0;
5786                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5787                        int hItem = hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNext);
5788                        while (hItem != 0 && hItem != lpht.hItem) {
5789                            hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
5790                        }
5791                        if (hItem == 0) break;
5792                    }
5793                }
5794            }
5795        }
5796        dragStarted = gestureCompleted = false;
5797        if (fixSelection) ignoreDeselect = ignoreSelect = lockSelection = true;
5798        int code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
5799        if (fixSelection) ignoreDeselect = ignoreSelect = lockSelection = false;
5800        if (dragStarted) {
5801            if (!display.captureChanged && !isDisposed ()) {
5802                if (OS.GetCapture () != handle) OS.SetCapture (handle);
5803            }
5804        }
5805        if (deselected) {
5806            Event event = new Event ();
5807            event.item = _getItem (lpht.hItem);
5808            postEvent (SWT.Selection, event);
5809        }
5810        return new LRESULT (code);
5811    }
5812    
5813    /* Look for check/uncheck */
5814    if ((style & SWT.CHECK) != 0) {
5815        if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
5816            Display display = this.display;
5817            display.captureChanged = false;
5818            if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
5819                if (!display.captureChanged && !isDisposed ()) {
5820                    if (OS.GetCapture () != handle) OS.SetCapture (handle);
5821                }
5822                return LRESULT.ZERO;
5823            }
5824            if (!display.captureChanged && !isDisposed ()) {
5825                if (OS.GetCapture () != handle) OS.SetCapture (handle);
5826            }
5827            OS.SetFocus (handle);
5828            TVITEM tvItem = new TVITEM ();
5829            tvItem.hItem = lpht.hItem;
5830            tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
5831            tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
5832            OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5833            int state = tvItem.state >> 12;
5834            if ((state & 0x1) != 0) {
5835                state++;
5836            } else {
5837                --state;
5838            }
5839            tvItem.state = state << 12;
5840            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5841            if (!OS.IsWinCE) {
5842                int id = tvItem.hItem;
5843                if (OS.COMCTL32_MAJOR >= 6) {
5844                    id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
5845                }
5846                OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, id);
5847            }
5848            Event event = new Event ();
5849            event.item = _getItem (tvItem.hItem, tvItem.lParam);
5850            event.detail = SWT.CHECK;
5851            postEvent (SWT.Selection, event);
5852            return LRESULT.ZERO;
5853        }
5854    }
5855    
5856    /* Process the mouse when an item is not selected */
5857    if ((style & SWT.FULL_SELECTION) == 0) {
5858        if ((lpht.flags & OS.TVHT_ONITEM) == 0) {
5859            Display display = this.display;
5860            display.captureChanged = false;
5861            if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
5862                if (!display.captureChanged && !isDisposed ()) {
5863                    if (OS.GetCapture () != handle) OS.SetCapture (handle);
5864                }
5865                return LRESULT.ZERO;
5866            }
5867            int code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
5868            if (!display.captureChanged && !isDisposed ()) {
5869                if (OS.GetCapture () != handle) OS.SetCapture (handle);
5870            }
5871            return new LRESULT (code);
5872        }
5873    }
5874
5875    /* Get the selected state of the item under the mouse */
5876    TVITEM tvItem = new TVITEM ();
5877    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5878    tvItem.stateMask = OS.TVIS_SELECTED;
5879    boolean hittestSelected = false, focused = false;
5880    if ((style & SWT.MULTI) != 0) {
5881        tvItem.hItem = lpht.hItem;
5882        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5883        hittestSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
5884        focused = OS.GetFocus () == handle;
5885    }
5886    
5887    /* Get the selected state of the last selected item */
5888    boolean redraw = false;
5889    int hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5890    if ((style & SWT.MULTI) != 0) {
5891        tvItem.hItem = hOldItem;
5892        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5893
5894        /* Check for CONTROL or drag selection */
5895        if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
5896            /*
5897            * Feature in Windows. When the tree is not drawing focus
5898            * and the user selects a tree item using while the CONTROL
5899            * key is down, the tree window proc sends WM_UPDATEUISTATE
5900            * to the top level window, causing controls within the shell
5901            * to redraw. When drag detect is enabled, the tree window
5902            * proc runs a modal loop that allows WM_PAINT messages to be
5903            * delivered during WM_LBUTTONDOWN. When WM_SETREDRAW is used
5904            * to disable drawing for the tree and a WM_PAINT happens for
5905            * a parent of the tree (or a sibling that overlaps), the parent
5906            * will draw on top of the tree. If WM_SETREDRAW is turned back
5907            * on without redrawing the entire tree, pixel corruption occurs.
5908            * This case only seems to happen when the tree has been given
5909            * focus from WM_MOUSEACTIVATE of the shell. The fix is to
5910            * detect that WM_UPDATEUISTATE will be sent and avoid using
5911            * WM_SETREDRAW to disable drawing.
5912            *
5913            * NOTE: Any redraw of a parent (or sibling) will be dispatched
5914            * during the modal drag detect loop. This code only fixes the
5915            * case where the tree causes a redraw from WM_UPDATEUISTATE.
5916            * In SWT, the InvalidateRect() that causes the pixel corruption
5917            * is found in Composite.WM_UPDATEUISTATE().
5918            */

5919            int uiState = OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
5920            if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
5921                redraw = focused && drawCount == 0 && OS.IsWindowVisible (handle);
5922            }
5923            if (redraw) {
5924                OS.UpdateWindow (handle);
5925                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5926            }
5927        } else {
5928            deselectAll ();
5929        }
5930    }
5931
5932    /* Do the selection */
5933    Display display = this.display;
5934    display.captureChanged = false;
5935    if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
5936        if (!display.captureChanged && !isDisposed ()) {
5937            if (OS.GetCapture () != handle) OS.SetCapture (handle);
5938        }
5939        return LRESULT.ZERO;
5940    }
5941    hSelect = lpht.hItem;
5942    dragStarted = gestureCompleted = false;
5943    ignoreDeselect = ignoreSelect = true;
5944    int code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
5945    int hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5946    /*
5947    * Feature in Windows. When the tree has the style
5948    * TVS_FULLROWSELECT, the background color for the
5949    * entire row is filled when an item is painted,
5950    * drawing on top of any custom drawing. The fix
5951    * is to emulate TVS_FULLROWSELECT.
5952    */

5953    if ((style & SWT.FULL_SELECTION) != 0) {
5954        int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
5955        if ((bits & OS.TVS_FULLROWSELECT) == 0) {
5956            if (hNewItem == hOldItem && lpht.hItem != hOldItem) {
5957                OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
5958                hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5959            }
5960            if (!dragStarted && lpht.hItem != 0 && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
5961                dragStarted = dragDetect (handle, lpht.x, lpht.y, false, null, null);
5962            }
5963        }
5964    }
5965    ignoreDeselect = ignoreSelect = false;
5966    hSelect = 0;
5967    if (dragStarted) {
5968        if (!display.captureChanged && !isDisposed ()) {
5969            if (OS.GetCapture () != handle) OS.SetCapture (handle);
5970        }
5971    }
5972
5973    /*
5974    * Feature in Windows. When the old and new focused item
5975    * are the same, Windows does not check to make sure that
5976    * the item is actually selected, not just focused. The
5977    * fix is to force the item to draw selected by setting
5978    * the state mask. This is only necessary when the tree
5979    * is single select.
5980    */

5981    if ((style & SWT.SINGLE) != 0) {
5982        if (hOldItem == hNewItem) {
5983            tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5984            tvItem.state = OS.TVIS_SELECTED;
5985            tvItem.stateMask = OS.TVIS_SELECTED;
5986            tvItem.hItem = hNewItem;
5987            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5988        }
5989    }
5990    
5991    /* Reselect the last item that was unselected */
5992    if ((style & SWT.MULTI) != 0) {
5993        
5994        /* Check for CONTROL and reselect the last item */
5995        if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
5996            if (hOldItem == hNewItem && hOldItem == lpht.hItem) {
5997                if ((wParam & OS.MK_CONTROL) != 0) {
5998                    tvItem.state ^= OS.TVIS_SELECTED;
5999                    if (dragStarted) tvItem.state = OS.TVIS_SELECTED;
6000                    OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6001                }
6002            } else {
6003                if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
6004                    tvItem.state = OS.TVIS_SELECTED;
6005                    OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6006                }
6007                if ((wParam & OS.MK_CONTROL) != 0 && !dragStarted) {
6008                    if (hittestSelected) {
6009                        tvItem.state = 0;
6010                        tvItem.hItem = lpht.hItem;
6011                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6012                    }
6013                }
6014            }
6015            if (redraw) {
6016                RECT rect1 = new RECT (), rect2 = new RECT ();
6017                rect1.left = hOldItem; rect2.left = hNewItem;
6018                int fItemRect = (style & SWT.FULL_SELECTION) != 0 ? 0 : 1;
6019                if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) fItemRect = 0;
6020                if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) fItemRect = 0;
6021                OS.SendMessage (handle, OS.TVM_GETITEMRECT, fItemRect, rect1);
6022                OS.SendMessage (handle, OS.TVM_GETITEMRECT, fItemRect, rect2);
6023                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
6024                OS.InvalidateRect (handle, rect1, true);
6025                OS.InvalidateRect (handle, rect2, true);
6026                OS.UpdateWindow (handle);
6027            }
6028        }
6029
6030        /* Check for SHIFT or normal select and deselect/reselect items */
6031        if ((wParam & OS.MK_CONTROL) == 0) {
6032            if (!hittestSelected || !dragStarted) {
6033                tvItem.state = 0;
6034                int oldProc = OS.GetWindowLong (handle, OS.GWL_WNDPROC);
6035                OS.SetWindowLong (handle, OS.GWL_WNDPROC, TreeProc);
6036                if ((style & SWT.VIRTUAL) != 0) {
6037                    int hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
6038                    deselect (hItem, tvItem, hNewItem);
6039                } else {
6040                    for (int i=0; i<items.length; i++) {
6041                        TreeItem item = items [i];
6042                        if (item != null && item.handle != hNewItem) {
6043                            tvItem.hItem = item.handle;
6044                            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6045                        }
6046                    }
6047                }
6048                tvItem.hItem = hNewItem;
6049                tvItem.state = OS.TVIS_SELECTED;
6050                OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6051                OS.SetWindowLong (handle, OS.GWL_WNDPROC, oldProc);
6052                if ((wParam & OS.MK_SHIFT) != 0) {
6053                    RECT rect1 = new RECT ();
6054                    if (hAnchor == 0) hAnchor = hNewItem;
6055                    rect1.left = hAnchor;
6056                    if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect1) != 0) {
6057                        RECT rect2 = new RECT ();
6058                        rect2.left = hNewItem;
6059                        OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect2);
6060                        int flags = rect1.top < rect2.top ? OS.TVGN_NEXTVISIBLE : OS.TVGN_PREVIOUSVISIBLE;
6061                        tvItem.state = OS.TVIS_SELECTED;
6062                        int hItem = tvItem.hItem = hAnchor;
6063                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6064                        while (hItem != hNewItem) {
6065                            tvItem.hItem = hItem;
6066                            OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6067                            hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hItem);
6068                        }
6069                    }
6070                }
6071            }
6072        }
6073    }
6074    if ((wParam & OS.MK_SHIFT) == 0) hAnchor = hNewItem;
6075            
6076    /* Issue notification */
6077    if (!gestureCompleted) {
6078        tvItem.hItem = hNewItem;
6079        tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6080        OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6081        Event event = new Event ();
6082        event.item = _getItem (tvItem.hItem, tvItem.lParam);
6083        postEvent (SWT.Selection, event);
6084    }
6085    gestureCompleted = false;
6086    
6087    /*
6088    * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
6089    * the widget starts a modal loop to determine if the user wants
6090    * to begin a drag/drop operation or marquee select. Unfortunately,
6091    * this modal loop eats the corresponding mouse up. The fix is to
6092    * detect the cases when the modal loop has eaten the mouse up and
6093    * issue a fake mouse up.
6094    */

6095    if (dragStarted) {
6096        sendDragEvent (1, (short) (lParam & 0xFFFF), (short) (lParam >> 16));
6097    } else {
6098        int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6099        if ((bits & OS.TVS_DISABLEDRAGDROP) == 0) {
6100            sendMouseEvent (SWT.MouseUp, 1, handle, OS.WM_LBUTTONUP, wParam, lParam);
6101        }
6102    }
6103    dragStarted = false;
6104    return new LRESULT (code);
6105}
6106
6107LRESULT WM_MOUSEMOVE (int wParam, int lParam) {
6108    Display display = this.display;
6109    LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
6110    if (result != null) return result;
6111    if (itemToolTipHandle != 0 && hwndHeader != 0) {
6112        /*
6113        * Bug in Windows. On some machines that do not have XBUTTONs,
6114        * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
6115        * causing mouse capture to become stuck. The fix is to test
6116        * for the extra buttons only when they exist.
6117        */

6118        int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
6119        if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
6120        if (((wParam & 0xFFFF) & mask) == 0) {
6121            TVHITTESTINFO lpht = new TVHITTESTINFO ();
6122            lpht.x = (short) (lParam & 0xFFFF);
6123            lpht.y = (short) (lParam >> 16);
6124            OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6125            if (lpht.hItem != 0) {
6126                int hDC = OS.GetDC (handle);
6127                int oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
6128                if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
6129                POINT pt = new POINT();
6130                pt.x = lpht.x;
6131                pt.y = lpht.y;
6132                RECT rect = new RECT ();
6133                OS.GetClientRect (hwndParent, rect);
6134                OS.MapWindowPoints (hwndParent, handle, rect, 2);
6135                TreeItem item = _getItem (lpht.hItem);
6136                int index = 0, count = Math.max (1, OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0));
6137                int [] order = new int [count];
6138                OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
6139                while (index < count) {
6140                    int hFont = item.cellFont != null ? item.cellFont [order [index]] : -1;
6141                    if (hFont == -1) hFont = item.font;
6142                    if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
6143                    RECT cellRect = item.getBounds (order [index], true, false, true, false, true, hDC);
6144                    if (hFont != -1) OS.SelectObject (hDC, hFont);
6145                    if (cellRect.left > rect.right) break;
6146                    cellRect.right = Math.min (cellRect.right, rect.right);
6147                    if (OS.PtInRect (cellRect, pt)) {
6148                        RECT textRect = item.getBounds (order [index], true, false, false, false, false, hDC);
6149                        if (textRect.right > cellRect.right) {
6150                            TOOLINFO lpti = new TOOLINFO ();
6151                            lpti.cbSize = TOOLINFO.sizeof;
6152                            lpti.hwnd = handle;
6153                            lpti.uId = handle;
6154                            lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
6155                            lpti.left = cellRect.left;
6156                            lpti.top = cellRect.top;
6157                            lpti.right = cellRect.right;
6158                            lpti.bottom = cellRect.bottom;
6159                            OS.SendMessage (itemToolTipHandle, OS.TTM_NEWTOOLRECT, 0, lpti);
6160                        }
6161                        break;
6162                    }
6163                    index++;
6164                }
6165                if (newFont != 0) OS.SelectObject (hDC, oldFont);
6166                OS.ReleaseDC (handle, hDC);
6167            }
6168        }
6169    }
6170    return result;
6171}
6172
6173LRESULT WM_MOVE (int wParam, int lParam) {
6174    if (ignoreResize) return null;
6175    return super.WM_MOVE (wParam, lParam);
6176}
6177
6178LRESULT WM_RBUTTONDOWN (int wParam, int lParam) {
6179    /*
6180    * Feature in Windows. The receiver uses WM_RBUTTONDOWN
6181    * to initiate a drag/drop operation depending on how the
6182    * user moves the mouse. If the user clicks the right button,
6183    * without moving the mouse, the tree consumes the corresponding
6184    * WM_RBUTTONUP. The fix is to avoid calling the window proc for
6185    * the tree.
6186    */

6187    Display display = this.display;
6188    display.captureChanged = false;
6189    if (!sendMouseEvent (SWT.MouseDown, 3, handle, OS.WM_RBUTTONDOWN, wParam, lParam)) {
6190        if (!display.captureChanged && !isDisposed ()) {
6191            if (OS.GetCapture () != handle) OS.SetCapture (handle);
6192        }
6193        return LRESULT.ZERO;
6194    }
6195    /*
6196    * This code is intentionally commented.
6197    */

6198// if (OS.GetCapture () != handle) OS.SetCapture (handle);
6199
setFocus ();
6200    
6201    /*
6202    * Feature in Windows. When the user selects a tree item
6203    * with the right mouse button, the item remains selected
6204    * only as long as the user does not release or move the
6205    * mouse. As soon as this happens, the selection snaps
6206    * back to the previous selection. This behavior can be
6207    * observed in the Explorer but is not instantly apparent
6208    * because the Explorer explicitly sets the selection when
6209    * the user chooses a menu item. If the user cancels the
6210    * menu, the selection snaps back. The fix is to avoid
6211    * calling the window proc and do the selection ourselves.
6212    * This behavior is consistent with the table.
6213    */

6214    TVHITTESTINFO lpht = new TVHITTESTINFO ();
6215    lpht.x = (short) (lParam & 0xFFFF);
6216    lpht.y = (short) (lParam >> 16);
6217    OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6218    if (lpht.hItem != 0) {
6219        int flags = OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
6220        if ((style & SWT.FULL_SELECTION) != 0 || (lpht.flags & flags) != 0) {
6221            if ((wParam & (OS.MK_CONTROL | OS.MK_SHIFT)) == 0) {
6222                TVITEM tvItem = new TVITEM ();
6223                tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6224                tvItem.stateMask = OS.TVIS_SELECTED;
6225                tvItem.hItem = lpht.hItem;
6226                OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6227                if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
6228                    ignoreSelect = true;
6229                    OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, 0);
6230                    ignoreSelect = false;
6231                    OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
6232                }
6233            }
6234        }
6235    }
6236    return LRESULT.ZERO;
6237}
6238
6239LRESULT WM_PAINT (int wParam, int lParam) {
6240    if (shrink && !ignoreShrink) {
6241        /* Resize the item array to fit the last item */
6242        int count = items.length - 1;
6243        while (count >= 0) {
6244            if (items [count] != null) break;
6245            --count;
6246        }
6247        count++;
6248        if (items.length > 4 && items.length - count > 3) {
6249            int length = Math.max (4, (count + 3) / 4 * 4);
6250            TreeItem [] newItems = new TreeItem [length];
6251            System.arraycopy (items, 0, newItems, 0, count);
6252            items = newItems;
6253        }
6254        shrink = false;
6255    }
6256    if ((style & SWT.DOUBLE_BUFFERED) != 0 || findImageControl () != null) {
6257        boolean doubleBuffer = true;
6258        if (EXPLORER_THEME) {
6259            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
6260                int exStyle = OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
6261                if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) doubleBuffer = false;
6262            }
6263        }
6264        if (doubleBuffer) {
6265            GC gc = null;
6266            int paintDC = 0;
6267            PAINTSTRUCT ps = new PAINTSTRUCT ();
6268            boolean hooksPaint = hooks (SWT.Paint);
6269            if (hooksPaint) {
6270                GCData data = new GCData ();
6271                data.ps = ps;
6272                data.hwnd = handle;
6273                gc = GC.win32_new (this, data);
6274                paintDC = gc.handle;
6275            } else {
6276                paintDC = OS.BeginPaint (handle, ps);
6277            }
6278            int width = ps.right - ps.left;
6279            int height = ps.bottom - ps.top;
6280            if (width != 0 && height != 0) {
6281                int hDC = OS.CreateCompatibleDC (paintDC);
6282                POINT lpPoint1 = new POINT (), lpPoint2 = new POINT ();
6283                OS.SetWindowOrgEx (hDC, ps.left, ps.top, lpPoint1);
6284                OS.SetBrushOrgEx (hDC, ps.left, ps.top, lpPoint2);
6285                int hBitmap = OS.CreateCompatibleBitmap (paintDC, width, height);
6286                int hOldBitmap = OS.SelectObject (hDC, hBitmap);
6287                RECT rect = new RECT ();
6288                OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
6289                drawBackground (hDC, rect);
6290                callWindowProc (handle, OS.WM_PAINT, hDC, 0);
6291                OS.SetWindowOrgEx (hDC, lpPoint1.x, lpPoint1.y, null);
6292                OS.SetBrushOrgEx (hDC, lpPoint2.x, lpPoint2.y, null);
6293                OS.BitBlt (paintDC, ps.left, ps.top, width, height, hDC, 0, 0, OS.SRCCOPY);
6294                OS.SelectObject (hDC, hOldBitmap);
6295                OS.DeleteObject (hBitmap);
6296                OS.DeleteObject (hDC);
6297                if (hooksPaint) {
6298                    Event event = new Event ();
6299                    event.gc = gc;
6300                    event.x = ps.left;
6301                    event.y = ps.top;
6302                    event.width = ps.right - ps.left;
6303                    event.height = ps.bottom - ps.top;
6304                    sendEvent (SWT.Paint, event);
6305                    // widget could be disposed at this point
6306
event.gc = null;
6307                }
6308            }
6309            if (hooksPaint) {
6310                gc.dispose ();
6311            } else {
6312                OS.EndPaint (handle, ps);
6313            }
6314            return LRESULT.ZERO;
6315        }
6316    }
6317    return super.WM_PAINT (wParam, lParam);
6318}
6319
6320LRESULT WM_PRINTCLIENT (int wParam, int lParam) {
6321    LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
6322    if (result != null) return result;
6323    /*
6324    * Feature in Windows. For some reason, when WM_PRINT is used
6325    * to capture an image of a hierarchy that contains a tree with
6326    * columns, the clipping that is used to stop the first column
6327    * from drawing on top of subsequent columns stops the first
6328    * column and the tree lines from drawing. This does not happen
6329    * during WM_PAINT. The fix is to draw without clipping and
6330    * then draw the rest of the columns on top. Since the drawing
6331    * is happening in WM_PRINTCLIENT, the redrawing is not visible.
6332    */

6333    printClient = true;
6334    int code = callWindowProc (handle, OS.WM_PRINTCLIENT, wParam, lParam);
6335    printClient = false;
6336    return new LRESULT (code);
6337}
6338
6339LRESULT WM_SETFOCUS (int wParam, int lParam) {
6340    /*
6341    * Bug in Windows. When a tree item that has an image
6342    * with alpha is expanded or collapsed, the area where
6343    * the image is drawn is not erased before it is drawn.
6344    * This means that the image gets darker each time.
6345    * The fix is to redraw the selection.
6346    *
6347    * Feature in Windows. When multiple item have
6348    * the TVIS_SELECTED state, Windows redraws only
6349    * the focused item in the color used to show the
6350    * selection when the tree loses or gains focus.
6351    * The fix is to force Windows to redraw the
6352    * selection when focus is gained or lost.
6353    */

6354    boolean redraw = (style & SWT.MULTI) != 0;
6355    if (!redraw) {
6356        if (!OS.IsWinCE && OS.COMCTL32_MAJOR >= 6) {
6357            if (imageList != null) {
6358                int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6359                if ((bits & OS.TVS_FULLROWSELECT) == 0) {
6360                    redraw = true;
6361                }
6362            }
6363        }
6364    }
6365    if (redraw) redrawSelection ();
6366    return super.WM_SETFOCUS (wParam, lParam);
6367}
6368
6369LRESULT WM_SETFONT (int wParam, int lParam) {
6370    LRESULT result = super.WM_SETFONT (wParam, lParam);
6371    if (result != null) return result;
6372    if (hwndHeader != 0) {
6373        /*
6374        * Bug in Windows. When a header has a sort indicator
6375        * triangle, Windows resizes the indicator based on the
6376        * size of the n-1th font. The fix is to always make
6377        * the n-1th font be the default. This makes the sort
6378        * indicator always be the default size.
6379        */

6380        OS.SendMessage (hwndHeader, OS.WM_SETFONT, 0, lParam);
6381        OS.SendMessage (hwndHeader, OS.WM_SETFONT, wParam, lParam);
6382    }
6383    if (itemToolTipHandle != 0) {
6384        OS.SendMessage (itemToolTipHandle, OS.WM_SETFONT, wParam, lParam);
6385    }
6386    if (headerToolTipHandle != 0) {
6387        OS.SendMessage (headerToolTipHandle, OS.WM_SETFONT, wParam, lParam);
6388    }
6389    return result;
6390}
6391
6392LRESULT WM_SETREDRAW (int wParam, int lParam) {
6393    LRESULT result = super.WM_SETREDRAW (wParam, lParam);
6394    if (result != null) return result;
6395    /*
6396    * Bug in Windows. Under certain circumstances, when
6397    * WM_SETREDRAW is used to turn off drawing and then
6398    * TVM_GETITEMRECT is sent to get the bounds of an item
6399    * that is not inside the client area, Windows segment
6400    * faults. The fix is to call the default window proc
6401    * rather than the default tree proc.
6402    *
6403    * NOTE: This problem is intermittent and happens on
6404    * Windows Vista running under the theme manager.
6405    */

6406    if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
6407        int code = OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
6408        return code == 0 ? LRESULT.ZERO : new LRESULT (code);
6409    }
6410    return result;
6411}
6412
6413LRESULT WM_SIZE (int wParam, int lParam) {
6414    /*
6415    * Bug in Windows. When TVS_NOHSCROLL is set when the
6416    * size of the tree is zero, the scroll bar is shown the
6417    * next time the tree resizes. The fix is to hide the
6418    * scroll bar every time the tree is resized.
6419    */

6420    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6421    if ((bits & OS.TVS_NOHSCROLL) != 0) {
6422        if (!OS.IsWinCE) OS.ShowScrollBar (handle, OS.SB_HORZ, false);
6423    }
6424    /*
6425    * Bug in Windows. On Vista, when the Explorer theme
6426    * is used with a full selection tree, when the tree
6427    * is resized to be smaller, the rounded right edge
6428    * of the selected items is not drawn. The fix is the
6429    * redraw the entire tree.
6430    */

6431    if (EXPLORER_THEME) {
6432        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
6433            if ((style & SWT.FULL_SELECTION) != 0) {
6434                OS.InvalidateRect (handle, null, false);
6435            }
6436        }
6437    }
6438    if (ignoreResize) return null;
6439    return super.WM_SIZE (wParam, lParam);
6440}
6441
6442LRESULT WM_SYSCOLORCHANGE (int wParam, int lParam) {
6443    LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
6444    if (result != null) return result;
6445    /*
6446    * Bug in Windows. When the tree is using the explorer
6447    * theme, it does not use COLOR_WINDOW_TEXT for the
6448    * default foreground color. The fix is to explicitly
6449    * set the foreground.
6450    */

6451    if (explorerTheme) {
6452        if (foreground == -1) setForegroundPixel (-1);
6453    }
6454    if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
6455    return result;
6456}
6457
6458LRESULT wmColorChild (int wParam, int lParam) {
6459    if (findImageControl () != null) {
6460        if (OS.COMCTL32_MAJOR < 6) {
6461            return super.wmColorChild (wParam, lParam);
6462        }
6463        return new LRESULT (OS.GetStockObject (OS.NULL_BRUSH));
6464    }
6465    /*
6466    * Feature in Windows. Tree controls send WM_CTLCOLOREDIT
6467    * to allow application code to change the default colors.
6468    * This is undocumented and conflicts with TVM_SETTEXTCOLOR
6469    * and TVM_SETBKCOLOR, the documented way to do this. The
6470    * fix is to ignore WM_CTLCOLOREDIT messages from trees.
6471    */

6472    return null;
6473}
6474
6475LRESULT wmNotify (NMHDR hdr, int wParam, int lParam) {
6476    if (hdr.hwndFrom == itemToolTipHandle && hwndHeader != 0) {
6477        if (!OS.IsWinCE) {
6478            switch (hdr.code) {
6479                case OS.TTN_POP: {
6480                    if (display.isXMouseActive ()) {
6481                        Shell shell = getShell ();
6482                        shell.lockToolTipControl = null;
6483                    }
6484                    break;
6485                }
6486                case OS.TTN_SHOW: {
6487                    if (display.isXMouseActive ()) {
6488                        Shell shell = getShell ();
6489                        shell.lockToolTipControl = this;
6490                    }
6491                    int pos = OS.GetMessagePos ();
6492                    POINT pt = new POINT();
6493                    pt.x = (short) (pos & 0xFFFF);
6494                    pt.y = (short) (pos >> 16);
6495                    OS.ScreenToClient (handle, pt);
6496                    TVHITTESTINFO lpht = new TVHITTESTINFO ();
6497                    lpht.x = pt.x;
6498                    lpht.y = pt.y;
6499                    OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6500                    if (lpht.hItem != 0) {
6501                        int hDC = OS.GetDC (handle);
6502                        int oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
6503                        if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
6504                        LRESULT result = null;
6505                        RECT rect = new RECT ();
6506                        OS.GetClientRect (hwndParent, rect);
6507                        OS.MapWindowPoints (hwndParent, handle, rect, 2);
6508                        TreeItem item = _getItem (lpht.hItem);
6509                        int index = 0, count = Math.max (1, OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0));
6510                        int [] order = new int [count];
6511                        OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
6512                        while (index < count) {
6513                            int hFont = item.cellFont != null ? item.cellFont [order [index]] : -1;
6514                            if (hFont == -1) hFont = item.font;
6515                            if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
6516                            RECT cellRect = item.getBounds (order [index], true, false, true, false, true, hDC);
6517                            if (hFont != -1) OS.SelectObject (hDC, hFont);
6518                            if (cellRect.left > rect.right) break;
6519                            cellRect.right = Math.min (cellRect.right, rect.right);
6520                            if (OS.PtInRect (cellRect, pt)) {
6521                                RECT textRect = item.getBounds (order [index], true, false, false, false, false, hDC);
6522                                if (textRect.right > cellRect.right) {
6523                                    OS.MapWindowPoints (handle, 0, textRect, 2);
6524                                    int flags = OS.SWP_NOACTIVATE | OS.SWP_NOSIZE | OS.SWP_NOZORDER;
6525                                    SetWindowPos (itemToolTipHandle, 0, textRect.left, textRect.top, 0, 0, flags);
6526                                    result = LRESULT.ONE;
6527                                }
6528                                break;
6529                            }
6530                            index++;
6531                        }
6532                        if (newFont != 0) OS.SelectObject (hDC, oldFont);
6533                        OS.ReleaseDC (handle, hDC);
6534                        if (result != null) return result;
6535                    }
6536                }
6537            }
6538        }
6539    }
6540    if (hdr.hwndFrom == hwndHeader) {
6541        /*
6542        * Feature in Windows. On NT, the automatically created
6543        * header control is created as a UNICODE window, not an
6544        * ANSI window despite the fact that the parent is created
6545        * as an ANSI window. This means that it sends UNICODE
6546        * notification messages to the parent window on NT for
6547        * no good reason. The data and size in the NMHEADER and
6548        * HDITEM structs is identical between the platforms so no
6549        * different message is actually necessary. Despite this,
6550        * Windows sends different messages. The fix is to look
6551        * for both messages, despite the platform. This works
6552        * because only one will be sent on either platform, never
6553        * both.
6554        */

6555        switch (hdr.code) {
6556            case OS.HDN_BEGINTRACKW:
6557            case OS.HDN_BEGINTRACKA:
6558            case OS.HDN_DIVIDERDBLCLICKW:
6559            case OS.HDN_DIVIDERDBLCLICKA: {
6560                NMHEADER phdn = new NMHEADER ();
6561                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6562                TreeColumn column = columns [phdn.iItem];
6563                if (column != null && !column.getResizable ()) {
6564                    return LRESULT.ONE;
6565                }
6566                ignoreColumnMove = true;
6567                switch (hdr.code) {
6568                    case OS.HDN_DIVIDERDBLCLICKW:
6569                    case OS.HDN_DIVIDERDBLCLICKA:
6570                        if (column != null) column.pack ();
6571                }
6572                break;
6573            }
6574            case OS.NM_RELEASEDCAPTURE: {
6575                if (!ignoreColumnMove) {
6576                    int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
6577                    for (int i=0; i<count; i++) {
6578                        TreeColumn column = columns [i];
6579                        column.updateToolTip (i);
6580                    }
6581                    updateImageList ();
6582                }
6583                ignoreColumnMove = false;
6584                break;
6585            }
6586            case OS.HDN_BEGINDRAG: {
6587                if (ignoreColumnMove) return LRESULT.ONE;
6588                NMHEADER phdn = new NMHEADER ();
6589                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6590                if (phdn.iItem != -1) {
6591                    TreeColumn column = columns [phdn.iItem];
6592                    if (column != null && !column.getMoveable ()) {
6593                        ignoreColumnMove = true;
6594                        return LRESULT.ONE;
6595                    }
6596                }
6597                break;
6598            }
6599            case OS.HDN_ENDDRAG: {
6600                NMHEADER phdn = new NMHEADER ();
6601                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6602                if (phdn.iItem != -1 && phdn.pitem != 0) {
6603                    HDITEM pitem = new HDITEM ();
6604                    OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
6605                    if ((pitem.mask & OS.HDI_ORDER) != 0 && pitem.iOrder != -1) {
6606                        int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
6607                        int [] order = new int [count];
6608                        OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
6609                        int index = 0;
6610                        while (index < order.length) {
6611                            if (order [index] == phdn.iItem) break;
6612                            index++;
6613                        }
6614                        if (index == order.length) index = 0;
6615                        if (index == pitem.iOrder) break;
6616                        int start = Math.min (index, pitem.iOrder);
6617                        int end = Math.max (index, pitem.iOrder);
6618                        RECT rect = new RECT (), headerRect = new RECT ();
6619                        OS.GetClientRect (handle, rect);
6620                        OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [start], headerRect);
6621                        rect.left = Math.max (rect.left, headerRect.left);
6622                        OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [end], headerRect);
6623                        rect.right = Math.min (rect.right, headerRect.right);
6624                        OS.InvalidateRect (handle, rect, true);
6625                        ignoreColumnMove = false;
6626                        for (int i=start; i<=end; i++) {
6627                            TreeColumn column = columns [order [i]];
6628                            if (!column.isDisposed ()) {
6629                                column.postEvent (SWT.Move);
6630                            }
6631                        }
6632                    }
6633                }
6634                break;
6635            }
6636            case OS.HDN_ITEMCHANGINGW:
6637            case OS.HDN_ITEMCHANGINGA: {
6638                NMHEADER phdn = new NMHEADER ();
6639                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6640                if (phdn.pitem != 0) {
6641                    HDITEM newItem = new HDITEM ();
6642                    OS.MoveMemory (newItem, phdn.pitem, HDITEM.sizeof);
6643                    if ((newItem.mask & OS.HDI_WIDTH) != 0) {
6644                        RECT rect = new RECT ();
6645                        OS.GetClientRect (handle, rect);
6646                        HDITEM oldItem = new HDITEM ();
6647                        oldItem.mask = OS.HDI_WIDTH;
6648                        OS.SendMessage (hwndHeader, OS.HDM_GETITEM, phdn.iItem, oldItem);
6649                        int deltaX = newItem.cxy - oldItem.cxy;
6650                        RECT headerRect = new RECT ();
6651                        OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, phdn.iItem, headerRect);
6652                        int gridWidth = linesVisible ? GRID_WIDTH : 0;
6653                        rect.left = headerRect.right - gridWidth;
6654                        int newX = rect.left + deltaX;
6655                        rect.right = Math.max (rect.right, rect.left + Math.abs (deltaX));
6656                        if (explorerTheme || (findImageControl () != null || hooks (SWT.EraseItem) || hooks (SWT.PaintItem))) {
6657                            OS.InvalidateRect (handle, rect, true);
6658                            OS.OffsetRect (rect, deltaX, 0);
6659                            OS.InvalidateRect (handle, rect, true);
6660                        } else {
6661                            int flags = OS.SW_INVALIDATE | OS.SW_ERASE;
6662                            OS.ScrollWindowEx (handle, deltaX, 0, rect, null, 0, null, flags);
6663                        }
6664                        if (OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, phdn.iItem, 0) != 0) {
6665                            rect.left = headerRect.left;
6666                            rect.right = newX;
6667                            OS.InvalidateRect (handle, rect, true);
6668                        }
6669                        setScrollWidth ();
6670                    }
6671                }
6672                break;
6673            }
6674            case OS.HDN_ITEMCHANGEDW:
6675            case OS.HDN_ITEMCHANGEDA: {
6676                NMHEADER phdn = new NMHEADER ();
6677                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6678                if (phdn.pitem != 0) {
6679                    HDITEM pitem = new HDITEM ();
6680                    OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
6681                    if ((pitem.mask & OS.HDI_WIDTH) != 0) {
6682                        if (ignoreColumnMove) {
6683                            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
6684                                int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
6685                                OS.RedrawWindow (handle, null, 0, flags);
6686                            } else {
6687                                if ((style & SWT.DOUBLE_BUFFERED) == 0) {
6688                                    int oldStyle = style;
6689                                    style |= SWT.DOUBLE_BUFFERED;
6690                                    OS.UpdateWindow (handle);
6691                                    style = oldStyle;
6692                                }
6693                            }
6694                        }
6695                        TreeColumn column = columns [phdn.iItem];
6696                        if (column != null) {
6697                            column.updateToolTip (phdn.iItem);
6698                            column.sendEvent (SWT.Resize);
6699                            if (isDisposed ()) return LRESULT.ZERO;
6700                            int count = OS.SendMessage (hwndHeader, OS.HDM_GETITEMCOUNT, 0, 0);
6701                            TreeColumn [] newColumns = new TreeColumn [count];
6702                            System.arraycopy (columns, 0, newColumns, 0, count);
6703                            int [] order = new int [count];
6704                            OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
6705                            boolean moved = false;
6706                            for (int i=0; i<count; i++) {
6707                                TreeColumn nextColumn = newColumns [order [i]];
6708                                if (moved && !nextColumn.isDisposed ()) {
6709                                    nextColumn.updateToolTip (order [i]);
6710                                    nextColumn.sendEvent (SWT.Move);
6711                                }
6712                                if (nextColumn == column) moved = true;
6713                            }
6714                        }
6715                    }
6716                    setScrollWidth ();
6717                }
6718                break;
6719            }
6720            case OS.HDN_ITEMCLICKW:
6721            case OS.HDN_ITEMCLICKA: {
6722                NMHEADER phdn = new NMHEADER ();
6723                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6724                TreeColumn column = columns [phdn.iItem];
6725                if (column != null) {
6726                    column.postEvent (SWT.Selection);
6727                }
6728                break;
6729            }
6730            case OS.HDN_ITEMDBLCLICKW:
6731            case OS.HDN_ITEMDBLCLICKA: {
6732                NMHEADER phdn = new NMHEADER ();
6733                OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
6734                TreeColumn column = columns [phdn.iItem];
6735                if (column != null) {
6736                    column.postEvent (SWT.DefaultSelection);
6737                }
6738                break;
6739            }
6740        }
6741    }
6742    return super.wmNotify (hdr, wParam, lParam);
6743}
6744
6745LRESULT wmNotifyChild (NMHDR hdr, int wParam, int lParam) {
6746    switch (hdr.code) {
6747        case OS.TVN_GETDISPINFOA:
6748        case OS.TVN_GETDISPINFOW: {
6749            NMTVDISPINFO lptvdi = new NMTVDISPINFO ();
6750            OS.MoveMemory (lptvdi, lParam, NMTVDISPINFO.sizeof);
6751            if ((style & SWT.VIRTUAL) != 0) {
6752                /*
6753                * Feature in Windows. When a new tree item is inserted
6754                * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
6755                * TVM_INSERTITEM returns and before the item is added to
6756                * the items array. The fix is to check for null.
6757                *
6758                * NOTE: This only happens on XP with the version 6.00 of
6759                * COMCTL32.DLL.
6760                */

6761                boolean checkVisible = true;
6762                /*
6763                * When an item is being deleted from a virtual tree, do not
6764                * allow the application to provide data for a new item that
6765                * becomes visible until the item has been removed from the
6766                * items array. Because arbitrary application code can run
6767                * during the callback, the items array might be accessed
6768                * in an inconsistent state. Rather than answering the data
6769                * right away, queue a redraw for later.
6770                */

6771                if (!ignoreShrink) {
6772                    if (items != null && lptvdi.lParam != -1) {
6773                        if (items [lptvdi.lParam] != null && items [lptvdi.lParam].cached) {
6774                            checkVisible = false;
6775                        }
6776                    }
6777                }
6778                if (checkVisible) {
6779                    if (drawCount != 0 || !OS.IsWindowVisible (handle)) break;
6780                    RECT itemRect = new RECT ();
6781                    itemRect.left = lptvdi.hItem;
6782                    if (OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, itemRect) == 0) {
6783                        break;
6784                    }
6785                    RECT rect = new RECT ();
6786                    OS.GetClientRect (handle, rect);
6787                    if (!OS.IntersectRect (rect, rect, itemRect)) break;
6788                    if (ignoreShrink) {
6789                        OS.InvalidateRect (handle, rect, true);
6790                        break;
6791                    }
6792                }
6793            }
6794            if (items == null) break;
6795            /*
6796            * Bug in Windows. If the lParam field of TVITEM
6797            * is changed during custom draw using TVM_SETITEM,
6798            * the lItemlParam field of the NMTVCUSTOMDRAW struct
6799            * is not updated until the next custom draw. The
6800            * fix is to query the field from the item instead
6801            * of using the struct.
6802            */

6803            int id = lptvdi.lParam;
6804            if ((style & SWT.VIRTUAL) != 0) {
6805                if (id == -1) {
6806                    TVITEM tvItem = new TVITEM ();
6807                    tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6808                    tvItem.hItem = lptvdi.hItem;
6809                    OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6810                    id = tvItem.lParam;
6811                }
6812            }
6813            TreeItem item = _getItem (lptvdi.hItem, id);
6814            /*
6815            * Feature in Windows. When a new tree item is inserted
6816            * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
6817            * TVM_INSERTITEM returns and before the item is added to
6818            * the items array. The fix is to check for null.
6819            *
6820            * NOTE: This only happens on XP with the version 6.00 of
6821            * COMCTL32.DLL.
6822            *
6823            * Feature in Windows. When TVM_DELETEITEM is called with
6824            * TVI_ROOT to remove all items from a tree, under certain
6825            * circumstances, the tree sends TVN_GETDISPINFO for items
6826            * that are about to be disposed. The fix is to check for
6827            * disposed items.
6828            */

6829            if (item == null) break;
6830            if (item.isDisposed ()) break;
6831            if (!item.cached) {
6832                if ((style & SWT.VIRTUAL) != 0) {
6833                    if (!checkData (item, false)) break;
6834                }
6835                if (painted) item.cached = true;
6836            }
6837            int index = 0;
6838            if (hwndHeader != 0) {
6839                index = OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
6840            }
6841            if ((lptvdi.mask & OS.TVIF_TEXT) != 0) {
6842                String JavaDoc string = null;
6843                if (index == 0) {
6844                    string = item.text;
6845                } else {
6846                    String JavaDoc [] strings = item.strings;
6847                    if (strings != null) string = strings [index];
6848                }
6849                if (string != null) {
6850                    TCHAR buffer = new TCHAR (getCodePage (), string, false);
6851                    int byteCount = Math.min (buffer.length (), lptvdi.cchTextMax - 1) * TCHAR.sizeof;
6852                    OS.MoveMemory (lptvdi.pszText, buffer, byteCount);
6853                    OS.MoveMemory (lptvdi.pszText + byteCount, new byte [TCHAR.sizeof], TCHAR.sizeof);
6854                    lptvdi.cchTextMax = Math.min (lptvdi.cchTextMax, string.length () + 1);
6855                }
6856            }
6857            if ((lptvdi.mask & (OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE)) != 0) {
6858                Image image = null;
6859                if (index == 0) {
6860                    image = item.image;
6861                } else {
6862                    Image [] images = item.images;
6863                    if (images != null) image = images [index];
6864                }
6865                lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
6866                if (image != null) {
6867                    lptvdi.iImage = lptvdi.iSelectedImage = imageIndex (image, index);
6868                }
6869                if (explorerTheme && OS.IsWindowEnabled (handle)) {
6870                    if (findImageControl () != null) {
6871                        lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
6872                    }
6873                }
6874            }
6875            OS.MoveMemory (lParam, lptvdi, NMTVDISPINFO.sizeof);
6876            break;
6877        }
6878        case OS.NM_CUSTOMDRAW: {
6879            if (hdr.hwndFrom == hwndHeader) break;
6880            if (hooks (SWT.MeasureItem)) {
6881                if (hwndHeader == 0) createParent ();
6882            }
6883            if (!customDraw && findImageControl () == null) {
6884                if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
6885                    if (sortColumn == null || sortDirection == SWT.NONE) {
6886                        break;
6887                    }
6888                }
6889            }
6890            NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW ();
6891            OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof);
6892            switch (nmcd.dwDrawStage) {
6893                case OS.CDDS_PREPAINT: return CDDS_PREPAINT (nmcd, wParam, lParam);
6894                case OS.CDDS_ITEMPREPAINT: return CDDS_ITEMPREPAINT (nmcd, wParam, lParam);
6895                case OS.CDDS_ITEMPOSTPAINT: return CDDS_ITEMPOSTPAINT (nmcd, wParam, lParam);
6896                case OS.CDDS_POSTPAINT: return CDDS_POSTPAINT (nmcd, wParam, lParam);
6897            }
6898            break;
6899        }
6900        case OS.NM_DBLCLK: {
6901            /*
6902            * When the user double clicks on a tree item
6903            * or a line beside the item, the window proc
6904            * for the tree collapses or expand the branch.
6905            * When application code associates an action
6906            * with double clicking, then the tree expand
6907            * is unexpected and unwanted. The fix is to
6908            * avoid the operation by testing to see whether
6909            * the mouse was inside a tree item.
6910            */

6911            if (hooks (SWT.DefaultSelection)) {
6912                POINT pt = new POINT ();
6913                int pos = OS.GetMessagePos ();
6914                pt.x = (short) (pos & 0xFFFF);
6915                pt.y = (short) (pos >> 16);
6916                OS.ScreenToClient (handle, pt);
6917                TVHITTESTINFO lpht = new TVHITTESTINFO ();
6918                lpht.x = pt.x;
6919                lpht.y = pt.y;
6920                OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6921                if (lpht.hItem != 0 && (lpht.flags & OS.TVHT_ONITEM) != 0) {
6922                    return LRESULT.ONE;
6923                }
6924            }
6925            break;
6926        }
6927        /*
6928        * Bug in Windows. On Vista, when TVM_SELECTITEM is called
6929        * with TVGN_CARET in order to set the selection, for some
6930        * reason, Windows deselects the previous two items that
6931        * were selected. The fix is to stop the selection from
6932        * changing on all but the item that is supposed to be
6933        * selected.
6934        */

6935        case OS.TVN_ITEMCHANGINGA:
6936        case OS.TVN_ITEMCHANGINGW: {
6937            if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
6938                if ((style & SWT.MULTI) != 0) {
6939                    if (hSelect != 0) {
6940                        NMTVITEMCHANGE pnm = new NMTVITEMCHANGE ();
6941                        OS.MoveMemory (pnm, lParam, NMTVITEMCHANGE.sizeof);
6942                        if (hSelect == pnm.hItem) break;
6943                        return LRESULT.ONE;
6944                    }
6945                }
6946            }
6947            break;
6948        }
6949        case OS.TVN_SELCHANGINGA:
6950        case OS.TVN_SELCHANGINGW: {
6951            if ((style & SWT.MULTI) != 0) {
6952                if (lockSelection) {
6953                    /* Save the old selection state for both items */
6954                    TVITEM tvItem = new TVITEM ();
6955                    int offset1 = NMHDR.sizeof + 4;
6956                    OS.MoveMemory (tvItem, lParam + offset1, TVITEM.sizeof);
6957                    oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6958                    int offset2 = NMHDR.sizeof + 4 + TVITEM.sizeof;
6959                    OS.MoveMemory (tvItem, lParam + offset2, TVITEM.sizeof);
6960                    newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6961                }
6962            }
6963            if (!ignoreSelect && !ignoreDeselect) {
6964                hAnchor = 0;
6965                if ((style & SWT.MULTI) != 0) deselectAll ();
6966            }
6967            break;
6968        }
6969        case OS.TVN_SELCHANGEDA:
6970        case OS.TVN_SELCHANGEDW: {
6971            if ((style & SWT.MULTI) != 0) {
6972                if (lockSelection) {
6973                    /* Restore the old selection state of both items */
6974                    if (oldSelected) {
6975                        TVITEM tvItem = new TVITEM ();
6976                        int offset = NMHDR.sizeof + 4;
6977                        OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
6978                        tvItem.mask = OS.TVIF_STATE;
6979                        tvItem.stateMask = OS.TVIS_SELECTED;
6980                        tvItem.state = OS.TVIS_SELECTED;
6981                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6982                    }
6983                    if (!newSelected && ignoreSelect) {
6984                        TVITEM tvItem = new TVITEM ();
6985                        int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
6986                        OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
6987                        tvItem.mask = OS.TVIF_STATE;
6988                        tvItem.stateMask = OS.TVIS_SELECTED;
6989                        tvItem.state = 0;
6990                        OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6991                    }
6992                }
6993            }
6994            if (!ignoreSelect) {
6995                TVITEM tvItem = new TVITEM ();
6996                int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
6997                OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
6998                hAnchor = tvItem.hItem;
6999                Event event = new Event ();
7000                event.item = _getItem (tvItem.hItem, tvItem.lParam);
7001                postEvent (SWT.Selection, event);
7002            }
7003            updateScrollBar ();
7004            break;
7005        }
7006        case OS.TVN_ITEMEXPANDINGA:
7007        case OS.TVN_ITEMEXPANDINGW: {
7008            boolean runExpanded = false;
7009            if ((style & SWT.VIRTUAL) != 0) style &= ~SWT.DOUBLE_BUFFERED;
7010            if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style &= ~SWT.DOUBLE_BUFFERED;
7011            if (findImageControl () != null && drawCount == 0 && OS.IsWindowVisible (handle)) {
7012                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
7013            }
7014            /*
7015            * Bug in Windows. When TVM_SETINSERTMARK is used to set
7016            * an insert mark for a tree and an item is expanded or
7017            * collapsed near the insert mark, the tree does not redraw
7018            * the insert mark properly. The fix is to hide and show
7019            * the insert mark whenever an item is expanded or collapsed.
7020            */

7021            if (hInsert != 0) {
7022                OS.SendMessage (handle, OS.TVM_SETINSERTMARK, 0, 0);
7023            }
7024            if (!ignoreExpand) {
7025                TVITEM tvItem = new TVITEM ();
7026                int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
7027                OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
7028                /*
7029                * Feature in Windows. In some cases, TVM_ITEMEXPANDING
7030                * is sent from within TVM_DELETEITEM for the tree item
7031                * being destroyed. By the time the message is sent,
7032                * the item has already been removed from the list of
7033                * items. The fix is to check for null.
7034                */

7035                if (items == null) break;
7036                TreeItem item = _getItem (tvItem.hItem, tvItem.lParam);
7037                if (item == null) break;
7038                Event event = new Event ();
7039                event.item = item;
7040                int [] action = new int [1];
7041                OS.MoveMemory (action, lParam + NMHDR.sizeof, 4);
7042                switch (action [0]) {
7043                    case OS.TVE_EXPAND:
7044                        /*
7045                        * Bug in Windows. When the numeric keypad asterisk
7046                        * key is used to expand every item in the tree, Windows
7047                        * sends TVN_ITEMEXPANDING to items in the tree that
7048                        * have already been expanded. The fix is to detect
7049                        * that the item is already expanded and ignore the
7050                        * notification.
7051                        */

7052                        if ((tvItem.state & OS.TVIS_EXPANDED) == 0) {
7053                            sendEvent (SWT.Expand, event);
7054                            if (isDisposed ()) return LRESULT.ZERO;
7055                        }
7056                        break;
7057                    case OS.TVE_COLLAPSE:
7058                        sendEvent (SWT.Collapse, event);
7059                        if (isDisposed ()) return LRESULT.ZERO;
7060                        break;
7061                }
7062                /*
7063                * Bug in Windows. When all of the items are deleted during
7064                * TVN_ITEMEXPANDING, Windows does not send TVN_ITEMEXPANDED.
7065                * The fix is to detect this case and run the TVN_ITEMEXPANDED
7066                * code in this method.
7067                */

7068                int hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, tvItem.hItem);
7069                runExpanded = hFirstItem == 0;
7070            }
7071            if (!runExpanded) break;
7072            //FALL THROUGH
7073
}
7074        case OS.TVN_ITEMEXPANDEDA:
7075        case OS.TVN_ITEMEXPANDEDW: {
7076            if ((style & SWT.VIRTUAL) != 0) style |= SWT.DOUBLE_BUFFERED;
7077            if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style |= SWT.DOUBLE_BUFFERED;
7078            if (findImageControl () != null && drawCount == 0 /*&& OS.IsWindowVisible (handle)*/) {
7079                OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
7080                OS.InvalidateRect (handle, null, true);
7081            }
7082            /*
7083            * Bug in Windows. When TVM_SETINSERTMARK is used to set
7084            * an insert mark for a tree and an item is expanded or
7085            * collapsed near the insert mark, the tree does not redraw
7086            * the insert mark properly. The fix is to hide and show
7087            * the insert mark whenever an item is expanded or collapsed.
7088            */

7089            if (hInsert != 0) {
7090                OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
7091            }
7092            /*
7093            * Bug in Windows. When a tree item that has an image
7094            * with alpha is expanded or collapsed, the area where
7095            * the image is drawn is not erased before it is drawn.
7096            * This means that the image gets darker each time.
7097            * The fix is to redraw the item.
7098            */

7099            if (!OS.IsWinCE && OS.COMCTL32_MAJOR >= 6) {
7100                if (imageList != null) {
7101                    TVITEM tvItem = new TVITEM ();
7102                    int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
7103                    OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
7104                    if (tvItem.hItem != 0) {
7105                        int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7106                        if ((bits & OS.TVS_FULLROWSELECT) == 0) {
7107                            RECT rect = new RECT ();
7108                            rect.left = tvItem.hItem;
7109                            OS.SendMessage (handle, OS.TVM_GETITEMRECT, 0, rect);
7110                            OS.InvalidateRect (handle, rect, true);
7111                        }
7112                    }
7113                }
7114            }
7115            updateScrollBar ();
7116            break;
7117        }
7118        case OS.TVN_BEGINDRAGA:
7119        case OS.TVN_BEGINDRAGW:
7120        case OS.TVN_BEGINRDRAGA:
7121        case OS.TVN_BEGINRDRAGW: {
7122            TVITEM tvItem = new TVITEM ();
7123            int offset = NMHDR.sizeof + 4 + TVITEM.sizeof;
7124            OS.MoveMemory (tvItem, lParam + offset, TVITEM.sizeof);
7125            if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) {
7126                hSelect = tvItem.hItem;
7127                ignoreSelect = ignoreDeselect = true;
7128                OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem);
7129                ignoreSelect = ignoreDeselect = false;
7130                hSelect = 0;
7131            }
7132            dragStarted = true;
7133            break;
7134        }
7135        case OS.NM_RECOGNIZEGESTURE: {
7136            /*
7137            * Feature in Pocket PC. The tree and table controls detect the tap
7138            * and hold gesture by default. They send a GN_CONTEXTMENU message to show
7139            * the popup menu. This default behaviour is unwanted on Pocket PC 2002
7140            * when no menu has been set, as it still draws a red circle. The fix
7141            * is to disable this default behaviour when no menu is set by returning
7142            * TRUE when receiving the Pocket PC 2002 specific NM_RECOGNIZEGESTURE
7143            * message.
7144            */

7145            if (OS.IsPPC) {
7146                boolean hasMenu = menu != null && !menu.isDisposed ();
7147                if (!hasMenu && !hooks (SWT.MenuDetect)) return LRESULT.ONE;
7148            }
7149            break;
7150        }
7151        case OS.GN_CONTEXTMENU: {
7152            if (OS.IsPPC) {
7153                boolean hasMenu = menu != null && !menu.isDisposed ();
7154                if (hasMenu || hooks (SWT.MenuDetect)) {
7155                    NMRGINFO nmrg = new NMRGINFO ();
7156                    OS.MoveMemory (nmrg, lParam, NMRGINFO.sizeof);
7157                    showMenu (nmrg.x, nmrg.y);
7158                    gestureCompleted = true;
7159                    return LRESULT.ONE;
7160                }
7161            }
7162            break;
7163        }
7164    }
7165    return super.wmNotifyChild (hdr, wParam, lParam);
7166}
7167
7168}
7169
Popular Tags