1 /*******************************************************************************
2 * Copyright (c) 2000, 2018 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.widgets;
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.events.*;
19 import org.eclipse.swt.graphics.*;
20 import org.eclipse.swt.internal.*;
21 import org.eclipse.swt.internal.win32.*;
24 * Instances of this class provide a selectable user interface object
25 * that displays a hierarchy of items and issues notification when an
26 * item in the hierarchy is selected.
28 * The item children that may be added to instances of this class
29 * must be of type <code>TreeItem</code>.
31 * Style <code>VIRTUAL</code> is used to create a <code>Tree</code> whose
32 * <code>TreeItem</code>s are to be populated by the client on an on-demand basis
33 * instead of up-front. This can provide significant performance improvements for
34 * trees that are very large or for which <code>TreeItem</code> population is
35 * expensive (for example, retrieving values from an external source).
37 * Here is an example of using a <code>Tree</code> with style <code>VIRTUAL</code>:</p>
39 * final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
40 * tree.setItemCount(20);
41 * tree.addListener(SWT.SetData, new Listener() {
42 * public void handleEvent(Event event) {
43 * TreeItem item = (TreeItem)event.item;
44 * TreeItem parentItem = item.getParentItem();
46 * if (parentItem == null) {
47 * text = "node " + tree.indexOf(item);
49 * text = parentItem.getText() + " - " + parentItem.indexOf(item);
52 * System.out.println(text);
53 * item.setItemCount(10);
58 * Note that although this class is a subclass of <code>Composite</code>,
59 * it does not normally make sense to add <code>Control</code> children to
60 * it, or set a layout on it, unless implementing something like a cell
64 * <dt><b>Styles:</b></dt>
65 * <dd>SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL, NO_SCROLL</dd>
66 * <dt><b>Events:</b></dt>
67 * <dd>Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, EraseItem, PaintItem</dd>
70 * Note: Only one of the styles SINGLE and MULTI may be specified.
72 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
75 * @see <a href="http://www.eclipse.org/swt/snippets/#tree">Tree, TreeItem, TreeColumn snippets</a>
76 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
77 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
78 * @noextend This class is not intended to be subclassed by clients.
80 public class Tree extends Composite {
82 TreeColumn [] columns;
84 ImageList imageList, headerImageList;
86 TreeColumn sortColumn;
88 long hwndParent, hwndHeader, hAnchor, hInsert, hSelect;
90 long hFirstIndexOf, hLastIndexOf;
91 int lastIndexOf, itemCount, sortDirection;
92 boolean dragStarted, gestureCompleted, insertAfter, shrink, ignoreShrink;
93 boolean ignoreSelect, ignoreExpand, ignoreDeselect, ignoreResize;
94 boolean lockSelection, oldSelected, newSelected, ignoreColumnMove;
95 boolean linesVisible, customDraw, painted, ignoreItemHeight;
96 boolean ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus;
97 boolean ignoreDrawSelection, ignoreDrawHot, ignoreFullSelection, explorerTheme;
99 boolean headerItemDragging;
100 int scrollWidth, selectionForeground;
101 long headerToolTipHandle, itemToolTipHandle;
102 long lastTimerID = -1;
104 int headerBackground = -1;
105 int headerForeground = -1;
106 static final boolean ENABLE_TVS_EX_FADEINOUTEXPANDOS = System.getProperty("org.eclipse.swt.internal.win32.enableFadeInOutExpandos") != null;
107 static final int TIMER_MAX_COUNT = 8;
108 static final int INSET = 3;
109 static final int GRID_WIDTH = 1;
110 static final int SORT_WIDTH = 10;
111 static final int HEADER_MARGIN = 12;
112 static final int HEADER_EXTRA = 3;
113 static final int INCREMENT = 5;
114 static final int EXPLORER_EXTRA = 2;
115 static final int DRAG_IMAGE_SIZE = 301;
116 static final long TreeProc;
117 static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true);
118 static final long HeaderProc;
119 static final TCHAR HeaderClass = new TCHAR (0, OS.WC_HEADER, true);
121 WNDCLASS lpWndClass = new WNDCLASS ();
122 OS.GetClassInfo (0, TreeClass, lpWndClass);
123 TreeProc = lpWndClass.lpfnWndProc;
124 OS.GetClassInfo (0, HeaderClass, lpWndClass);
125 HeaderProc = lpWndClass.lpfnWndProc;
129 * Constructs a new instance of this class given its parent
130 * and a style value describing its behavior and appearance.
132 * The style value is either one of the style constants defined in
133 * class <code>SWT</code> which is applicable to instances of this
134 * class, or must be built by <em>bitwise OR</em>'ing together
135 * (that is, using the <code>int</code> "|" operator) two or more
136 * of those <code>SWT</code> style constants. The class description
137 * lists the style constants that are applicable to the class.
138 * Style bits are also inherited from superclasses.
141 * @param parent a composite control which will be the parent of the new instance (cannot be null)
142 * @param style the style of control to construct
144 * @exception IllegalArgumentException <ul>
145 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
147 * @exception SWTException <ul>
148 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
149 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
155 * @see SWT#FULL_SELECTION
158 * @see Widget#checkSubclass
159 * @see Widget#getStyle
161 public Tree (Composite parent, int style) {
162 super (parent, checkStyle (style));
165 static int checkStyle (int style) {
167 * Feature in Windows. Even when WS_HSCROLL or
168 * WS_VSCROLL is not specified, Windows creates
169 * trees and tables with scroll bars. The fix
170 * is to set H_SCROLL and V_SCROLL.
172 * NOTE: This code appears on all platforms so that
173 * applications have consistent scroll bar behavior.
175 if ((style & SWT.NO_SCROLL) == 0) {
176 style |= SWT.H_SCROLL | SWT.V_SCROLL;
179 * Note: Windows only supports TVS_NOSCROLL and TVS_NOHSCROLL.
181 if ((style & SWT.H_SCROLL) != 0 && (style & SWT.V_SCROLL) == 0) {
182 style |= SWT.V_SCROLL;
184 return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0);
188 void _addListener (int eventType, Listener listener) {
189 super._addListener (eventType, listener);
191 case SWT.DragDetect: {
192 if ((state & DRAG_DETECT) != 0) {
193 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
194 bits &= ~OS.TVS_DISABLEDRAGDROP;
195 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
199 case SWT.MeasureItem:
201 case SWT.PaintItem: {
203 style |= SWT.DOUBLE_BUFFERED;
204 if (isCustomToolTip ()) createItemToolTips ();
205 OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
206 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
207 if (eventType == SWT.MeasureItem) {
209 * This code is intentionally commented.
211 // if (explorerTheme) {
212 // int bits1 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
213 // bits1 &= ~OS.TVS_EX_AUTOHSCROLL;
214 // OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits1);
216 bits |= OS.TVS_NOHSCROLL;
219 * Feature in Windows. When the tree has the style
220 * TVS_FULLROWSELECT, the background color for the
221 * entire row is filled when an item is painted,
222 * drawing on top of any custom drawing. The fix
223 * is to clear TVS_FULLROWSELECT.
225 if ((style & SWT.FULL_SELECTION) != 0) {
226 if (eventType != SWT.MeasureItem) {
227 if (!explorerTheme) bits &= ~OS.TVS_FULLROWSELECT;
230 if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) {
231 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
232 OS.InvalidateRect (handle, null, true);
234 * Bug in Windows. When TVS_NOHSCROLL is set after items
235 * have been inserted into the tree, Windows shows the
236 * scroll bar. The fix is to check for this case and
237 * explicitly hide the scroll bar.
239 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
240 if (count != 0 && (bits & OS.TVS_NOHSCROLL) != 0) {
241 OS.ShowScrollBar (handle, OS.SB_HORZ, false);
249 TreeItem _getItem (long hItem) {
250 TVITEM tvItem = new TVITEM ();
251 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
252 tvItem.hItem = hItem;
253 if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
254 return _getItem (tvItem.hItem, (int)tvItem.lParam);
259 TreeItem _getItem (long hItem, int id) {
260 if ((style & SWT.VIRTUAL) == 0) return items [id];
261 return id != -1 ? items [id] : new TreeItem (this, SWT.NONE, -1, -1, hItem);
265 void _removeListener (int eventType, Listener listener) {
266 super._removeListener (eventType, listener);
268 case SWT.MeasureItem: {
270 * If H_SCROLL is set, reverting the TVS_NOHSCROLL settings which
271 * was applied while adding SWT.MeasureItem event Listener.
273 if ((style & SWT.H_SCROLL) != 0 && (state & DISPOSE_SENT) == 0) {
274 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
275 bits &= ~OS.TVS_NOHSCROLL;
276 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
277 OS.InvalidateRect (handle, null, true);
284 void _setBackgroundPixel (int newPixel) {
285 int oldPixel = (int)OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0);
286 if (oldPixel != newPixel) {
288 * Bug in Windows. When TVM_SETBKCOLOR is used more
289 * than once to set the background color of a tree,
290 * the background color of the lines and the plus/minus
291 * does not change to the new color. The fix is to set
292 * the background color to the default before setting
295 if (oldPixel != -1) {
296 OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
299 /* Set the background color */
300 OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, newPixel);
303 * Feature in Windows. When TVM_SETBKCOLOR is used to
304 * set the background color of a tree, the plus/minus
305 * animation draws badly. The fix is to clear the effect.
307 if (explorerTheme && ENABLE_TVS_EX_FADEINOUTEXPANDOS) {
308 int bits2 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
309 if (newPixel == -1 && findImageControl () == null) {
310 bits2 |= OS.TVS_EX_FADEINOUTEXPANDOS;
312 bits2 &= ~OS.TVS_EX_FADEINOUTEXPANDOS;
314 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits2);
317 /* Set the checkbox image list */
318 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
323 * Adds the listener to the collection of listeners who will
324 * be notified when the user changes the receiver's selection, by sending
325 * it one of the messages defined in the <code>SelectionListener</code>
328 * When <code>widgetSelected</code> is called, the item field of the event object is valid.
329 * If the receiver has the <code>SWT.CHECK</code> style and the check selection changes,
330 * the event object detail field contains the value <code>SWT.CHECK</code>.
331 * <code>widgetDefaultSelected</code> is typically called when an item is double-clicked.
332 * The item field of the event object is valid for default selection, but the detail field is not used.
335 * @param listener the listener which should be notified when the user changes the receiver's selection
337 * @exception IllegalArgumentException <ul>
338 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
340 * @exception SWTException <ul>
341 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
342 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
345 * @see SelectionListener
346 * @see #removeSelectionListener
347 * @see SelectionEvent
349 public void addSelectionListener(SelectionListener listener) {
351 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
352 TypedListener typedListener = new TypedListener (listener);
353 addListener (SWT.Selection, typedListener);
354 addListener (SWT.DefaultSelection, typedListener);
358 * Adds the listener to the collection of listeners who will
359 * be notified when an item in the receiver is expanded or collapsed
360 * by sending it one of the messages defined in the <code>TreeListener</code>
363 * @param listener the listener which should be notified
365 * @exception IllegalArgumentException <ul>
366 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
368 * @exception SWTException <ul>
369 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
370 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
374 * @see #removeTreeListener
376 public void addTreeListener(TreeListener listener) {
378 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
379 TypedListener typedListener = new TypedListener (listener);
380 addListener (SWT.Expand, typedListener);
381 addListener (SWT.Collapse, typedListener);
385 long borderHandle () {
386 return hwndParent != 0 ? hwndParent : handle;
389 LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
390 if (ignoreCustomDraw) return null;
391 if (nmcd.left == nmcd.right) return new LRESULT (OS.CDRF_DODEFAULT);
393 OS.RestoreDC (hDC, -1);
394 TreeItem item = getItem (nmcd);
397 * Feature in Windows. When a new tree item is inserted
398 * using TVM_INSERTITEM and the tree is using custom draw,
399 * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
400 * and before the item is added to the items array. The
401 * fix is to check for null.
403 * NOTE: This only happens on XP with the version 6.00 of
406 if (item == null) return null;
409 * Feature in Windows. Under certain circumstances, Windows
410 * sends CDDS_ITEMPOSTPAINT for an empty rectangle. This is
411 * not a problem providing that graphics do not occur outside
412 * the rectangle. The fix is to test for the rectangle and
415 * NOTE: This seems to happen when both I_IMAGECALLBACK
416 * and LPSTR_TEXTCALLBACK are used at the same time with
419 if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) return null;
420 if (!OS.IsWindowVisible (handle)) return null;
421 if ((style & SWT.FULL_SELECTION) != 0 || findImageControl () != null || ignoreDrawSelection || explorerTheme) {
422 OS.SetBkMode (hDC, OS.TRANSPARENT);
424 boolean selected = isItemSelected (nmcd);
425 boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
426 if (OS.IsWindowEnabled (handle)) {
428 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
429 if ((bits & OS.TVS_TRACKSELECT) != 0) {
430 if ((style & SWT.FULL_SELECTION) != 0 && (selected || hot)) {
431 OS.SetTextColor (hDC, OS.GetSysColor (OS.COLOR_WINDOWTEXT));
433 OS.SetTextColor (hDC, getForegroundPixel ());
439 RECT clientRect = new RECT ();
440 OS.GetClientRect (scrolledHandle (), clientRect);
441 if (hwndHeader != 0) {
442 OS.MapWindowPoints (hwndParent, handle, clientRect, 2);
443 if (columnCount != 0) {
444 order = new int [columnCount];
445 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
448 int sortIndex = -1, clrSortBk = -1;
449 if (OS.IsAppThemed ()) {
450 if (sortColumn != null && sortDirection != SWT.NONE) {
451 if (findImageControl () == null) {
452 sortIndex = indexOf (sortColumn);
453 clrSortBk = getSortColumnPixel ();
459 for (int i=0; i<Math.max (1, columnCount); i++) {
460 int index = order == null ? i : order [i], width = nmcd.right - nmcd.left;
461 if (columnCount > 0 && hwndHeader != 0) {
462 HDITEM hdItem = new HDITEM ();
463 hdItem.mask = OS.HDI_WIDTH;
464 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
468 if ((style & SWT.FULL_SELECTION) != 0) {
469 boolean clear = !explorerTheme && !ignoreDrawSelection && findImageControl () == null;
470 if (clear || (selected && !ignoreDrawSelection) || (hot && !ignoreDrawHot)) {
472 RECT pClipRect = new RECT ();
473 OS.SetRect (pClipRect, width, nmcd.top, nmcd.right, nmcd.bottom);
475 if (hooks (SWT.EraseItem)) {
476 RECT itemRect = item.getBounds (index, true, true, false, false, true, hDC);
477 itemRect.left -= EXPLORER_EXTRA;
478 itemRect.right += EXPLORER_EXTRA + 1;
479 pClipRect.left = itemRect.left;
480 pClipRect.right = itemRect.right;
481 if (columnCount > 0 && hwndHeader != 0) {
482 HDITEM hdItem = new HDITEM ();
483 hdItem.mask = OS.HDI_WIDTH;
484 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
485 pClipRect.right = Math.min (pClipRect.right, nmcd.left + hdItem.cxy);
488 RECT pRect = new RECT ();
489 OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
490 if (columnCount > 0 && hwndHeader != 0) {
492 HDITEM hdItem = new HDITEM ();
493 hdItem.mask = OS.HDI_WIDTH;
494 for (int j=0; j<columnCount; j++) {
495 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
496 totalWidth += hdItem.cxy;
498 if (totalWidth > clientRect.right - clientRect.left) {
500 pRect.right = totalWidth;
502 pRect.left = clientRect.left;
503 pRect.right = clientRect.right;
507 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
508 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
509 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
510 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
511 OS.CloseThemeData (hTheme);
513 if (draw) fillBackground (hDC, OS.GetBkColor (hDC), pClipRect);
517 if (x + width > clientRect.left) {
518 RECT rect = new RECT (), backgroundRect = null;
519 boolean drawItem = true, drawText = true, drawImage = true, drawBackground = false;
521 drawItem = drawImage = drawText = false;
522 if (findImageControl () != null) {
524 if (OS.IsWindowEnabled (handle) && !hooks (SWT.EraseItem)) {
529 Image [] images = item.images;
530 if (images != null) image = images [index];
533 Rectangle bounds = image.getBounds (); // Points
534 if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points
535 if (!ignoreDrawForeground) {
536 GCData data = new GCData();
537 data.device = display;
538 GC gc = GC.win32_new (hDC, data);
539 RECT iconRect = item.getBounds (index, false, true, false, false, true, hDC); // Pixels
540 gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(iconRect.left, iconRect.top, iconRect.right - iconRect.left, iconRect.bottom - iconRect.top)));
541 gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(iconRect.left), DPIUtil.autoScaleDown(iconRect.top), size.x, size.y);
542 OS.SelectClipRgn (hDC, 0);
548 drawItem = drawText = drawBackground = true;
549 rect = item.getBounds (index, true, false, false, false, true, hDC);
556 if (selected && !ignoreDrawSelection && !ignoreDrawBackground) {
557 if (!explorerTheme) fillBackground (hDC, OS.GetBkColor (hDC), rect);
558 drawBackground = false;
560 backgroundRect = rect;
561 if (hooks (SWT.EraseItem)) {
562 drawItem = drawText = drawImage = true;
563 rect = item.getBounds (index, true, true, false, false, true, hDC);
564 if ((style & SWT.FULL_SELECTION) != 0) {
565 backgroundRect = rect;
567 backgroundRect = item.getBounds (index, true, false, false, false, true, hDC);
571 selectionForeground = -1;
572 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = false;
573 OS.SetRect (rect, x, nmcd.top, x + width, nmcd.bottom);
574 backgroundRect = rect;
576 int clrText = -1, clrTextBk = -1;
577 long hFont = item.fontHandle (index);
578 if (selectionForeground != -1) clrText = selectionForeground;
579 if (OS.IsWindowEnabled (handle)) {
580 boolean drawForeground = false;
582 if (i != 0 && (style & SWT.FULL_SELECTION) == 0) {
583 OS.SetTextColor (hDC, getForegroundPixel ());
584 OS.SetBkColor (hDC, getBackgroundPixel ());
585 drawForeground = drawBackground = true;
588 drawForeground = drawBackground = true;
590 if (drawForeground) {
591 clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
592 if (clrText == -1) clrText = item.foreground;
594 if (drawBackground) {
595 clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
596 if (clrTextBk == -1) clrTextBk = item.background;
597 if (clrTextBk == -1 && index == sortIndex) clrTextBk = clrSortBk;
600 if (clrTextBk == -1 && index == sortIndex) {
601 drawBackground = true;
602 clrTextBk = clrSortBk;
606 if (selected || (nmcd.uItemState & OS.CDIS_HOT) != 0) {
607 if ((style & SWT.FULL_SELECTION) != 0) {
608 drawBackground = false;
611 drawBackground = false;
612 if (!hooks (SWT.EraseItem)) drawText = false;
619 if (hooks (SWT.MeasureItem)) {
620 sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0);
621 if (isDisposed () || item.isDisposed ()) break;
623 if (hooks (SWT.EraseItem)) {
624 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
625 int nSavedDC = OS.SaveDC (hDC);
626 GCData data = new GCData ();
627 data.device = display;
628 data.foreground = OS.GetTextColor (hDC);
629 data.background = OS.GetBkColor (hDC);
630 if (!selected || (style & SWT.FULL_SELECTION) == 0) {
631 if (clrText != -1) data.foreground = clrText;
632 if (clrTextBk != -1) data.background = clrTextBk;
634 data.font = item.getFont (index);
635 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
636 GC gc = GC.win32_new (hDC, data);
637 Event event = new Event ();
641 event.detail |= SWT.FOREGROUND;
642 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
643 if ((style & SWT.FULL_SELECTION) != 0) {
644 if (hot) event.detail |= SWT.HOT;
645 if (selected) event.detail |= SWT.SELECTED;
646 if (!explorerTheme) {
647 //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
648 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
649 if (handle == OS.GetFocus ()) {
650 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
651 if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
656 Rectangle boundsInPixels = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top);
657 event.setBoundsInPixels (boundsInPixels);
658 gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels));
659 sendEvent (SWT.EraseItem, event);
661 int newTextClr = data.foreground;
663 OS.RestoreDC (hDC, nSavedDC);
664 if (isDisposed () || item.isDisposed ()) break;
666 ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
667 ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
668 if ((style & SWT.FULL_SELECTION) != 0) {
669 ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
670 ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
671 ignoreDrawHot = (event.detail & SWT.HOT) == 0;
674 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
676 if (selected && ignoreDrawSelection) ignoreDrawHot = true;
677 if ((style & SWT.FULL_SELECTION) != 0) {
678 if (ignoreDrawSelection) ignoreFullSelection = true;
679 if (!ignoreDrawSelection || !ignoreDrawHot) {
680 if (!selected && !hot) {
681 selectionForeground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
683 if (!explorerTheme) {
684 drawBackground = true;
685 ignoreDrawBackground = false;
686 if ((handle == OS.GetFocus () || display.getHighContrast ()) && OS.IsWindowEnabled (handle)) {
687 clrTextBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT);
689 clrTextBk = OS.GetSysColor (OS.COLOR_3DFACE);
691 if (!ignoreFullSelection && index == columnCount - 1) {
692 RECT selectionRect = new RECT ();
693 OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, nmcd.right, backgroundRect.bottom);
694 backgroundRect = selectionRect;
697 RECT pRect = new RECT ();
698 OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
699 if (columnCount > 0 && hwndHeader != 0) {
701 HDITEM hdItem = new HDITEM ();
702 hdItem.mask = OS.HDI_WIDTH;
703 for (int j=0; j<columnCount; j++) {
704 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, j, hdItem);
705 totalWidth += hdItem.cxy;
707 if (totalWidth > clientRect.right - clientRect.left) {
709 pRect.right = totalWidth;
711 pRect.left = clientRect.left;
712 pRect.right = clientRect.right;
714 if (index == columnCount - 1) {
715 RECT selectionRect = new RECT ();
716 OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, pRect.right, backgroundRect.bottom);
717 backgroundRect = selectionRect;
720 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
721 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
722 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
723 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, backgroundRect);
724 OS.CloseThemeData (hTheme);
729 selectionForeground = newTextClr;
730 if (!explorerTheme) {
731 if (clrTextBk == -1 && OS.IsWindowEnabled (handle)) {
732 Control control = findBackgroundControl ();
733 if (control == null) control = this;
734 clrTextBk = control.getBackgroundPixel ();
741 if (selectionForeground != -1) clrText = selectionForeground;
743 if (!ignoreDrawBackground) {
744 if (clrTextBk != -1) {
745 if (drawBackground) fillBackground (hDC, clrTextBk, backgroundRect);
747 Control control = findImageControl ();
748 if (control != null) {
750 int right = Math.min (rect.right, width);
751 OS.SetRect (rect, rect.left, rect.top, right, rect.bottom);
752 if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0);
754 if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0);
759 rect.left += INSET - 1;
765 Image [] images = item.images;
766 if (images != null) image = images [index];
768 int inset = i != 0 ? INSET : 0;
769 int offset = i != 0 ? INSET : INSET + 2;
771 Rectangle bounds = image.getBounds (); // Points
772 if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points
773 if (!ignoreDrawForeground) {
774 //int y1 = rect.top + (index == 0 ? (getItemHeight () - size.y) / 2 : 0);
775 int y1 = rect.top + DPIUtil.autoScaleUp((getItemHeight () - size.y) / 2);
776 int x1 = Math.max (rect.left, rect.left - inset + 1);
777 GCData data = new GCData();
778 data.device = display;
779 GC gc = GC.win32_new (hDC, data);
780 gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(x1, rect.top, rect.right - x1, rect.bottom - rect.top)));
781 gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(x1), DPIUtil.autoScaleDown(y1), size.x, size.y);
782 OS.SelectClipRgn (hDC, 0);
785 OS.SetRect (rect, rect.left + DPIUtil.autoScaleUp(size.x) + offset, rect.top, rect.right - inset, rect.bottom);
788 if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) != 0) {
789 if (size == null) size = getImageSize ();
790 rect.left = Math.min (rect.left + size.x + offset, rect.right);
793 OS.SetRect (rect, rect.left + offset, rect.top, rect.right - inset, rect.bottom);
799 * Bug in Windows. When DrawText() is used with DT_VCENTER
800 * and DT_ENDELLIPSIS, the ellipsis can draw outside of the
801 * rectangle when the rectangle is empty. The fix is avoid
802 * all text drawing for empty rectangles.
804 if (rect.left < rect.right) {
805 String string = null;
809 String [] strings = item.strings;
810 if (strings != null) string = strings [index];
812 if (string != null) {
813 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
814 if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
815 if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
816 int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
817 if (i != 0) flags |= OS.DT_ENDELLIPSIS;
818 TreeColumn column = columns != null ? columns [index] : null;
819 if (column != null) {
820 if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
821 if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
823 if ((string != null) && (string.length() > Item.TEXT_LIMIT)) {
824 string = string.substring(0, Item.TEXT_LIMIT - Item.ELLIPSIS.length()) + Item.ELLIPSIS;
826 char [] buffer = string.toCharArray ();
827 if (!ignoreDrawForeground) OS.DrawText (hDC, buffer, buffer.length, rect, flags);
828 OS.DrawText (hDC, buffer, buffer.length, rect, flags | OS.DT_CALCRECT);
829 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
830 if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText);
831 if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk);
836 if (selectionForeground != -1) clrText = selectionForeground;
837 if (hooks (SWT.PaintItem)) {
838 RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
839 int nSavedDC = OS.SaveDC (hDC);
840 GCData data = new GCData ();
841 data.device = display;
842 data.font = item.getFont (index);
843 data.foreground = OS.GetTextColor (hDC);
844 data.background = OS.GetBkColor (hDC);
845 if (selected && (style & SWT.FULL_SELECTION) != 0) {
846 if (selectionForeground != -1) data.foreground = selectionForeground;
848 if (clrText != -1) data.foreground = clrText;
849 if (clrTextBk != -1) data.background = clrTextBk;
851 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
852 GC gc = GC.win32_new (hDC, data);
853 Event event = new Event ();
857 event.detail |= SWT.FOREGROUND;
858 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
859 if (hot) event.detail |= SWT.HOT;
860 if (selected && (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0)) {
861 event.detail |= SWT.SELECTED;
863 if (!explorerTheme) {
864 //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
865 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
866 if (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0) {
867 if (handle == OS.GetFocus ()) {
868 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
869 if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED;
874 event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
875 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
876 int cellWidth = cellRect.right - cellRect.left;
877 int cellHeight = cellRect.bottom - cellRect.top;
878 gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(cellRect.left, cellRect.top, cellWidth, cellHeight)));
879 sendEvent (SWT.PaintItem, event);
880 if (data.focusDrawn) focusRect = null;
883 OS.RestoreDC (hDC, nSavedDC);
884 if (isDisposed () || item.isDisposed ()) break;
888 if (x > clientRect.right) break;
891 if ((style & SWT.FULL_SELECTION) != 0) {
892 if (columnCount != 0) {
893 HDITEM hdItem = new HDITEM ();
894 hdItem.mask = OS.HDI_WIDTH;
895 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem);
896 RECT rect = new RECT ();
897 OS.SetRect (rect, nmcd.left + hdItem.cxy, nmcd.top, nmcd.right, nmcd.bottom);
898 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
901 RECT rect = new RECT ();
902 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
903 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
905 if (!ignoreDrawFocus && focusRect != null) {
906 OS.DrawFocusRect (hDC, focusRect);
909 if (!explorerTheme) {
910 if (handle == OS.GetFocus ()) {
911 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
912 if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
913 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
914 if (hItem == item.handle) {
915 if (!ignoreDrawFocus && findImageControl () != null) {
916 if ((style & SWT.FULL_SELECTION) != 0) {
917 RECT focusRect = new RECT ();
918 OS.SetRect (focusRect, 0, nmcd.top, clientRect.right + 1, nmcd.bottom);
919 OS.DrawFocusRect (hDC, focusRect);
921 int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
922 RECT focusRect = item.getBounds (index, true, false, false, false, false, hDC);
923 RECT clipRect = item.getBounds (index, true, false, false, false, true, hDC);
924 OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
925 OS.DrawFocusRect (hDC, focusRect);
926 OS.SelectClipRgn (hDC, 0);
934 return new LRESULT (OS.CDRF_DODEFAULT);
937 LRESULT CDDS_ITEMPREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
939 * Even when custom draw is being ignored, the font needs
940 * to be selected into the HDC so that the item bounds are
941 * measured correctly.
943 TreeItem item = getItem (nmcd);
945 * Feature in Windows. When a new tree item is inserted
946 * using TVM_INSERTITEM and the tree is using custom draw,
947 * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns
948 * and before the item is added to the items array. The
949 * fix is to check for null.
951 * NOTE: This only happens on XP with the version 6.00 of
954 if (item == null) return null;
956 int index = hwndHeader != 0 ? (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) : 0;
957 long hFont = item.fontHandle (index);
958 if (hFont != -1) OS.SelectObject (hDC, hFont);
959 if (ignoreCustomDraw || nmcd.left == nmcd.right) {
960 return new LRESULT (hFont == -1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT);
962 RECT clipRect = null;
963 if (columnCount != 0) {
964 clipRect = new RECT ();
965 HDITEM hdItem = new HDITEM ();
966 hdItem.mask = OS.HDI_WIDTH;
967 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
968 OS.SetRect (clipRect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
970 int clrText = -1, clrTextBk = -1;
971 if (OS.IsWindowEnabled (handle)) {
972 clrText = item.cellForeground != null ? item.cellForeground [index] : -1;
973 if (clrText == -1) clrText = item.foreground;
974 clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1;
975 if (clrTextBk == -1) clrTextBk = item.background;
978 if (OS.IsAppThemed ()) {
979 if (sortColumn != null && sortDirection != SWT.NONE) {
980 if (findImageControl () == null) {
981 if (indexOf (sortColumn) == index) {
982 clrSortBk = getSortColumnPixel ();
983 if (clrTextBk == -1) clrTextBk = clrSortBk;
988 boolean selected = isItemSelected (nmcd);
989 boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0;
990 boolean focused = explorerTheme && (nmcd.uItemState & OS.CDIS_FOCUS) != 0;
991 if (OS.IsWindowVisible (handle) && nmcd.left < nmcd.right && nmcd.top < nmcd.bottom) {
992 if (hFont != -1) OS.SelectObject (hDC, hFont);
994 RECT rect = new RECT ();
995 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
996 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
998 //TODO - BUG - measure and erase sent when first column is clipped
999 Event measureEvent = null;
1000 Rectangle boundsInPixels = null;
1001 if (hooks (SWT.MeasureItem)) {
1002 measureEvent = sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0);
1003 boundsInPixels = measureEvent.getBoundsInPixels ();
1004 if (isDisposed () || item.isDisposed ()) return null;
1006 selectionForeground = -1;
1007 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = ignoreFullSelection = false;
1008 if (hooks (SWT.EraseItem)) {
1009 RECT rect = new RECT ();
1010 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1011 RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC);
1012 if (clrSortBk != -1) {
1013 drawBackground (hDC, cellRect, clrSortBk, 0, 0);
1015 if (OS.IsWindowEnabled (handle) || findImageControl () != null) {
1016 drawBackground (hDC, rect);
1018 fillBackground (hDC, OS.GetBkColor (hDC), rect);
1021 int nSavedDC = OS.SaveDC (hDC);
1022 GCData data = new GCData ();
1023 data.device = display;
1024 if (selected && explorerTheme) {
1025 data.foreground = OS.GetSysColor (OS.COLOR_WINDOWTEXT);
1027 data.foreground = OS.GetTextColor (hDC);
1029 data.background = OS.GetBkColor (hDC);
1031 if (clrText != -1) data.foreground = clrText;
1032 if (clrTextBk != -1) data.background = clrTextBk;
1034 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1035 data.font = item.getFont (index);
1036 GC gc = GC.win32_new (hDC, data);
1037 Event event = new Event ();
1038 event.index = index;
1041 event.detail |= SWT.FOREGROUND;
1042 if (clrTextBk != -1) event.detail |= SWT.BACKGROUND;
1043 if (hot) event.detail |= SWT.HOT;
1044 if (selected) event.detail |= SWT.SELECTED;
1045 //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) {
1046 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) {
1047 if (handle == OS.GetFocus ()) {
1048 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
1049 if ((uiState & OS.UISF_HIDEFOCUS) == 0) {
1050 if (!explorerTheme || !selected) {
1052 event.detail |= SWT.FOCUSED;
1057 Rectangle boundsInPixels2 = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top);
1058 event.setBoundsInPixels (boundsInPixels2);
1059 gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels2));
1060 sendEvent (SWT.EraseItem, event);
1062 int newTextClr = data.foreground;
1064 OS.RestoreDC (hDC, nSavedDC);
1065 if (isDisposed () || item.isDisposed ()) return null;
1067 ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0;
1068 ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0;
1069 ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0;
1070 ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0;
1071 ignoreDrawHot = (event.detail & SWT.HOT) == 0;
1073 ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true;
1075 if (selected && ignoreDrawSelection) ignoreDrawHot = true;
1076 if (!ignoreDrawBackground && clrTextBk != -1) {
1077 boolean draw = !selected && !hot;
1078 if (!explorerTheme && selected) draw = !ignoreDrawSelection;
1080 if (columnCount == 0) {
1081 if ((style & SWT.FULL_SELECTION) != 0) {
1082 fillBackground (hDC, clrTextBk, rect);
1084 RECT textRect = item.getBounds (index, true, false, false, false, true, hDC);
1085 if (measureEvent != null) {
1086 textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1088 fillBackground (hDC, clrTextBk, textRect);
1091 fillBackground (hDC, clrTextBk, cellRect);
1095 if (ignoreDrawSelection) ignoreFullSelection = true;
1096 if (!ignoreDrawSelection || !ignoreDrawHot) {
1097 if (!selected && !hot) {
1098 selectionForeground = clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
1100 if (explorerTheme) {
1101 if ((style & SWT.FULL_SELECTION) == 0) {
1102 RECT pRect = item.getBounds (index, true, true, false, false, false, hDC);
1103 RECT pClipRect = item.getBounds (index, true, true, true, false, true, hDC);
1104 if (measureEvent != null) {
1105 pRect.right = Math.min (pClipRect.right, boundsInPixels.x + boundsInPixels.width);
1107 pRect.right += EXPLORER_EXTRA;
1108 pClipRect.right += EXPLORER_EXTRA;
1110 pRect.left -= EXPLORER_EXTRA;
1111 pClipRect.left -= EXPLORER_EXTRA;
1112 long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW);
1113 int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT;
1114 if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS;
1115 OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect);
1116 OS.CloseThemeData (hTheme);
1120 * Feature in Windows. When the tree has the style
1121 * TVS_FULLROWSELECT, the background color for the
1122 * entire row is filled when an item is painted,
1123 * drawing on top of any custom drawing. The fix
1124 * is to emulate TVS_FULLROWSELECT.
1126 if ((style & SWT.FULL_SELECTION) != 0) {
1127 if ((style & SWT.FULL_SELECTION) != 0 && columnCount == 0) {
1128 fillBackground (hDC, OS.GetBkColor (hDC), rect);
1130 fillBackground (hDC, OS.GetBkColor (hDC), cellRect);
1133 RECT textRect = item.getBounds (index, true, false, false, false, true, hDC);
1134 if (measureEvent != null) {
1135 textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1137 fillBackground (hDC, OS.GetBkColor (hDC), textRect);
1141 if (selected || hot) {
1142 selectionForeground = clrText = newTextClr;
1143 ignoreDrawSelection = ignoreDrawHot = true;
1145 if (explorerTheme) {
1146 nmcd.uItemState |= OS.CDIS_DISABLED;
1148 * Feature in Windows. On Vista only, when the text
1149 * color is unchanged and an item is asked to draw
1150 * disabled, it uses the disabled color. The fix is
1151 * to modify the color so that is it no longer equal.
1153 int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1154 if (nmcd.clrText == newColor) {
1155 nmcd.clrText |= 0x20000000;
1156 if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1158 nmcd.clrText = newColor;
1160 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1163 if (focused && !ignoreDrawFocus && (style & SWT.FULL_SELECTION) == 0) {
1164 RECT textRect = item.getBounds (index, true, explorerTheme, false, false, true, hDC);
1165 if (measureEvent != null) {
1166 textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width);
1168 nmcd.uItemState &= ~OS.CDIS_FOCUS;
1169 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1170 focusRect = textRect;
1172 if (explorerTheme) {
1173 if (selected || (hot && ignoreDrawHot)) nmcd.uItemState &= ~OS.CDIS_HOT;
1174 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1176 RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
1178 OS.SelectClipRgn (hDC, 0);
1179 if (explorerTheme) {
1180 itemRect.left -= EXPLORER_EXTRA;
1181 itemRect.right += EXPLORER_EXTRA;
1183 //TODO - bug in Windows selection or SWT itemRect
1184 /*if (selected)*/ itemRect.right++;
1185 if (linesVisible) itemRect.bottom++;
1186 if (clipRect != null) {
1187 OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1189 OS.ExcludeClipRect (hDC, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
1190 return new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1193 * Feature in Windows. When the tree has the style
1194 * TVS_FULLROWSELECT, the background color for the
1195 * entire row is filled when an item is painted,
1196 * drawing on top of any custom drawing. The fix
1197 * is to emulate TVS_FULLROWSELECT.
1199 if ((style & SWT.FULL_SELECTION) != 0) {
1200 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1201 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1202 RECT rect = new RECT ();
1203 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1205 fillBackground (hDC, OS.GetBkColor (hDC), rect);
1207 if (OS.IsWindowEnabled (handle)) drawBackground (hDC, rect);
1209 nmcd.uItemState &= ~OS.CDIS_FOCUS;
1210 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1214 LRESULT result = null;
1215 if (clrText == -1 && clrTextBk == -1 && hFont == -1) {
1216 result = new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT);
1218 result = new LRESULT (OS.CDRF_NEWFONT | OS.CDRF_NOTIFYPOSTPAINT);
1219 if (hFont != -1) OS.SelectObject (hDC, hFont);
1220 if (OS.IsWindowEnabled (handle) && OS.IsWindowVisible (handle)) {
1222 * Feature in Windows. Windows does not fill the entire cell
1223 * with the background color when TVS_FULLROWSELECT is not set.
1224 * The fix is to fill the cell with the background color.
1226 if (clrTextBk != -1) {
1227 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1228 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
1229 if (columnCount != 0 && hwndHeader != 0) {
1230 RECT rect = new RECT ();
1231 HDITEM hdItem = new HDITEM ();
1232 hdItem.mask = OS.HDI_WIDTH;
1233 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1234 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1235 if (!OS.IsAppThemed ()) {
1236 RECT itemRect = new RECT ();
1237 if (OS.TreeView_GetItemRect (handle, item.handle, itemRect, true)) {
1238 rect.left = Math.min (itemRect.left, rect.right);
1241 if ((style & SWT.FULL_SELECTION) != 0) {
1242 if (!selected) fillBackground (hDC, clrTextBk, rect);
1244 fillBackground (hDC, clrTextBk, rect);
1247 if ((style & SWT.FULL_SELECTION) != 0) {
1248 RECT rect = new RECT ();
1249 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1250 if (!selected) fillBackground (hDC, clrTextBk, rect);
1256 nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText;
1257 nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk;
1258 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1262 if (OS.IsWindowEnabled (handle)) {
1264 * On Vista only, when an item is asked to draw disabled,
1265 * the background of the text is not filled with the
1266 * background color of the tree. This is true for both
1267 * regular and full selection trees. In order to draw a
1268 * background image, mark the item as disabled using
1269 * CDIS_DISABLED (when not selected) and set the text
1270 * to the regular text color to avoid drawing disabled.
1272 if (explorerTheme) {
1273 if (findImageControl () != null) {
1274 if (!selected && (nmcd.uItemState & (OS.CDIS_HOT | OS.CDIS_SELECTED)) == 0) {
1275 nmcd.uItemState |= OS.CDIS_DISABLED;
1277 * Feature in Windows. On Vista only, when the text
1278 * color is unchanged and an item is asked to draw
1279 * disabled, it uses the disabled color. The fix is
1280 * to modify the color so it is no longer equal.
1282 int newColor = clrText == -1 ? getForegroundPixel () : clrText;
1283 if (nmcd.clrText == newColor) {
1284 nmcd.clrText |= 0x20000000;
1285 if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000;
1287 nmcd.clrText = newColor;
1289 OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof);
1290 if (clrTextBk != -1) {
1291 if ((style & SWT.FULL_SELECTION) != 0) {
1292 RECT rect = new RECT ();
1293 if (columnCount != 0) {
1294 HDITEM hdItem = new HDITEM ();
1295 hdItem.mask = OS.HDI_WIDTH;
1296 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1297 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1299 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1301 fillBackground (hDC, clrTextBk, rect);
1303 RECT textRect = item.getBounds (index, true, false, true, false, true, hDC);
1304 fillBackground (hDC, clrTextBk, textRect);
1312 * Feature in Windows. When the tree is disabled, it draws
1313 * with a gray background over the sort column. The fix is
1314 * to fill the background with the sort column color.
1316 if (clrSortBk != -1) {
1317 RECT rect = new RECT ();
1318 HDITEM hdItem = new HDITEM ();
1319 hdItem.mask = OS.HDI_WIDTH;
1320 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1321 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom);
1322 fillBackground (hDC, clrSortBk, rect);
1326 if (clipRect != null) {
1327 long hRgn = OS.CreateRectRgn (clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1328 POINT lpPoint = new POINT ();
1329 OS.GetWindowOrgEx (hDC, lpPoint);
1330 OS.OffsetRgn (hRgn, -lpPoint.x, -lpPoint.y);
1331 OS.SelectClipRgn (hDC, hRgn);
1332 OS.DeleteObject (hRgn);
1337 LRESULT CDDS_POSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
1338 if (ignoreCustomDraw) return null;
1339 if (OS.IsWindowVisible (handle)) {
1340 if (OS.IsAppThemed ()) {
1341 if (sortColumn != null && sortDirection != SWT.NONE) {
1342 if (findImageControl () == null) {
1343 int index = indexOf (sortColumn);
1347 * Bug in Windows. For some reason, during a collapse,
1348 * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1349 * and the collapse causes the item being collapsed
1350 * to become the last visible item in the tree, the
1351 * message takes a long time to process. In order for
1352 * the slowness to happen, the children of the item
1353 * must have children. Times of up to 11 seconds have
1354 * been observed with 23 children, each having one
1355 * child. The fix is to use the bottom partially
1356 * visible item rather than the last possible item
1357 * that could be visible.
1359 * NOTE: This problem only happens on Vista during
1360 * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1363 if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1364 hItem = getBottomItem ();
1366 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1369 RECT rect = new RECT ();
1370 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
1374 RECT rect = new RECT ();
1375 OS.SetRect (rect, nmcd.left, top, nmcd.right, nmcd.bottom);
1376 RECT headerRect = new RECT ();
1377 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
1378 rect.left = headerRect.left;
1379 rect.right = headerRect.right;
1380 fillBackground (nmcd.hdc, getSortColumnPixel (), rect);
1386 long hDC = nmcd.hdc;
1387 if (hwndHeader != 0) {
1389 RECT rect = new RECT ();
1390 HDITEM hdItem = new HDITEM ();
1391 hdItem.mask = OS.HDI_WIDTH;
1392 for (int i=0; i<columnCount; i++) {
1393 int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, i, 0);
1394 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
1395 OS.SetRect (rect, x, nmcd.top, x + hdItem.cxy, nmcd.bottom);
1396 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_RIGHT);
1401 RECT rect = new RECT ();
1403 * Bug in Windows. For some reason, during a collapse,
1404 * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE
1405 * and the collapse causes the item being collapsed
1406 * to become the last visible item in the tree, the
1407 * message takes a long time to process. In order for
1408 * the slowness to happen, the children of the item
1409 * must have children. Times of up to 11 seconds have
1410 * been observed with 23 children, each having one
1411 * child. The fix is to use the bottom partially
1412 * visible item rather than the last possible item
1413 * that could be visible.
1415 * NOTE: This problem only happens on Vista during
1416 * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT.
1419 if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
1420 hItem = getBottomItem ();
1422 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
1425 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
1426 height = rect.bottom - rect.top;
1430 height = (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
1431 OS.GetClientRect (handle, rect);
1432 OS.SetRect (rect, rect.left, rect.top, rect.right, rect.top + height);
1433 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1436 while (rect.bottom < nmcd.bottom) {
1437 int top = rect.top + height;
1438 OS.SetRect (rect, rect.left, top, rect.right, top + height);
1439 OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM);
1444 return new LRESULT (OS.CDRF_DODEFAULT);
1447 LRESULT CDDS_PREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
1448 if (explorerTheme) {
1449 if ((OS.IsWindowEnabled (handle) && hooks (SWT.EraseItem)) || hasCustomBackground() || findImageControl () != null) {
1450 RECT rect = new RECT ();
1451 OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1452 drawBackground (nmcd.hdc, rect);
1455 return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT);
1459 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
1460 if (handle == 0) return 0;
1461 if (hwndParent != 0 && hwnd == hwndParent) {
1462 return OS.DefWindowProc (hwnd, msg, wParam, lParam);
1464 if (hwndHeader != 0 && hwnd == hwndHeader) {
1465 return OS.CallWindowProc (HeaderProc, hwnd, msg, wParam, lParam);
1468 case OS.WM_SETFOCUS: {
1470 * Feature in Windows. When a tree control processes WM_SETFOCUS,
1471 * if no item is selected, the first item in the tree is selected.
1472 * This is unexpected and might clear the previous selection.
1473 * The fix is to detect that there is no selection and set it to
1474 * the first visible item in the tree. If the item was not selected,
1475 * only the focus is assigned.
1477 if ((style & SWT.SINGLE) != 0) break;
1478 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
1480 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1482 TVITEM tvItem = new TVITEM ();
1483 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
1484 tvItem.hItem = hItem;
1485 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
1487 ignoreDeselect = ignoreSelect = lockSelection = true;
1488 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem);
1489 ignoreDeselect = ignoreSelect = lockSelection = false;
1491 if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
1492 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1500 boolean redraw = false;
1502 /* Keyboard messages */
1504 if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1507 case OS.WM_IME_CHAR:
1510 case OS.WM_SYSKEYDOWN:
1511 case OS.WM_SYSKEYUP:
1514 /* Scroll messages */
1519 /* Resize messages */
1521 redraw = findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle);
1522 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
1525 /* Mouse messages */
1526 case OS.WM_LBUTTONDBLCLK:
1527 case OS.WM_LBUTTONDOWN:
1528 case OS.WM_LBUTTONUP:
1529 case OS.WM_MBUTTONDBLCLK:
1530 case OS.WM_MBUTTONDOWN:
1531 case OS.WM_MBUTTONUP:
1532 case OS.WM_MOUSEHOVER:
1533 case OS.WM_MOUSELEAVE:
1534 case OS.WM_MOUSEMOVE:
1535 case OS.WM_MOUSEWHEEL:
1536 case OS.WM_RBUTTONDBLCLK:
1537 case OS.WM_RBUTTONDOWN:
1538 case OS.WM_RBUTTONUP:
1539 case OS.WM_XBUTTONDBLCLK:
1540 case OS.WM_XBUTTONDOWN:
1541 case OS.WM_XBUTTONUP:
1544 /* Other messages */
1547 if (findImageControl () != null) {
1548 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1554 long code = OS.CallWindowProc (TreeProc, hwnd, msg, wParam, lParam);
1556 /* Keyboard messages */
1558 if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break;
1561 case OS.WM_IME_CHAR:
1564 case OS.WM_SYSKEYDOWN:
1565 case OS.WM_SYSKEYUP:
1568 /* Scroll messages */
1573 /* Resize messages */
1576 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
1577 OS.InvalidateRect (handle, null, true);
1578 if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
1582 /* Mouse messages */
1583 case OS.WM_LBUTTONDBLCLK:
1584 case OS.WM_LBUTTONDOWN:
1585 case OS.WM_LBUTTONUP:
1586 case OS.WM_MBUTTONDBLCLK:
1587 case OS.WM_MBUTTONDOWN:
1588 case OS.WM_MBUTTONUP:
1589 case OS.WM_MOUSEHOVER:
1590 case OS.WM_MOUSELEAVE:
1591 case OS.WM_MOUSEMOVE:
1592 case OS.WM_MOUSEWHEEL:
1593 case OS.WM_RBUTTONDBLCLK:
1594 case OS.WM_RBUTTONDOWN:
1595 case OS.WM_RBUTTONUP:
1596 case OS.WM_XBUTTONDBLCLK:
1597 case OS.WM_XBUTTONDOWN:
1598 case OS.WM_XBUTTONUP:
1601 /* Other messages */
1604 if (findImageControl () != null) {
1605 if (hItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) {
1606 OS.InvalidateRect (handle, null, true);
1621 void checkBuffered () {
1622 super.checkBuffered ();
1623 if ((style & SWT.VIRTUAL) != 0) {
1624 style |= SWT.DOUBLE_BUFFERED;
1625 OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0);
1627 if (OS.IsAppThemed ()) {
1628 int exStyle = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
1629 if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) style |= SWT.DOUBLE_BUFFERED;
1633 boolean checkData (TreeItem item, boolean redraw) {
1634 if ((style & SWT.VIRTUAL) == 0) return true;
1636 TreeItem parentItem = item.getParentItem ();
1637 return checkData (item, parentItem == null ? indexOf (item) : parentItem.indexOf (item), redraw);
1642 boolean checkData (TreeItem item, int index, boolean redraw) {
1643 if ((style & SWT.VIRTUAL) == 0) return true;
1646 Event event = new Event ();
1648 event.index = index;
1649 TreeItem oldItem = currentItem;
1652 * Bug in Windows. If the tree scrolls during WM_NOTIFY
1653 * with TVN_GETDISPINFO, pixel corruption occurs. The fix
1654 * is to detect that the top item has changed and redraw
1657 long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
1658 sendEvent (SWT.SetData, event);
1659 //widget could be disposed at this point
1660 currentItem = oldItem;
1661 if (isDisposed () || item.isDisposed ()) return false;
1662 if (redraw) item.redraw ();
1663 if (hTopItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) {
1664 OS.InvalidateRect (handle, null, true);
1671 boolean checkHandle (long hwnd) {
1672 return hwnd == handle || (hwndParent != 0 && hwnd == hwndParent) || (hwndHeader != 0 && hwnd == hwndHeader);
1675 boolean checkScroll (long hItem) {
1677 * Feature in Windows. If redraw is turned off using WM_SETREDRAW
1678 * and a tree item that is not a child of the first root is selected or
1679 * scrolled using TVM_SELECTITEM or TVM_ENSUREVISIBLE, then scrolling
1680 * does not occur. The fix is to detect this case, and make sure
1681 * that redraw is temporarily enabled. To avoid flashing, DefWindowProc()
1682 * is called to disable redrawing.
1684 * NOTE: The code that actually works around the problem is in the
1685 * callers of this method.
1687 if (getDrawing ()) return false;
1688 long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1689 long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
1690 while (hParent != hRoot && hParent != 0) {
1691 hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hParent);
1693 return hParent == 0;
1697 protected void checkSubclass () {
1698 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
1702 * Clears the item at the given zero-relative index in the receiver.
1703 * The text, icon and other attributes of the item are set to the default
1704 * value. If the tree was created with the <code>SWT.VIRTUAL</code> style,
1705 * these attributes are requested again as needed.
1707 * @param index the index of the item to clear
1708 * @param all <code>true</code> if all child items of the indexed item should be
1709 * cleared recursively, and <code>false</code> otherwise
1711 * @exception IllegalArgumentException <ul>
1712 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1714 * @exception SWTException <ul>
1715 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1716 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1724 public void clear (int index, boolean all) {
1726 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1727 if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1728 hItem = findItem (hItem, index);
1729 if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
1730 TVITEM tvItem = new TVITEM ();
1731 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1732 clear (hItem, tvItem);
1734 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1735 clearAll (hItem, tvItem, all);
1739 void clear (long hItem, TVITEM tvItem) {
1740 tvItem.hItem = hItem;
1741 TreeItem item = null;
1742 if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
1743 item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null;
1746 if ((style & SWT.VIRTUAL) != 0 && !item.cached) return;
1753 * Clears all the items in the receiver. The text, icon and other
1754 * attributes of the items are set to their default values. If the
1755 * tree was created with the <code>SWT.VIRTUAL</code> style, these
1756 * attributes are requested again as needed.
1758 * @param all <code>true</code> if all child items should be cleared
1759 * recursively, and <code>false</code> otherwise
1761 * @exception SWTException <ul>
1762 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1763 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1771 public void clearAll (boolean all) {
1773 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1774 if (hItem == 0) return;
1776 boolean redraw = false;
1777 for (int i=0; i<items.length; i++) {
1778 TreeItem item = items [i];
1779 if (item != null && item != currentItem) {
1784 if (redraw) OS.InvalidateRect (handle, null, true);
1786 TVITEM tvItem = new TVITEM ();
1787 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
1788 clearAll (hItem, tvItem, all);
1792 void clearAll (long hItem, TVITEM tvItem, boolean all) {
1793 while (hItem != 0) {
1794 clear (hItem, tvItem);
1796 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
1797 clearAll (hFirstItem, tvItem, all);
1799 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
1803 long CompareFunc (long lParam1, long lParam2, long lParamSort) {
1804 TreeItem item1 = items [(int)lParam1], item2 = items [(int)lParam2];
1805 String text1 = item1.getText ((int)lParamSort), text2 = item2.getText ((int)lParamSort);
1806 return sortDirection == SWT.UP ? text1.compareTo (text2) : text2.compareTo (text1);
1809 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
1810 int width = 0, height = 0;
1811 if (hwndHeader != 0) {
1812 HDITEM hdItem = new HDITEM ();
1813 hdItem.mask = OS.HDI_WIDTH;
1814 for (int i=0; i<columnCount; i++) {
1815 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
1816 width += hdItem.cxy;
1818 RECT rect = new RECT ();
1819 OS.GetWindowRect (hwndHeader, rect);
1820 height += rect.bottom - rect.top;
1822 RECT rect = new RECT ();
1823 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
1824 while (hItem != 0) {
1825 if ((style & SWT.VIRTUAL) == 0 && !painted) {
1826 TVITEM tvItem = new TVITEM ();
1827 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_TEXT;
1828 tvItem.hItem = hItem;
1829 tvItem.pszText = OS.LPSTR_TEXTCALLBACK;
1830 ignoreCustomDraw = true;
1831 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
1832 ignoreCustomDraw = false;
1834 if (OS.TreeView_GetItemRect (handle, hItem, rect, true)) {
1835 width = Math.max (width, rect.right);
1836 height += rect.bottom - rect.top;
1838 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
1840 if (width == 0) width = DEFAULT_WIDTH;
1841 if (height == 0) height = DEFAULT_HEIGHT;
1842 if (wHint != SWT.DEFAULT) width = wHint;
1843 if (hHint != SWT.DEFAULT) height = hHint;
1844 int border = getBorderWidthInPixels ();
1845 width += border * 2;
1846 height += border * 2;
1847 if ((style & SWT.V_SCROLL) != 0) {
1848 width += OS.GetSystemMetrics (OS.SM_CXVSCROLL);
1850 if ((style & SWT.H_SCROLL) != 0) {
1851 height += OS.GetSystemMetrics (OS.SM_CYHSCROLL);
1853 return new Point (width, height);
1857 void createHandle () {
1858 super.createHandle ();
1859 state &= ~(CANVAS | THEME_BACKGROUND);
1861 /* Use the Explorer theme */
1862 if (OS.IsAppThemed ()) {
1863 explorerTheme = true;
1864 OS.SetWindowTheme (handle, Display.EXPLORER, null);
1865 int bits = OS.TVS_EX_DOUBLEBUFFER | OS.TVS_EX_RICHTOOLTIP;
1866 if (ENABLE_TVS_EX_FADEINOUTEXPANDOS) bits |= OS.TVS_EX_FADEINOUTEXPANDOS;
1868 * This code is intentionally commented.
1870 // if ((style & SWT.FULL_SELECTION) == 0) bits |= OS.TVS_EX_AUTOHSCROLL;
1871 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits);
1873 * Bug in Windows. When the tree is using the explorer
1874 * theme, it does not use COLOR_WINDOW_TEXT for the
1875 * default foreground color. The fix is to explicitly
1876 * set the foreground.
1878 setForegroundPixel (-1);
1881 /* Set the checkbox image list */
1882 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
1885 * Feature in Windows. When the control is created,
1886 * it does not use the default system font. A new HFONT
1887 * is created and destroyed when the control is destroyed.
1888 * This means that a program that queries the font from
1889 * this control, uses the font in another control and then
1890 * destroys this control will have the font unexpectedly
1891 * destroyed in the other control. The fix is to assign
1892 * the font ourselves each time the control is created.
1893 * The control will not destroy a font that it did not
1896 long hFont = OS.GetStockObject (OS.SYSTEM_FONT);
1897 OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
1900 * Bug in Windows. When image list is not set, tree glyph
1901 * size is tied to tree indent. Indent doesn't automatically
1902 * scale with DPI resulting in distorted glyph image
1903 * at higher DPI settings.
1905 int indent = DPIUtil.autoScaleUpUsingNativeDPI(16);
1906 OS.SendMessage(handle, OS.TVM_SETINDENT, indent, 0);
1908 createdAsRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
1911 void createHeaderToolTips () {
1912 if (headerToolTipHandle != 0) return;
1914 if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
1915 headerToolTipHandle = OS.CreateWindowEx (
1917 new TCHAR (0, OS.TOOLTIPS_CLASS, true),
1920 OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
1923 OS.GetModuleHandle (null),
1925 if (headerToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
1927 * Feature in Windows. Despite the fact that the
1928 * tool tip text contains \r\n, the tooltip will
1929 * not honour the new line unless TTM_SETMAXTIPWIDTH
1930 * is set. The fix is to set TTM_SETMAXTIPWIDTH to
1933 OS.SendMessage (headerToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
1936 void createItem (TreeColumn column, int index) {
1937 if (hwndHeader == 0) createParent ();
1938 if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
1939 if (columnCount == columns.length) {
1940 TreeColumn [] newColumns = new TreeColumn [columns.length + 4];
1941 System.arraycopy (columns, 0, newColumns, 0, columns.length);
1942 columns = newColumns;
1944 for (int i=0; i<items.length; i++) {
1945 TreeItem item = items [i];
1947 String [] strings = item.strings;
1948 if (strings != null) {
1949 String [] temp = new String [columnCount + 1];
1950 System.arraycopy (strings, 0, temp, 0, index);
1951 System.arraycopy (strings, index, temp, index + 1, columnCount - index);
1952 item.strings = temp;
1954 Image [] images = item.images;
1955 if (images != null) {
1956 Image [] temp = new Image [columnCount + 1];
1957 System.arraycopy (images, 0, temp, 0, index);
1958 System.arraycopy (images, index, temp, index + 1, columnCount - index);
1962 if (columnCount != 0) {
1963 if (strings == null) {
1964 item.strings = new String [columnCount + 1];
1965 item.strings [1] = item.text;
1968 if (images == null) {
1969 item.images = new Image [columnCount + 1];
1970 item.images [1] = item.image;
1975 if (item.cellBackground != null) {
1976 int [] cellBackground = item.cellBackground;
1977 int [] temp = new int [columnCount + 1];
1978 System.arraycopy (cellBackground, 0, temp, 0, index);
1979 System.arraycopy (cellBackground, index, temp, index + 1, columnCount - index);
1981 item.cellBackground = temp;
1983 if (item.cellForeground != null) {
1984 int [] cellForeground = item.cellForeground;
1985 int [] temp = new int [columnCount + 1];
1986 System.arraycopy (cellForeground, 0, temp, 0, index);
1987 System.arraycopy (cellForeground, index, temp, index + 1, columnCount - index);
1989 item.cellForeground = temp;
1991 if (item.cellFont != null) {
1992 Font [] cellFont = item.cellFont;
1993 Font [] temp = new Font [columnCount + 1];
1994 System.arraycopy (cellFont, 0, temp, 0, index);
1995 System.arraycopy (cellFont, index, temp, index + 1, columnCount- index);
1996 item.cellFont = temp;
2000 System.arraycopy (columns, index, columns, index + 1, columnCount++ - index);
2001 columns [index] = column;
2004 * Bug in Windows. For some reason, when HDM_INSERTITEM
2005 * is used to insert an item into a header without text,
2006 * if is not possible to set the text at a later time.
2007 * The fix is to insert the item with an empty string.
2009 long hHeap = OS.GetProcessHeap ();
2010 long pszText = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, TCHAR.sizeof);
2011 HDITEM hdItem = new HDITEM ();
2012 hdItem.mask = OS.HDI_TEXT | OS.HDI_FORMAT;
2013 hdItem.pszText = pszText;
2014 if ((column.style & SWT.LEFT) == SWT.LEFT) hdItem.fmt = OS.HDF_LEFT;
2015 if ((column.style & SWT.CENTER) == SWT.CENTER) hdItem.fmt = OS.HDF_CENTER;
2016 if ((column.style & SWT.RIGHT) == SWT.RIGHT) hdItem.fmt = OS.HDF_RIGHT;
2017 OS.SendMessage (hwndHeader, OS.HDM_INSERTITEM, index, hdItem);
2018 if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
2020 /* When the first column is created, hide the horizontal scroll bar */
2021 if (columnCount == 1) {
2023 if ((style & SWT.H_SCROLL) != 0) {
2024 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2025 bits |= OS.TVS_NOHSCROLL;
2026 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2029 * Bug in Windows. When TVS_NOHSCROLL is set after items
2030 * have been inserted into the tree, Windows shows the
2031 * scroll bar. The fix is to check for this case and
2032 * explicitly hide the scroll bar explicitly.
2034 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
2036 OS.ShowScrollBar (handle, OS.SB_HORZ, false);
2038 createItemToolTips ();
2039 if (itemToolTipHandle != 0) {
2040 OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_AUTOMATIC, -1);
2047 /* Redraw to hide the items when the first column is created */
2048 if (columnCount == 1 && OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) != 0) {
2049 OS.InvalidateRect (handle, null, true);
2052 /* Add the tool tip item for the header */
2053 if (headerToolTipHandle != 0) {
2054 RECT rect = new RECT ();
2055 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, rect) != 0) {
2056 TOOLINFO lpti = new TOOLINFO ();
2057 lpti.cbSize = TOOLINFO.sizeof;
2058 lpti.uFlags = OS.TTF_SUBCLASS;
2059 lpti.hwnd = hwndHeader;
2060 lpti.uId = column.id = display.nextToolTipId++;
2061 lpti.left = rect.left;
2062 lpti.top = rect.top;
2063 lpti.right = rect.right;
2064 lpti.bottom = rect.bottom;
2065 lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2066 OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2071 // For fast bulk insert, see comments for TreeItem#TreeItem(TreeItem,int,int)
2072 void createItem (TreeItem item, long hParent, long hInsertAfter, long hItem) {
2075 id = lastID < items.length ? lastID : 0;
2076 while (id < items.length && items [id] != null) id++;
2077 if (id == items.length) {
2079 * Grow the array faster when redraw is off or the
2080 * table is not visible. When the table is painted,
2081 * the items array is resized to be smaller to reduce
2085 if (getDrawing () && OS.IsWindowVisible (handle)) {
2086 length = items.length + 4;
2089 length = Math.max (4, items.length * 3 / 2);
2091 TreeItem [] newItems = new TreeItem [length];
2092 System.arraycopy (items, 0, newItems, 0, items.length);
2098 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent);
2099 boolean fixParent = hFirstItem == 0;
2101 TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
2102 tvInsert.hParent = hParent;
2103 tvInsert.hInsertAfter = hInsertAfter;
2104 tvInsert.lParam = id;
2105 tvInsert.pszText = OS.LPSTR_TEXTCALLBACK;
2106 tvInsert.iImage = tvInsert.iSelectedImage = OS.I_IMAGECALLBACK;
2107 tvInsert.mask = OS.TVIF_TEXT | OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE | OS.TVIF_HANDLE | OS.TVIF_PARAM;
2108 if ((style & SWT.CHECK) != 0) {
2109 tvInsert.mask = tvInsert.mask | OS.TVIF_STATE;
2110 tvInsert.state = 1 << 12;
2111 tvInsert.stateMask = OS.TVIS_STATEIMAGEMASK;
2113 ignoreCustomDraw = true;
2114 hNewItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
2115 ignoreCustomDraw = false;
2116 if (hNewItem == 0) error (SWT.ERROR_ITEM_NOT_ADDED);
2118 * This code is intentionally commented.
2120 // if (hParent != 0) {
2121 // int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2122 // bits |= OS.TVS_LINESATROOT;
2123 // OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2126 TVITEM tvItem = new TVITEM ();
2127 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
2128 tvItem.hItem = hNewItem = hItem;
2130 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2133 item.handle = hNewItem;
2136 if (hFirstItem == 0) {
2137 if (hInsertAfter == OS.TVI_FIRST || hInsertAfter == OS.TVI_LAST) {
2138 hFirstIndexOf = hLastIndexOf = hFirstItem = hNewItem;
2139 itemCount = lastIndexOf = 0;
2142 if (hFirstItem == hFirstIndexOf && itemCount != -1) itemCount++;
2145 * Bug in Windows. When a child item is added to a parent item
2146 * that has no children outside of WM_NOTIFY with control code
2147 * TVN_ITEMEXPANDED, the tree widget does not redraw the +/-
2148 * indicator. The fix is to detect the case when the first
2149 * child is added to a visible parent item and redraw the parent.
2152 if (getDrawing () && OS.IsWindowVisible (handle)) {
2153 RECT rect = new RECT ();
2154 if (OS.TreeView_GetItemRect (handle, hParent, rect, false)) {
2155 OS.InvalidateRect (handle, rect, true);
2160 * Bug in Windows. When a new item is added while Windows
2161 * is requesting data a tree item using TVN_GETDISPINFO,
2162 * outstanding damage for items that are below the new item
2163 * is not scrolled. The fix is to explicitly damage the
2166 if ((style & SWT.VIRTUAL) != 0) {
2167 if (currentItem != null) {
2168 RECT rect = new RECT ();
2169 if (OS.TreeView_GetItemRect (handle, hNewItem, rect, false)) {
2170 RECT damageRect = new RECT ();
2171 boolean damaged = OS.GetUpdateRect (handle, damageRect, true);
2172 if (damaged && damageRect.top < rect.bottom) {
2173 long rgn = OS.CreateRectRgn (0, 0, 0, 0);
2174 int result = OS.GetUpdateRgn (handle, rgn, true);
2175 if (result != OS.NULLREGION) {
2176 OS.OffsetRgn (rgn, 0, rect.bottom - rect.top);
2177 OS.InvalidateRgn (handle, rgn, true);
2179 OS.DeleteObject (rgn);
2186 Note: Don't update scrollbars when drawing is disabled.
2187 This gives significant improvement for bulk insert scenarios.
2188 Later, setRedraw(true) will update scrollbars once.
2190 if (getDrawing ()) updateScrollBar ();
2194 void createItemToolTips () {
2195 if (itemToolTipHandle != 0) return;
2196 int bits1 = OS.GetWindowLong (handle, OS.GWL_STYLE);
2197 bits1 |= OS.TVS_NOTOOLTIPS;
2198 OS.SetWindowLong (handle, OS.GWL_STYLE, bits1);
2200 if ((style & SWT.RIGHT_TO_LEFT) != 0) bits2 |= OS.WS_EX_LAYOUTRTL;
2202 * Feature in Windows. For some reason, when the user
2203 * clicks on a tool tip, it temporarily takes focus, even
2204 * when WS_EX_NOACTIVATE is specified. The fix is to
2205 * use WS_EX_TRANSPARENT, even though WS_EX_TRANSPARENT
2206 * is documented to affect painting, not hit testing.
2208 bits2 |= OS.WS_EX_TRANSPARENT;
2209 itemToolTipHandle = OS.CreateWindowEx (
2211 new TCHAR (0, OS.TOOLTIPS_CLASS, true),
2213 OS.TTS_NOPREFIX | OS.TTS_NOANIMATE | OS.TTS_NOFADE,
2214 OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
2217 OS.GetModuleHandle (null),
2219 if (itemToolTipHandle == 0) error (SWT.ERROR_NO_HANDLES);
2220 OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_INITIAL, 0);
2222 * Feature in Windows. Despite the fact that the
2223 * tool tip text contains \r\n, the tooltip will
2224 * not honour the new line unless TTM_SETMAXTIPWIDTH
2225 * is set. The fix is to set TTM_SETMAXTIPWIDTH to
2228 OS.SendMessage (itemToolTipHandle, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
2229 TOOLINFO lpti = new TOOLINFO ();
2230 lpti.cbSize = TOOLINFO.sizeof;
2233 lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
2234 lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
2235 OS.SendMessage (itemToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
2238 void createParent () {
2240 RECT rect = new RECT ();
2241 OS.GetWindowRect (handle, rect);
2242 OS.MapWindowPoints (0, parent.handle, rect, 2);
2243 int oldStyle = OS.GetWindowLong (handle, OS.GWL_STYLE);
2244 int newStyle = super.widgetStyle () & ~OS.WS_VISIBLE;
2245 if ((oldStyle & OS.WS_DISABLED) != 0) newStyle |= OS.WS_DISABLED;
2246 // if ((oldStyle & OS.WS_VISIBLE) != 0) newStyle |= OS.WS_VISIBLE;
2247 hwndParent = OS.CreateWindowEx (
2248 super.widgetExtStyle (),
2249 super.windowClass (),
2254 rect.right - rect.left,
2255 rect.bottom - rect.top,
2258 OS.GetModuleHandle (null),
2260 if (hwndParent == 0) error (SWT.ERROR_NO_HANDLES);
2261 OS.SetWindowLongPtr (hwndParent, OS.GWLP_ID, hwndParent);
2262 int bits = OS.WS_EX_NOINHERITLAYOUT;
2263 if ((style & SWT.RIGHT_TO_LEFT) != 0) bits |= OS.WS_EX_LAYOUTRTL;
2264 hwndHeader = OS.CreateWindowEx (
2268 OS.HDS_BUTTONS | OS.HDS_FULLDRAG | OS.HDS_DRAGDROP | OS.HDS_HIDDEN | OS.WS_CHILD | OS.WS_CLIPSIBLINGS,
2272 OS.GetModuleHandle (null),
2274 if (hwndHeader == 0) error (SWT.ERROR_NO_HANDLES);
2275 OS.SetWindowLongPtr (hwndHeader, OS.GWLP_ID, hwndHeader);
2276 if (OS.IsDBLocale) {
2277 long hIMC = OS.ImmGetContext (handle);
2278 OS.ImmAssociateContext (hwndParent, hIMC);
2279 OS.ImmAssociateContext (hwndHeader, hIMC);
2280 OS.ImmReleaseContext (handle, hIMC);
2282 //This code is intentionally commented
2284 // if ((style & SWT.BORDER) != 0) {
2285 // int oldExStyle = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
2286 // oldExStyle &= ~OS.WS_EX_CLIENTEDGE;
2287 // OS.SetWindowLong (handle, OS.GWL_EXSTYLE, oldExStyle);
2290 long hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
2291 if (hFont != 0) OS.SendMessage (hwndHeader, OS.WM_SETFONT, hFont, 0);
2292 long hwndInsertAfter = OS.GetWindow (handle, OS.GW_HWNDPREV);
2293 int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
2294 OS.SetWindowPos (hwndParent, hwndInsertAfter, 0, 0, 0, 0, flags);
2295 SCROLLINFO info = new SCROLLINFO ();
2296 info.cbSize = SCROLLINFO.sizeof;
2297 info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
2298 OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
2299 info.nPage = info.nMax + 1;
2300 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
2301 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
2302 info.nPage = info.nMax + 1;
2303 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
2306 if ((oldStyle & OS.WS_VISIBLE) != 0) {
2307 OS.ShowWindow (hwndParent, OS.SW_SHOW);
2309 long hwndFocus = OS.GetFocus ();
2310 if (hwndFocus == handle) OS.SetFocus (hwndParent);
2311 OS.SetParent (handle, hwndParent);
2312 if (hwndFocus == handle) OS.SetFocus (handle);
2318 void createWidget () {
2319 super.createWidget ();
2320 items = new TreeItem [4];
2321 columns = new TreeColumn [4];
2325 private boolean customHeaderDrawing() {
2326 return headerBackground != -1 || headerForeground != -1;
2330 int defaultBackground () {
2331 return OS.GetSysColor (OS.COLOR_WINDOW);
2335 void deregister () {
2336 super.deregister ();
2337 if (hwndParent != 0) display.removeControl (hwndParent);
2338 if (hwndHeader != 0) display.removeControl (hwndHeader);
2341 void deselect (long hItem, TVITEM tvItem, long hIgnoreItem) {
2342 while (hItem != 0) {
2343 if (hItem != hIgnoreItem) {
2344 tvItem.hItem = hItem;
2345 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2347 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
2348 deselect (hFirstItem, tvItem, hIgnoreItem);
2349 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
2354 * Deselects an item in the receiver. If the item was already
2355 * deselected, it remains deselected.
2357 * @param item the item to be deselected
2359 * @exception IllegalArgumentException <ul>
2360 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
2361 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
2363 * @exception SWTException <ul>
2364 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2365 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2370 public void deselect (TreeItem item) {
2372 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
2373 if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
2374 TVITEM tvItem = new TVITEM ();
2375 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
2376 tvItem.stateMask = OS.TVIS_SELECTED;
2377 tvItem.hItem = item.handle;
2378 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2382 * Deselects all selected items in the receiver.
2384 * @exception SWTException <ul>
2385 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2386 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2389 public void deselectAll () {
2391 TVITEM tvItem = new TVITEM ();
2392 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
2393 tvItem.stateMask = OS.TVIS_SELECTED;
2394 if ((style & SWT.SINGLE) != 0) {
2395 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2397 tvItem.hItem = hItem;
2398 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2401 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
2402 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
2403 if ((style & SWT.VIRTUAL) != 0) {
2404 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
2405 deselect (hItem, tvItem, 0);
2407 for (int i=0; i<items.length; i++) {
2408 TreeItem item = items [i];
2410 tvItem.hItem = item.handle;
2411 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
2415 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
2419 void destroyItem (TreeColumn column) {
2420 if (hwndHeader == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
2422 while (index < columnCount) {
2423 if (columns [index] == column) break;
2426 int [] oldOrder = new int [columnCount];
2427 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder);
2429 while (orderIndex < columnCount) {
2430 if (oldOrder [orderIndex] == index) break;
2433 RECT headerRect = new RECT ();
2434 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
2435 if (OS.SendMessage (hwndHeader, OS.HDM_DELETEITEM, index, 0) == 0) {
2436 error (SWT.ERROR_ITEM_NOT_REMOVED);
2438 System.arraycopy (columns, index + 1, columns, index, --columnCount - index);
2439 columns [columnCount] = null;
2440 for (int i=0; i<items.length; i++) {
2441 TreeItem item = items [i];
2443 if (columnCount == 0) {
2444 item.strings = null;
2446 item.cellBackground = null;
2447 item.cellForeground = null;
2448 item.cellFont = null;
2450 if (item.strings != null) {
2451 String [] strings = item.strings;
2453 item.text = strings [1] != null ? strings [1] : "";
2455 String [] temp = new String [columnCount];
2456 System.arraycopy (strings, 0, temp, 0, index);
2457 System.arraycopy (strings, index + 1, temp, index, columnCount - index);
2458 item.strings = temp;
2460 if (index == 0) item.text = "";
2462 if (item.images != null) {
2463 Image [] images = item.images;
2464 if (index == 0) item.image = images [1];
2465 Image [] temp = new Image [columnCount];
2466 System.arraycopy (images, 0, temp, 0, index);
2467 System.arraycopy (images, index + 1, temp, index, columnCount - index);
2470 if (index == 0) item.image = null;
2472 if (item.cellBackground != null) {
2473 int [] cellBackground = item.cellBackground;
2474 int [] temp = new int [columnCount];
2475 System.arraycopy (cellBackground, 0, temp, 0, index);
2476 System.arraycopy (cellBackground, index + 1, temp, index, columnCount - index);
2477 item.cellBackground = temp;
2479 if (item.cellForeground != null) {
2480 int [] cellForeground = item.cellForeground;
2481 int [] temp = new int [columnCount];
2482 System.arraycopy (cellForeground, 0, temp, 0, index);
2483 System.arraycopy (cellForeground, index + 1, temp, index, columnCount - index);
2484 item.cellForeground = temp;
2486 if (item.cellFont != null) {
2487 Font [] cellFont = item.cellFont;
2488 Font [] temp = new Font [columnCount];
2489 System.arraycopy (cellFont, 0, temp, 0, index);
2490 System.arraycopy (cellFont, index + 1, temp, index, columnCount - index);
2491 item.cellFont = temp;
2498 * When the last column is deleted, show the horizontal
2499 * scroll bar. Otherwise, left align the first column
2500 * and redraw the columns to the right.
2502 if (columnCount == 0) {
2504 if (!hooks (SWT.MeasureItem)) {
2505 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2506 if ((style & SWT.H_SCROLL) != 0) bits &= ~OS.TVS_NOHSCROLL;
2507 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2508 OS.InvalidateRect (handle, null, true);
2510 if (itemToolTipHandle != 0) {
2511 OS.SendMessage (itemToolTipHandle, OS.TTM_SETDELAYTIME, OS.TTDT_INITIAL, 0);
2515 columns [0].style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER);
2516 columns [0].style |= SWT.LEFT;
2517 HDITEM hdItem = new HDITEM ();
2518 hdItem.mask = OS.HDI_FORMAT | OS.HDI_IMAGE;
2519 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem);
2520 hdItem.fmt &= ~OS.HDF_JUSTIFYMASK;
2521 hdItem.fmt |= OS.HDF_LEFT;
2522 OS.SendMessage (hwndHeader, OS.HDM_SETITEM, index, hdItem);
2524 RECT rect = new RECT ();
2525 OS.GetClientRect (handle, rect);
2526 rect.left = headerRect.left;
2527 OS.InvalidateRect (handle, rect, true);
2532 if (columnCount != 0) {
2533 int [] newOrder = new int [columnCount];
2534 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, newOrder);
2535 TreeColumn [] newColumns = new TreeColumn [columnCount - orderIndex];
2536 for (int i=orderIndex; i<newOrder.length; i++) {
2537 newColumns [i - orderIndex] = columns [newOrder [i]];
2538 newColumns [i - orderIndex].updateToolTip (newOrder [i]);
2540 for (int i=0; i<newColumns.length; i++) {
2541 if (!newColumns [i].isDisposed ()) {
2542 newColumns [i].sendEvent (SWT.Move);
2547 /* Remove the tool tip item for the header */
2548 if (headerToolTipHandle != 0) {
2549 TOOLINFO lpti = new TOOLINFO ();
2550 lpti.cbSize = TOOLINFO.sizeof;
2551 lpti.uId = column.id;
2552 lpti.hwnd = hwndHeader;
2553 OS.SendMessage (headerToolTipHandle, OS.TTM_DELTOOL, 0, lpti);
2557 void destroyItem (TreeItem item, long hItem) {
2558 hFirstIndexOf = hLastIndexOf = 0;
2561 * Feature in Windows. When an item is removed that is not
2562 * visible in the tree because it belongs to a collapsed branch,
2563 * Windows redraws the tree causing a flash for each item that
2564 * is removed. The fix is to detect whether the item is visible,
2565 * force the widget to be fully painted, turn off redraw, remove
2566 * the item and validate the damage caused by the removing of
2569 * NOTE: This fix is not necessary when double buffering and
2570 * can cause problems for virtual trees due to the call to
2571 * UpdateWindow() that flushes outstanding WM_PAINT events,
2572 * allowing application code to add or remove items during
2573 * this remove operation.
2576 boolean fixRedraw = false;
2577 if ((style & SWT.DOUBLE_BUFFERED) == 0) {
2578 if (getDrawing () && OS.IsWindowVisible (handle)) {
2579 RECT rect = new RECT ();
2580 fixRedraw = !OS.TreeView_GetItemRect (handle, hItem, rect, false);
2584 hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
2585 OS.UpdateWindow (handle);
2586 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
2588 * This code is intentionally commented.
2590 // OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
2592 ignoreDeselect = ignoreSelect = lockSelection = true;
2595 * Feature in Windows. When an item is deleted and a tool tip
2596 * is showing, Window requests the new text for the new item
2597 * that is under the cursor right away. This means that when
2598 * multiple items are deleted, the tool tip flashes, showing
2599 * each new item in the tool tip as it is scrolled into view.
2600 * The fix is to hide tool tips when any item is deleted.
2602 * NOTE: This only happens on Vista.
2604 long hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
2605 if (hwndToolTip != 0) OS.SendMessage (hwndToolTip, OS.TTM_POP, 0 ,0);
2607 shrink = ignoreShrink = true;
2608 OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
2609 ignoreShrink = false;
2611 * Bug 546333: When TVGN_CARET item is deleted, Windows automatically
2612 * sets selection to some other item. We do not want that.
2614 ignoreDeselect = ignoreSelect = lockSelection = false;
2616 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
2617 OS.ValidateRect (handle, null);
2619 * If the item that was deleted was the last child of a tree item that
2620 * is visible, redraw the parent item to force the +/- to be updated.
2622 if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hParent) == 0) {
2623 RECT rect = new RECT ();
2624 if (OS.TreeView_GetItemRect (handle, hParent, rect, false)) {
2625 OS.InvalidateRect (handle, rect, true);
2629 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
2631 if (imageList != null) {
2632 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
2633 display.releaseImageList (imageList);
2636 if (hwndParent == 0 && !linesVisible) {
2637 if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
2641 items = new TreeItem [4];
2647 Note: Don't update scrollbars when drawing is disabled.
2648 This gives significant improvement for bulk remove scenarios.
2649 Later, setRedraw(true) will update scrollbars once.
2651 if (getDrawing ()) updateScrollBar ();
2655 void destroyScrollBar (int type) {
2656 super.destroyScrollBar (type);
2657 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2658 if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
2659 bits &= ~(OS.WS_HSCROLL | OS.WS_VSCROLL);
2660 bits |= OS.TVS_NOSCROLL;
2662 if ((style & SWT.H_SCROLL) == 0) {
2663 bits &= ~OS.WS_HSCROLL;
2664 bits |= OS.TVS_NOHSCROLL;
2667 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2671 void enableDrag (boolean enabled) {
2672 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
2673 if (enabled && hooks (SWT.DragDetect)) {
2674 bits &= ~OS.TVS_DISABLEDRAGDROP;
2676 bits |= OS.TVS_DISABLEDRAGDROP;
2678 OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
2682 void enableWidget (boolean enabled) {
2683 super.enableWidget (enabled);
2685 * Bug in Windows. On Vista only, Windows does not draw using
2686 * the background color when the tree is disabled. The fix is
2687 * to set the default color, even when the color has not been
2688 * changed, causing Windows to draw correctly.
2690 Control control = findBackgroundControl ();
2691 if (control == null) control = this;
2692 if (control.backgroundImage == null) {
2693 _setBackgroundPixel (hasCustomBackground() ? control.getBackgroundPixel () : -1);
2695 if (hwndParent != 0) OS.EnableWindow (hwndParent, enabled);
2698 * Feature in Windows. When the tree has the style
2699 * TVS_FULLROWSELECT, the background color for the
2700 * entire row is filled when an item is painted,
2701 * drawing on top of the sort column color. The fix
2702 * is to clear TVS_FULLROWSELECT when there is
2705 updateFullSelection ();
2708 boolean findCell (int x, int y, TreeItem [] item, int [] index, RECT [] cellRect, RECT [] itemRect) {
2709 boolean found = false;
2710 TVHITTESTINFO lpht = new TVHITTESTINFO ();
2713 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
2714 if (lpht.hItem != 0) {
2715 item [0] = _getItem (lpht.hItem);
2716 POINT pt = new POINT ();
2719 long hDC = OS.GetDC (handle);
2720 long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
2721 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
2722 RECT rect = new RECT ();
2723 if (hwndParent != 0) {
2724 OS.GetClientRect (hwndParent, rect);
2725 OS.MapWindowPoints (hwndParent, handle, rect, 2);
2727 OS.GetClientRect (handle, rect);
2729 int count = Math.max (1, columnCount);
2730 int [] order = new int [count];
2731 if (hwndHeader != 0) OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, count, order);
2733 boolean quit = false;
2734 while (index [0] < count && !quit) {
2735 long hFont = item [0].fontHandle (order [index [0]]);
2736 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
2737 cellRect [0] = item [0].getBounds (order [index [0]], true, false, true, false, true, hDC);
2738 if (cellRect [0].left > rect.right) {
2741 cellRect [0].right = Math.min (cellRect [0].right, rect.right);
2742 if (OS.PtInRect (cellRect [0], pt)) {
2743 if (isCustomToolTip ()) {
2744 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, lpht.hItem, OS.TVIS_SELECTED);
2745 int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0;
2746 Event event = sendMeasureItemEvent (item [0], order [index [0]], hDC, detail);
2747 if (isDisposed () || item [0].isDisposed ()) break;
2748 Rectangle boundsInPixels = event.getBoundsInPixels();
2749 itemRect [0] = new RECT ();
2750 itemRect [0].left = boundsInPixels.x;
2751 itemRect [0].right = boundsInPixels.x + boundsInPixels.width;
2752 itemRect [0].top = boundsInPixels.y;
2753 itemRect [0].bottom = boundsInPixels.y + boundsInPixels.height;
2755 itemRect [0] = item [0].getBounds (order [index [0]], true, false, false, false, false, hDC);
2757 if (itemRect [0].right > cellRect [0].right) found = true;
2761 if (hFont != -1) OS.SelectObject (hDC, hFont);
2762 if (!found) index [0]++;
2764 if (newFont != 0) OS.SelectObject (hDC, oldFont);
2765 OS.ReleaseDC (handle, hDC);
2770 int findIndex (long hFirstItem, long hItem) {
2771 if (hFirstItem == 0) return -1;
2772 if (hFirstItem == hFirstIndexOf) {
2773 if (hFirstIndexOf == hItem) {
2774 hLastIndexOf = hFirstIndexOf;
2775 return lastIndexOf = 0;
2777 if (hLastIndexOf == hItem) return lastIndexOf;
2778 long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2779 if (hPrevItem == hItem) {
2780 hLastIndexOf = hPrevItem;
2781 return --lastIndexOf;
2783 long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2784 if (hNextItem == hItem) {
2785 hLastIndexOf = hNextItem;
2786 return ++lastIndexOf;
2788 int previousIndex = lastIndexOf - 1;
2789 while (hPrevItem != 0 && hPrevItem != hItem) {
2790 hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2793 if (hPrevItem == hItem) {
2794 hLastIndexOf = hPrevItem;
2795 return lastIndexOf = previousIndex;
2797 int nextIndex = lastIndexOf + 1;
2798 while (hNextItem != 0 && hNextItem != hItem) {
2799 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2802 if (hNextItem == hItem) {
2803 hLastIndexOf = hNextItem;
2804 return lastIndexOf = nextIndex;
2809 long hNextItem = hFirstItem;
2810 while (hNextItem != 0 && hNextItem != hItem) {
2811 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2814 if (hNextItem == hItem) {
2816 hFirstIndexOf = hFirstItem;
2817 hLastIndexOf = hNextItem;
2818 return lastIndexOf = index;
2824 Widget findItem (long hItem) {
2825 return _getItem (hItem);
2828 long findItem (long hFirstItem, int index) {
2829 if (hFirstItem == 0) return 0;
2830 if (hFirstItem == hFirstIndexOf) {
2833 return hLastIndexOf = hFirstIndexOf;
2835 if (lastIndexOf == index) return hLastIndexOf;
2836 if (lastIndexOf - 1 == index) {
2838 return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2840 if (lastIndexOf + 1 == index) {
2842 return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2844 if (index < lastIndexOf) {
2845 int previousIndex = lastIndexOf - 1;
2846 long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf);
2847 while (hPrevItem != 0 && index < previousIndex) {
2848 hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem);
2851 if (index == previousIndex) {
2852 lastIndexOf = previousIndex;
2853 return hLastIndexOf = hPrevItem;
2856 int nextIndex = lastIndexOf + 1;
2857 long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf);
2858 while (hNextItem != 0 && nextIndex < index) {
2859 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2862 if (index == nextIndex) {
2863 lastIndexOf = nextIndex;
2864 return hLastIndexOf = hNextItem;
2870 long hNextItem = hFirstItem;
2871 while (hNextItem != 0 && nextIndex < index) {
2872 hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem);
2875 if (index == nextIndex) {
2877 lastIndexOf = nextIndex;
2878 hFirstIndexOf = hFirstItem;
2879 return hLastIndexOf = hNextItem;
2884 TreeItem getFocusItem () {
2886 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
2887 return hItem != 0 ? _getItem (hItem) : null;
2891 * Returns the width in points of a grid line.
2893 * @return the width of a grid line in points
2895 * @exception SWTException <ul>
2896 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2897 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2902 public int getGridLineWidth () {
2904 return DPIUtil.autoScaleDown(getGridLineWidthInPixels ());
2907 int getGridLineWidthInPixels () {
2912 * Returns the header background color.
2914 * @return the receiver's header background color.
2916 * @exception SWTException <ul>
2917 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2918 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2922 public Color getHeaderBackground () {
2924 return Color.win32_new (display, getHeaderBackgroundPixel());
2927 private int getHeaderBackgroundPixel() {
2928 return headerBackground != -1 ? headerBackground : defaultBackground();
2932 * Returns the header foreground color.
2934 * @return the receiver's header foreground color.
2936 * @exception SWTException <ul>
2937 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2938 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2942 public Color getHeaderForeground () {
2944 return Color.win32_new (display, getHeaderForegroundPixel());
2947 private int getHeaderForegroundPixel() {
2948 return headerForeground != -1 ? headerForeground : defaultForeground();
2952 * Returns the height of the receiver's header
2954 * @return the height of the header or zero if the header is not visible
2956 * @exception SWTException <ul>
2957 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2958 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2963 public int getHeaderHeight () {
2965 return DPIUtil.autoScaleDown(getHeaderHeightInPixels ());
2968 int getHeaderHeightInPixels () {
2969 if (hwndHeader == 0) return 0;
2970 RECT rect = new RECT ();
2971 OS.GetWindowRect (hwndHeader, rect);
2972 return rect.bottom - rect.top;
2976 * Returns <code>true</code> if the receiver's header is visible,
2977 * and <code>false</code> otherwise.
2979 * If one of the receiver's ancestors is not visible or some
2980 * other condition makes the receiver not visible, this method
2981 * may still indicate that it is considered visible even though
2982 * it may not actually be showing.
2985 * @return the receiver's header's visibility state
2987 * @exception SWTException <ul>
2988 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2989 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2994 public boolean getHeaderVisible () {
2996 if (hwndHeader == 0) return false;
2997 int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
2998 return (bits & OS.WS_VISIBLE) != 0;
3001 Point getImageSize () {
3002 if (imageList != null) return imageList.getImageSize ();
3003 return new Point (0, getItemHeightInPixels ());
3006 long getBottomItem () {
3007 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3008 if (hItem == 0) return 0;
3009 int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
3010 while (index <= count) {
3011 long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3012 if (hNextItem == 0) return hItem;
3020 * Returns the column at the given, zero-relative index in the
3021 * receiver. Throws an exception if the index is out of range.
3022 * Columns are returned in the order that they were created.
3023 * If no <code>TreeColumn</code>s were created by the programmer,
3024 * this method will throw <code>ERROR_INVALID_RANGE</code> despite
3025 * the fact that a single column of data may be visible in the tree.
3026 * This occurs when the programmer uses the tree like a list, adding
3027 * items but never creating a column.
3029 * @param index the index of the column to return
3030 * @return the column at the given index
3032 * @exception IllegalArgumentException <ul>
3033 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
3035 * @exception SWTException <ul>
3036 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3037 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3040 * @see Tree#getColumnOrder()
3041 * @see Tree#setColumnOrder(int[])
3042 * @see TreeColumn#getMoveable()
3043 * @see TreeColumn#setMoveable(boolean)
3048 public TreeColumn getColumn (int index) {
3050 if (!(0 <= index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE);
3051 return columns [index];
3055 * Returns the number of columns contained in the receiver.
3056 * If no <code>TreeColumn</code>s were created by the programmer,
3057 * this value is zero, despite the fact that visually, one column
3058 * of items may be visible. This occurs when the programmer uses
3059 * the tree like a list, adding items but never creating a column.
3061 * @return the number of columns
3063 * @exception SWTException <ul>
3064 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3065 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3070 public int getColumnCount () {
3076 * Returns an array of zero-relative integers that map
3077 * the creation order of the receiver's items to the
3078 * order in which they are currently being displayed.
3080 * Specifically, the indices of the returned array represent
3081 * the current visual order of the items, and the contents
3082 * of the array represent the creation order of the items.
3084 * Note: This is not the actual structure used by the receiver
3085 * to maintain its list of items, so modifying the array will
3086 * not affect the receiver.
3089 * @return the current visual order of the receiver's items
3091 * @exception SWTException <ul>
3092 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3093 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3096 * @see Tree#setColumnOrder(int[])
3097 * @see TreeColumn#getMoveable()
3098 * @see TreeColumn#setMoveable(boolean)
3103 public int[] getColumnOrder () {
3105 if (columnCount == 0) return new int [0];
3106 int [] order = new int [columnCount];
3107 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
3112 * Returns an array of <code>TreeColumn</code>s which are the
3113 * columns in the receiver. Columns are returned in the order
3114 * that they were created. If no <code>TreeColumn</code>s were
3115 * created by the programmer, the array is empty, despite the fact
3116 * that visually, one column of items may be visible. This occurs
3117 * when the programmer uses the tree like a list, adding items but
3118 * never creating a column.
3120 * Note: This is not the actual structure used by the receiver
3121 * to maintain its list of items, so modifying the array will
3122 * not affect the receiver.
3125 * @return the items in the receiver
3127 * @exception SWTException <ul>
3128 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3129 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3132 * @see Tree#getColumnOrder()
3133 * @see Tree#setColumnOrder(int[])
3134 * @see TreeColumn#getMoveable()
3135 * @see TreeColumn#setMoveable(boolean)
3140 public TreeColumn [] getColumns () {
3142 TreeColumn [] result = new TreeColumn [columnCount];
3143 System.arraycopy (columns, 0, result, 0, columnCount);
3148 * Returns the item at the given, zero-relative index in the
3149 * receiver. Throws an exception if the index is out of range.
3151 * @param index the index of the item to return
3152 * @return the item at the given index
3154 * @exception IllegalArgumentException <ul>
3155 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
3157 * @exception SWTException <ul>
3158 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3159 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3164 public TreeItem getItem (int index) {
3166 if (index < 0) error (SWT.ERROR_INVALID_RANGE);
3167 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3168 if (hFirstItem == 0) error (SWT.ERROR_INVALID_RANGE);
3169 long hItem = findItem (hFirstItem, index);
3170 if (hItem == 0) error (SWT.ERROR_INVALID_RANGE);
3171 return _getItem (hItem);
3174 TreeItem getItem (NMTVCUSTOMDRAW nmcd) {
3176 * Bug in Windows. If the lParam field of TVITEM
3177 * is changed during custom draw using TVM_SETITEM,
3178 * the lItemlParam field of the NMTVCUSTOMDRAW struct
3179 * is not updated until the next custom draw. The
3180 * fix is to query the field from the item instead
3181 * of using the struct.
3183 int id = (int)nmcd.lItemlParam;
3184 if ((style & SWT.VIRTUAL) != 0) {
3186 TVITEM tvItem = new TVITEM ();
3187 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3188 tvItem.hItem = nmcd.dwItemSpec;
3189 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3190 id = (int)tvItem.lParam;
3193 return _getItem (nmcd.dwItemSpec, id);
3197 * Returns the item at the given point in the receiver
3198 * or null if no such item exists. The point is in the
3199 * coordinate system of the receiver.
3201 * The item that is returned represents an item that could be selected by the user.
3202 * For example, if selection only occurs in items in the first column, then null is
3203 * returned if the point is outside of the item.
3204 * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy,
3205 * determines the extent of the selection.
3208 * @param point the point used to locate the item
3209 * @return the item at the given point, or null if the point is not in a selectable item
3211 * @exception IllegalArgumentException <ul>
3212 * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
3214 * @exception SWTException <ul>
3215 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3216 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3219 public TreeItem getItem (Point point) {
3221 if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
3222 return getItemInPixels(DPIUtil.autoScaleUp(point));
3225 TreeItem getItemInPixels (Point point) {
3226 TVHITTESTINFO lpht = new TVHITTESTINFO ();
3229 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
3230 if (lpht.hItem != 0) {
3231 int flags = OS.TVHT_ONITEM;
3232 if ((style & SWT.FULL_SELECTION) != 0) {
3233 flags |= OS.TVHT_ONITEMRIGHT | OS.TVHT_ONITEMINDENT;
3235 if (hooks (SWT.MeasureItem)) {
3236 lpht.flags &= ~(OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL);
3237 if (hitTestSelection (lpht.hItem, lpht.x, lpht.y)) {
3238 lpht.flags |= OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
3242 if ((lpht.flags & flags) != 0) return _getItem (lpht.hItem);
3248 * Returns the number of items contained in the receiver
3249 * that are direct item children of the receiver. The
3250 * number that is returned is the number of roots in the
3253 * @return the number of items
3255 * @exception SWTException <ul>
3256 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3257 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3260 public int getItemCount () {
3262 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3263 if (hItem == 0) return 0;
3264 return getItemCount (hItem);
3267 int getItemCount (long hItem) {
3269 long hFirstItem = hItem;
3270 if (hItem == hFirstIndexOf) {
3271 if (itemCount != -1) return itemCount;
3272 hFirstItem = hLastIndexOf;
3273 count = lastIndexOf;
3275 while (hFirstItem != 0) {
3276 hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hFirstItem);
3279 if (hItem == hFirstIndexOf) itemCount = count;
3284 * Returns the height of the area which would be used to
3285 * display <em>one</em> of the items in the tree.
3287 * @return the height of one item
3289 * @exception SWTException <ul>
3290 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3291 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3294 public int getItemHeight () {
3296 return DPIUtil.autoScaleDown(getItemHeightInPixels());
3299 int getItemHeightInPixels () {
3300 return (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0);
3304 * Returns a (possibly empty) array of items contained in the
3305 * receiver that are direct item children of the receiver. These
3306 * are the roots of the tree.
3308 * Note: This is not the actual structure used by the receiver
3309 * to maintain its list of items, so modifying the array will
3310 * not affect the receiver.
3315 * @exception SWTException <ul>
3316 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3317 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3320 public TreeItem [] getItems () {
3322 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3323 if (hItem == 0) return new TreeItem [0];
3324 return getItems (hItem);
3327 TreeItem [] getItems (long hTreeItem) {
3329 long hItem = hTreeItem;
3330 while (hItem != 0) {
3331 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3335 TreeItem [] result = new TreeItem [count];
3336 TVITEM tvItem = new TVITEM ();
3337 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
3338 tvItem.hItem = hTreeItem;
3340 * Feature in Windows. In some cases an expand or collapse message
3341 * can occur from within TVM_DELETEITEM. When this happens, the item
3342 * being destroyed has been removed from the list of items but has not
3343 * been deleted from the tree. The fix is to check for null items and
3344 * remove them from the list.
3346 while (tvItem.hItem != 0) {
3347 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3348 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
3349 if (item != null) result [index++] = item;
3350 tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem);
3352 if (index != count) {
3353 TreeItem [] newResult = new TreeItem [index];
3354 System.arraycopy (result, 0, newResult, 0, index);
3361 * Returns <code>true</code> if the receiver's lines are visible,
3362 * and <code>false</code> otherwise. Note that some platforms draw
3363 * grid lines while others may draw alternating row colors.
3365 * If one of the receiver's ancestors is not visible or some
3366 * other condition makes the receiver not visible, this method
3367 * may still indicate that it is considered visible even though
3368 * it may not actually be showing.
3371 * @return the visibility state of the lines
3373 * @exception SWTException <ul>
3374 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3375 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3380 public boolean getLinesVisible () {
3382 return linesVisible;
3385 long getNextSelection (long hItem) {
3386 while (hItem != 0) {
3387 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3388 if ((state & OS.TVIS_SELECTED) != 0) return hItem;
3389 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3390 long hSelected = getNextSelection (hFirstItem);
3391 if (hSelected != 0) return hSelected;
3392 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3398 * Returns the receiver's parent item, which must be a
3399 * <code>TreeItem</code> or null when the receiver is a
3402 * @return the receiver's parent item
3404 * @exception SWTException <ul>
3405 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3406 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3409 public TreeItem getParentItem () {
3414 int getSelection (long hItem, TVITEM tvItem, TreeItem [] selection, int index, int count, boolean bigSelection, boolean all) {
3415 while (hItem != 0) {
3416 boolean expanded = true;
3418 tvItem.hItem = hItem;
3419 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3420 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
3421 if (selection != null && index < selection.length) {
3422 TreeItem item = _getItem (hItem, (int)tvItem.lParam);
3424 selection [index] = item;
3431 expanded = (tvItem.state & OS.TVIS_EXPANDED) != 0;
3433 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED | OS.TVIS_EXPANDED);
3434 if ((state & OS.TVIS_SELECTED) != 0) {
3435 if (tvItem != null && selection != null && index < selection.length) {
3436 tvItem.hItem = hItem;
3437 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3438 TreeItem item = _getItem (hItem, (int)tvItem.lParam);
3440 selection [index] = item;
3447 expanded = (state & OS.TVIS_EXPANDED) != 0;
3449 if (index == count) break;
3452 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3453 if ((index = getSelection (hFirstItem, tvItem, selection, index, count, bigSelection, all)) == count) {
3457 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3459 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3466 * Returns an array of <code>TreeItem</code>s that are currently
3467 * selected in the receiver. The order of the items is unspecified.
3468 * An empty array indicates that no items are selected.
3470 * Note: This is not the actual structure used by the receiver
3471 * to maintain its selection, so modifying the array will
3472 * not affect the receiver.
3474 * @return an array representing the selection
3476 * @exception SWTException <ul>
3477 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3478 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3481 public TreeItem [] getSelection () {
3483 if ((style & SWT.SINGLE) != 0) {
3484 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3485 if (hItem == 0) return new TreeItem [0];
3486 TVITEM tvItem = new TVITEM ();
3487 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3488 tvItem.hItem = hItem;
3489 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3490 if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0];
3491 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
3492 if (item == null) return new TreeItem [0];
3493 return new TreeItem [] {item};
3496 TreeItem [] guess = new TreeItem [(style & SWT.VIRTUAL) != 0 ? 8 : 1];
3497 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
3498 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3499 if ((style & SWT.VIRTUAL) != 0) {
3500 TVITEM tvItem = new TVITEM ();
3501 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3502 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3503 count = getSelection (hItem, tvItem, guess, 0, -1, false, true);
3505 for (int i=0; i<items.length; i++) {
3506 TreeItem item = items [i];
3508 long hItem = item.handle;
3509 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3510 if ((state & OS.TVIS_SELECTED) != 0) {
3511 if (count < guess.length) guess [count] = item;
3517 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3518 if (count == 0) return new TreeItem [0];
3519 if (count == guess.length) return guess;
3520 TreeItem [] result = new TreeItem [count];
3521 if (count < guess.length) {
3522 System.arraycopy (guess, 0, result, 0, count);
3525 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3526 TVITEM tvItem = new TVITEM ();
3527 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
3528 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3529 int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
3530 boolean bigSelection = result.length > itemCount / 2;
3531 if (count != getSelection (hItem, tvItem, result, 0, count, bigSelection, false)) {
3532 count = getSelection (hItem, tvItem, result, 0, count, bigSelection, true);
3534 if (count != result.length) {
3535 TreeItem[] newResult = new TreeItem[count];
3536 System.arraycopy (result, 0, newResult, 0, count);
3539 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3544 * Returns the number of selected items contained in the receiver.
3546 * @return the number of selected items
3548 * @exception SWTException <ul>
3549 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3550 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3553 public int getSelectionCount () {
3555 if ((style & SWT.SINGLE) != 0) {
3556 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3557 if (hItem == 0) return 0;
3558 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3559 return (state & OS.TVIS_SELECTED) == 0 ? 0 : 1;
3562 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
3563 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
3564 if ((style & SWT.VIRTUAL) != 0) {
3565 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3566 count = getSelection (hItem, null, null, 0, -1, false, true);
3568 for (int i=0; i<items.length; i++) {
3569 TreeItem item = items [i];
3571 long hItem = item.handle;
3572 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3573 if ((state & OS.TVIS_SELECTED) != 0) count++;
3577 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
3582 * Returns the column which shows the sort indicator for
3583 * the receiver. The value may be null if no column shows
3584 * the sort indicator.
3586 * @return the sort indicator
3588 * @exception SWTException <ul>
3589 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3590 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3593 * @see #setSortColumn(TreeColumn)
3597 public TreeColumn getSortColumn () {
3602 int getSortColumnPixel () {
3603 int pixel = OS.IsWindowEnabled (handle) || hasCustomBackground() ? getBackgroundPixel () : OS.GetSysColor (OS.COLOR_3DFACE);
3604 return getSlightlyDifferentBackgroundColor(pixel);
3608 * Returns the direction of the sort indicator for the receiver.
3609 * The value will be one of <code>UP</code>, <code>DOWN</code>
3610 * or <code>NONE</code>.
3612 * @return the sort direction
3614 * @exception SWTException <ul>
3615 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3616 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3619 * @see #setSortDirection(int)
3623 public int getSortDirection () {
3625 return sortDirection;
3629 * Returns the item which is currently at the top of the receiver.
3630 * This item can change when items are expanded, collapsed, scrolled
3631 * or new items are added or removed.
3633 * @return the item at the top of the receiver
3635 * @exception SWTException <ul>
3636 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3637 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3642 public TreeItem getTopItem () {
3644 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3645 return hItem != 0 ? _getItem (hItem) : null;
3648 boolean hitTestSelection (long hItem, int x, int y) {
3649 if (hItem == 0) return false;
3650 TreeItem item = _getItem (hItem);
3651 if (item == null) return false;
3652 if (!hooks (SWT.MeasureItem)) return false;
3653 boolean result = false;
3655 //BUG? - moved columns, only hittest first column
3656 //BUG? - check drag detect
3657 int [] order = new int [1], index = new int [1];
3659 long hDC = OS.GetDC (handle);
3660 long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
3661 if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont);
3662 long hFont = item.fontHandle (order [index [0]]);
3663 if (hFont != -1) hFont = OS.SelectObject (hDC, hFont);
3664 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3665 int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0;
3666 Event event = sendMeasureItemEvent (item, order [index [0]], hDC, detail);
3667 if (event.getBoundsInPixels ().contains (x, y)) result = true;
3668 if (newFont != 0) OS.SelectObject (hDC, oldFont);
3669 OS.ReleaseDC (handle, hDC);
3670 // if (isDisposed () || item.isDisposed ()) return false;
3674 int imageIndex (Image image, int index) {
3675 if (image == null) return OS.I_IMAGENONE;
3676 if (imageList == null) {
3677 Rectangle bounds = image.getBoundsInPixels ();
3678 imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3680 int imageIndex = imageList.indexOf (image);
3681 if (imageIndex == -1) imageIndex = imageList.add (image);
3682 if (hwndHeader == 0 || OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) == index) {
3684 * Feature in Windows. When setting the same image list multiple
3685 * times, Windows does work making this operation slow. The fix
3686 * is to test for the same image list before setting the new one.
3688 long hImageList = imageList.getHandle ();
3689 long hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
3690 if (hOldImageList != hImageList) {
3691 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
3698 int imageIndexHeader (Image image) {
3699 if (image == null) return OS.I_IMAGENONE;
3700 if (headerImageList == null) {
3701 Rectangle bounds = image.getBoundsInPixels ();
3702 headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height);
3703 int index = headerImageList.indexOf (image);
3704 if (index == -1) index = headerImageList.add (image);
3705 long hImageList = headerImageList.getHandle ();
3706 if (hwndHeader != 0) {
3707 OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageList);
3712 int index = headerImageList.indexOf (image);
3713 if (index != -1) return index;
3714 return headerImageList.add (image);
3718 * Searches the receiver's list starting at the first column
3719 * (index 0) until a column is found that is equal to the
3720 * argument, and returns the index of that column. If no column
3721 * is found, returns -1.
3723 * @param column the search column
3724 * @return the index of the column
3726 * @exception IllegalArgumentException <ul>
3727 * <li>ERROR_NULL_ARGUMENT - if the column is null</li>
3729 * @exception SWTException <ul>
3730 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3731 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3736 public int indexOf (TreeColumn column) {
3738 if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
3739 if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3740 for (int i=0; i<columnCount; i++) {
3741 if (columns [i] == column) return i;
3747 * Searches the receiver's list starting at the first item
3748 * (index 0) until an item is found that is equal to the
3749 * argument, and returns the index of that item. If no item
3750 * is found, returns -1.
3752 * @param item the search item
3753 * @return the index of the item
3755 * @exception IllegalArgumentException <ul>
3756 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
3757 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
3759 * @exception SWTException <ul>
3760 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3761 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3766 public int indexOf (TreeItem item) {
3768 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
3769 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
3770 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
3771 return hItem == 0 ? -1 : findIndex (hItem, item.handle);
3774 boolean isCustomToolTip () {
3775 return hooks (SWT.MeasureItem);
3778 boolean isItemSelected (NMTVCUSTOMDRAW nmcd) {
3779 boolean selected = false;
3780 if (OS.IsWindowEnabled (handle)) {
3781 TVITEM tvItem = new TVITEM ();
3782 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
3783 tvItem.hItem = nmcd.dwItemSpec;
3784 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
3785 if ((tvItem.state & (OS.TVIS_SELECTED | OS.TVIS_DROPHILITED)) != 0) {
3788 * Feature in Windows. When the mouse is pressed and the
3789 * selection is first drawn for a tree, the previously
3790 * selected item is redrawn but the the TVIS_SELECTED bits
3791 * are not cleared. When the user moves the mouse slightly
3792 * and a drag and drop operation is not started, the item is
3793 * drawn again and this time with TVIS_SELECTED is cleared.
3794 * This means that an item that contains colored cells will
3795 * not draw with the correct background until the mouse is
3796 * moved. The fix is to test for the selection colors and
3797 * guess that the item is not selected.
3799 * NOTE: This code does not work when the foreground and
3800 * background of the tree are set to the selection colors
3801 * but this does not happen in a regular application.
3803 if (handle == OS.GetFocus ()) {
3804 if (OS.GetTextColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3807 if (OS.GetBkColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3813 if (nmcd.dwDrawStage == OS.CDDS_ITEMPOSTPAINT) {
3815 * Feature in Windows. When the mouse is pressed and the
3816 * selection is first drawn for a tree, the item is drawn
3817 * selected, but the TVIS_SELECTED bits for the item are
3818 * not set. When the user moves the mouse slightly and
3819 * a drag and drop operation is not started, the item is
3820 * drawn again and this time TVIS_SELECTED is set. This
3821 * means that an item that is in a tree that has the style
3822 * TVS_FULLROWSELECT and that also contains colored cells
3823 * will not draw the entire row selected until the user
3824 * moves the mouse. The fix is to test for the selection
3825 * colors and guess that the item is selected.
3827 * NOTE: This code does not work when the foreground and
3828 * background of the tree are set to the selection colors
3829 * but this does not happen in a regular application.
3831 if (OS.GetTextColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) {
3832 if (OS.GetBkColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHT)) {
3842 void redrawSelection () {
3843 if ((style & SWT.SINGLE) != 0) {
3844 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
3846 RECT rect = new RECT ();
3847 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
3848 OS.InvalidateRect (handle, rect, true);
3852 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
3854 RECT rect = new RECT ();
3855 int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0);
3856 while (index <= count && hItem != 0) {
3857 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
3858 if ((state & OS.TVIS_SELECTED) != 0) {
3859 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
3860 OS.InvalidateRect (handle, rect, true);
3863 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
3873 if (hwndParent != 0) display.addControl (hwndParent, this);
3874 if (hwndHeader != 0) display.addControl (hwndHeader, this);
3877 void releaseItem (long hItem, TVITEM tvItem, boolean release) {
3878 if (hItem == hAnchor) hAnchor = 0;
3879 if (hItem == hInsert) hInsert = 0;
3880 tvItem.hItem = hItem;
3881 if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) {
3882 if (tvItem.lParam != -1) {
3883 if (tvItem.lParam < lastID) lastID = (int)tvItem.lParam;
3885 TreeItem item = items [(int)tvItem.lParam];
3886 if (item != null) item.release (false);
3888 items [(int)tvItem.lParam] = null;
3893 void releaseItems (long hItem, TVITEM tvItem) {
3894 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
3895 while (hItem != 0) {
3896 releaseItems (hItem, tvItem);
3897 releaseItem (hItem, tvItem, true);
3898 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
3903 void releaseHandle () {
3904 super.releaseHandle ();
3905 hwndParent = hwndHeader = 0;
3909 void releaseChildren (boolean destroy) {
3910 if (items != null) {
3911 for (int i=0; i<items.length; i++) {
3912 TreeItem item = items [i];
3913 if (item != null && !item.isDisposed ()) {
3914 item.release (false);
3919 if (columns != null) {
3920 for (int i=0; i<columns.length; i++) {
3921 TreeColumn column = columns [i];
3922 if (column != null && !column.isDisposed ()) {
3923 column.release (false);
3928 super.releaseChildren (destroy);
3932 void releaseWidget () {
3933 super.releaseWidget ();
3935 * Feature in Windows. For some reason, when TVM_GETIMAGELIST
3936 * or TVM_SETIMAGELIST is sent, the tree issues NM_CUSTOMDRAW
3937 * messages. This behavior is unwanted when the tree is being
3938 * disposed. The fix is to ignore NM_CUSTOMDRAW messages by
3939 * clearing the custom draw flag.
3941 * NOTE: This only happens on Windows XP.
3944 if (imageList != null) {
3945 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, 0);
3946 display.releaseImageList (imageList);
3948 if (headerImageList != null) {
3949 if (hwndHeader != 0) {
3950 OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, 0);
3952 display.releaseImageList (headerImageList);
3954 imageList = headerImageList = null;
3955 long hStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
3956 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, 0);
3957 if (hStateList != 0) OS.ImageList_Destroy (hStateList);
3958 if (itemToolTipHandle != 0) OS.DestroyWindow (itemToolTipHandle);
3959 if (headerToolTipHandle != 0) OS.DestroyWindow (headerToolTipHandle);
3960 itemToolTipHandle = headerToolTipHandle = 0;
3964 * Removes all of the items from the receiver.
3966 * @exception SWTException <ul>
3967 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3968 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3971 public void removeAll () {
3973 hFirstIndexOf = hLastIndexOf = 0;
3975 for (int i=0; i<items.length; i++) {
3976 TreeItem item = items [i];
3977 if (item != null && !item.isDisposed ()) {
3978 item.release (false);
3981 ignoreDeselect = ignoreSelect = true;
3982 boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
3983 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
3984 shrink = ignoreShrink = true;
3985 long result = OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, OS.TVI_ROOT);
3986 ignoreShrink = false;
3988 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
3989 OS.InvalidateRect (handle, null, true);
3991 ignoreDeselect = ignoreSelect = false;
3992 if (result == 0) error (SWT.ERROR_ITEM_NOT_REMOVED);
3993 if (imageList != null) {
3994 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, 0, 0);
3995 display.releaseImageList (imageList);
3998 if (hwndParent == 0 && !linesVisible) {
3999 if (!hooks (SWT.MeasureItem) && !hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
4003 hAnchor = hInsert = hFirstIndexOf = hLastIndexOf = 0;
4005 items = new TreeItem [4];
4012 * Removes the listener from the collection of listeners who will
4013 * be notified when the user changes the receiver's selection.
4015 * @param listener the listener which should no longer be notified
4017 * @exception IllegalArgumentException <ul>
4018 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
4020 * @exception SWTException <ul>
4021 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4022 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4025 * @see SelectionListener
4026 * @see #addSelectionListener
4028 public void removeSelectionListener (SelectionListener listener) {
4030 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
4031 eventTable.unhook (SWT.Selection, listener);
4032 eventTable.unhook (SWT.DefaultSelection, listener);
4036 * Removes the listener from the collection of listeners who will
4037 * be notified when items in the receiver are expanded or collapsed.
4039 * @param listener the listener which should no longer be notified
4041 * @exception IllegalArgumentException <ul>
4042 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
4044 * @exception SWTException <ul>
4045 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4046 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4050 * @see #addTreeListener
4052 public void removeTreeListener(TreeListener listener) {
4054 if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
4055 if (eventTable == null) return;
4056 eventTable.unhook (SWT.Expand, listener);
4057 eventTable.unhook (SWT.Collapse, listener);
4061 void reskinChildren (int flags) {
4062 if (items != null) {
4063 for (int i=0; i<items.length; i++) {
4064 TreeItem item = items [i];
4065 if (item != null) item.reskinChildren (flags);
4068 if (columns != null) {
4069 for (int i=0; i<columns.length; i++) {
4070 TreeColumn column = columns [i];
4071 if (column != null) column.reskinChildren (flags);
4074 super.reskinChildren (flags);
4079 * Display a mark indicating the point at which an item will be inserted.
4080 * The drop insert item has a visual hint to show where a dragged item
4081 * will be inserted when dropped on the tree.
4083 * @param item the insert item. Null will clear the insertion mark.
4084 * @param before true places the insert mark above 'item'. false places
4085 * the insert mark below 'item'.
4087 * @exception IllegalArgumentException <ul>
4088 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4090 * @exception SWTException <ul>
4091 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4092 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4095 public void setInsertMark (TreeItem item, boolean before) {
4099 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4100 hItem = item.handle;
4103 insertAfter = !before;
4104 OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
4108 * Sets the number of root-level items contained in the receiver.
4110 * @param count the number of items
4112 * @exception SWTException <ul>
4113 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4114 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4119 public void setItemCount (int count) {
4121 count = Math.max (0, count);
4122 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4123 setItemCount (count, OS.TVGN_ROOT, hItem);
4126 void setItemCount (int count, long hParent, long hItem) {
4127 boolean redraw = false;
4128 if (OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) == 0) {
4129 redraw = getDrawing () && OS.IsWindowVisible (handle);
4130 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4133 while (hItem != 0 && itemCount < count) {
4134 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4137 boolean expanded = false;
4138 TVITEM tvItem = new TVITEM ();
4139 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
4140 if (!redraw && (style & SWT.VIRTUAL) != 0) {
4142 * Bug in Windows. Despite the fact that TVM_GETITEMSTATE claims
4143 * to return only the bits specified by the stateMask, when called
4144 * with TVIS_EXPANDED, the entire state is returned. The fix is
4145 * to explicitly check for the TVIS_EXPANDED bit.
4147 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hParent, OS.TVIS_EXPANDED);
4148 expanded = (state & OS.TVIS_EXPANDED) != 0;
4150 while (hItem != 0) {
4151 tvItem.hItem = hItem;
4152 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4153 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4154 TreeItem item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null;
4155 if (item != null && !item.isDisposed ()) {
4158 releaseItem (tvItem.hItem, tvItem, false);
4159 destroyItem (null, tvItem.hItem);
4162 if ((style & SWT.VIRTUAL) != 0) {
4163 for (int i=itemCount; i<count; i++) {
4164 if (expanded) ignoreShrink = true;
4165 createItem (null, hParent, OS.TVI_LAST, 0);
4166 if (expanded) ignoreShrink = false;
4170 int extra = Math.max (4, (count + 3) / 4 * 4);
4171 TreeItem [] newItems = new TreeItem [items.length + extra];
4172 System.arraycopy (items, 0, newItems, 0, items.length);
4174 for (int i=itemCount; i<count; i++) {
4175 new TreeItem (this, SWT.NONE, hParent, OS.TVI_LAST, 0);
4179 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4180 OS.InvalidateRect (handle, null, true);
4185 * Sets the height of the area which would be used to
4186 * display <em>one</em> of the items in the tree.
4188 * @param itemHeight the height of one item
4190 * @exception SWTException <ul>
4191 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4192 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4197 /*public*/ void setItemHeight (int itemHeight) {
4199 if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT);
4200 OS.SendMessage (handle, OS.TVM_SETITEMHEIGHT, itemHeight, 0);
4204 * Marks the receiver's lines as visible if the argument is <code>true</code>,
4205 * and marks it invisible otherwise. Note that some platforms draw
4206 * grid lines while others may draw alternating row colors.
4208 * If one of the receiver's ancestors is not visible or some
4209 * other condition makes the receiver not visible, marking
4210 * it visible may not actually cause it to be displayed.
4213 * @param show the new visibility state
4215 * @exception SWTException <ul>
4216 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4217 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4222 public void setLinesVisible (boolean show) {
4224 if (linesVisible == show) return;
4225 linesVisible = show;
4226 if (hwndParent == 0 && linesVisible) customDraw = true;
4227 OS.InvalidateRect (handle, null, true);
4228 if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true);
4232 long scrolledHandle () {
4233 if (hwndHeader == 0) return handle;
4234 return columnCount == 0 && scrollWidth == 0 ? handle : hwndParent;
4237 void select (long hItem, TVITEM tvItem) {
4238 while (hItem != 0) {
4239 tvItem.hItem = hItem;
4240 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4241 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_EXPANDED);
4242 if ((state & OS.TVIS_EXPANDED) != 0) {
4243 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4244 select (hFirstItem, tvItem);
4247 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4252 * Selects an item in the receiver. If the item was already
4253 * selected, it remains selected.
4255 * @param item the item to be selected
4257 * @exception IllegalArgumentException <ul>
4258 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4259 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4261 * @exception SWTException <ul>
4262 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4263 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4268 public void select (TreeItem item) {
4270 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4271 if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
4272 if ((style & SWT.SINGLE) != 0) {
4273 long hItem = item.handle;
4274 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
4275 if ((state & OS.TVIS_SELECTED) != 0) return;
4277 * Feature in Windows. When an item is selected with
4278 * TVM_SELECTITEM and TVGN_CARET, the tree expands and
4279 * scrolls to show the new selected item. Unfortunately,
4280 * there is no other way in Windows to set the focus
4281 * and select an item. The fix is to save the current
4282 * scroll bar positions, turn off redraw, select the item,
4283 * then scroll back to the original position and redraw
4286 SCROLLINFO hInfo = null;
4287 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
4288 if ((bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) {
4289 hInfo = new SCROLLINFO ();
4290 hInfo.cbSize = SCROLLINFO.sizeof;
4291 hInfo.fMask = OS.SIF_ALL;
4292 OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo);
4294 SCROLLINFO vInfo = new SCROLLINFO ();
4295 vInfo.cbSize = SCROLLINFO.sizeof;
4296 vInfo.fMask = OS.SIF_ALL;
4297 OS.GetScrollInfo (handle, OS.SB_VERT, vInfo);
4298 boolean redraw = getDrawing () && OS.IsWindowVisible (handle);
4300 OS.UpdateWindow (handle);
4301 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4303 setSelection (item);
4304 if (hInfo != null) {
4305 long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos);
4306 OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0);
4309 * Feature in Windows. It seems that Vista does not
4310 * use wParam to get the new position when WM_VSCROLL
4311 * is sent with SB_THUMBPOSITION. The fix is to use
4312 * SetScrollInfo() to move the scroll bar thumb before
4313 * calling WM_VSCROLL.
4315 * NOTE: This code is only necessary on Windows Vista.
4317 OS.SetScrollInfo (handle, OS.SB_VERT, vInfo, true);
4318 long vThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, vInfo.nPos);
4319 OS.SendMessage (handle, OS.WM_VSCROLL, vThumb, 0);
4321 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4322 OS.InvalidateRect (handle, null, true);
4323 if ((style & SWT.DOUBLE_BUFFERED) == 0) {
4324 int oldStyle = style;
4325 style |= SWT.DOUBLE_BUFFERED;
4326 OS.UpdateWindow (handle);
4333 TVITEM tvItem = new TVITEM ();
4334 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4335 tvItem.stateMask = OS.TVIS_SELECTED;
4336 tvItem.state = OS.TVIS_SELECTED;
4337 tvItem.hItem = item.handle;
4338 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4342 * Selects all of the items in the receiver.
4344 * If the receiver is single-select, do nothing.
4347 * @exception SWTException <ul>
4348 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4349 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4352 public void selectAll () {
4354 if ((style & SWT.SINGLE) != 0) return;
4355 TVITEM tvItem = new TVITEM ();
4356 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
4357 tvItem.state = OS.TVIS_SELECTED;
4358 tvItem.stateMask = OS.TVIS_SELECTED;
4359 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
4360 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
4361 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
4362 select (hItem, tvItem);
4363 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
4366 Event sendEraseItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT cellRect) {
4367 int nSavedDC = OS.SaveDC (nmcd.hdc);
4368 RECT insetRect = toolTipInset (cellRect);
4369 OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
4370 GCData data = new GCData ();
4371 data.device = display;
4372 data.foreground = OS.GetTextColor (nmcd.hdc);
4373 data.background = OS.GetBkColor (nmcd.hdc);
4374 data.font = item.getFont (column);
4375 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
4376 GC gc = GC.win32_new (nmcd.hdc, data);
4377 Event event = new Event ();
4379 event.index = column;
4381 event.detail |= SWT.FOREGROUND;
4382 event.setBoundsInPixels(new Rectangle(cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top));
4383 //gc.setClipping (event.x, event.y, event.width, event.height);
4384 sendEvent (SWT.EraseItem, event);
4386 //int newTextClr = data.foreground;
4388 OS.RestoreDC (nmcd.hdc, nSavedDC);
4392 Event sendMeasureItemEvent (TreeItem item, int index, long hDC, int detail) {
4393 RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC);
4394 int nSavedDC = OS.SaveDC (hDC);
4395 GCData data = new GCData ();
4396 data.device = display;
4397 data.font = item.getFont (index);
4398 GC gc = GC.win32_new (hDC, data);
4399 Event event = new Event ();
4402 event.index = index;
4403 event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
4404 event.detail = detail;
4405 sendEvent (SWT.MeasureItem, event);
4408 OS.RestoreDC (hDC, nSavedDC);
4409 if (isDisposed () || item.isDisposed ()) return null;
4410 Rectangle rect = event.getBoundsInPixels ();
4411 if (hwndHeader != 0) {
4412 if (columnCount == 0) {
4413 if (rect.x + rect.width > scrollWidth) {
4414 setScrollWidth (scrollWidth = rect.x + rect.width);
4418 if (rect.height > getItemHeightInPixels ()) setItemHeight (rect.height);
4422 Event sendPaintItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT itemRect) {
4423 int nSavedDC = OS.SaveDC (nmcd.hdc);
4424 RECT insetRect = toolTipInset (itemRect);
4425 OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
4426 GCData data = new GCData ();
4427 data.device = display;
4428 data.font = item.getFont (column);
4429 data.foreground = OS.GetTextColor (nmcd.hdc);
4430 data.background = OS.GetBkColor (nmcd.hdc);
4431 data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
4432 GC gc = GC.win32_new (nmcd.hdc, data);
4433 Event event = new Event ();
4435 event.index = column;
4437 event.detail |= SWT.FOREGROUND;
4438 event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top));
4439 //gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight);
4440 sendEvent (SWT.PaintItem, event);
4443 OS.RestoreDC (nmcd.hdc, nSavedDC);
4448 void setBackgroundImage (long hBitmap) {
4449 super.setBackgroundImage (hBitmap);
4452 * Feature in Windows. If TVM_SETBKCOLOR is never
4453 * used to set the background color of a tree, the
4454 * background color of the lines and the plus/minus
4455 * will be drawn using the default background color,
4456 * not the HBRUSH returned from WM_CTLCOLOR. The fix
4457 * is to set the background color to the default (when
4458 * it is already the default) to make Windows use the
4461 if (OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0) == -1) {
4462 OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1);
4464 _setBackgroundPixel (-1);
4466 Control control = findBackgroundControl ();
4467 if (control == null) control = this;
4468 if (control.backgroundImage == null) {
4469 setBackgroundPixel (control.getBackgroundPixel ());
4473 * Feature in Windows. When the tree has the style
4474 * TVS_FULLROWSELECT, the background color for the
4475 * entire row is filled when an item is painted,
4476 * drawing on top of the background image. The fix
4477 * is to clear TVS_FULLROWSELECT when a background
4480 updateFullSelection ();
4484 void setBackgroundPixel (int pixel) {
4485 Control control = findImageControl ();
4486 if (control != null) {
4487 setBackgroundImage (control.backgroundImage);
4490 _setBackgroundPixel (pixel);
4493 * Feature in Windows. When the tree has the style
4494 * TVS_FULLROWSELECT, the background color for the
4495 * entire row is filled when an item is painted,
4496 * drawing on top of the background image. The fix
4497 * is to restore TVS_FULLROWSELECT when a background
4500 updateFullSelection ();
4506 * Bug in Windows. Under certain circumstances, when WM_SETCURSOR
4507 * is sent from SendMessage(), Windows GP's in the window proc for
4508 * the tree. The fix is to avoid calling the tree window proc and
4509 * set the cursor for the tree outside of WM_SETCURSOR.
4511 * NOTE: This code assumes that the default cursor for the tree
4514 Cursor cursor = findCursor ();
4515 long hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : cursor.handle;
4516 OS.SetCursor (hCursor);
4520 * Sets the order that the items in the receiver should
4521 * be displayed in to the given argument which is described
4522 * in terms of the zero-relative ordering of when the items
4525 * @param order the new order to display the items
4527 * @exception SWTException <ul>
4528 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4529 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4531 * @exception IllegalArgumentException <ul>
4532 * <li>ERROR_NULL_ARGUMENT - if the item order is null</li>
4533 * <li>ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items</li>
4536 * @see Tree#getColumnOrder()
4537 * @see TreeColumn#getMoveable()
4538 * @see TreeColumn#setMoveable(boolean)
4543 public void setColumnOrder (int [] order) {
4545 if (order == null) error (SWT.ERROR_NULL_ARGUMENT);
4546 if (columnCount == 0) {
4547 if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT);
4550 if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT);
4551 int [] oldOrder = new int [columnCount];
4552 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder);
4553 boolean reorder = false;
4554 boolean [] seen = new boolean [columnCount];
4555 for (int i=0; i<order.length; i++) {
4556 int index = order [i];
4557 if (index < 0 || index >= columnCount) error (SWT.ERROR_INVALID_RANGE);
4558 if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT);
4559 seen [index] = true;
4560 if (index != oldOrder [i]) reorder = true;
4563 RECT [] oldRects = new RECT [columnCount];
4564 for (int i=0; i<columnCount; i++) {
4565 oldRects [i] = new RECT ();
4566 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, oldRects [i]);
4568 OS.SendMessage (hwndHeader, OS.HDM_SETORDERARRAY, order.length, order);
4569 OS.InvalidateRect (handle, null, true);
4571 TreeColumn [] newColumns = new TreeColumn [columnCount];
4572 System.arraycopy (columns, 0, newColumns, 0, columnCount);
4573 RECT newRect = new RECT ();
4574 for (int i=0; i<columnCount; i++) {
4575 TreeColumn column = newColumns [i];
4576 if (!column.isDisposed ()) {
4577 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, newRect);
4578 if (newRect.left != oldRects [i].left) {
4579 column.updateToolTip (i);
4580 column.sendEvent (SWT.Move);
4587 void setCheckboxImageList () {
4588 if ((style & SWT.CHECK) == 0) return;
4589 int count = 5, flags = OS.ILC_COLOR32;
4590 if ((style & SWT.RIGHT_TO_LEFT) != 0) flags |= OS.ILC_MIRROR;
4591 if (!OS.IsAppThemed ()) flags |= OS.ILC_MASK;
4592 int height = (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0), width = height;
4593 long hStateList = OS.ImageList_Create (width, height, flags, count, count);
4594 long hDC = OS.GetDC (handle);
4595 long memDC = OS.CreateCompatibleDC (hDC);
4596 long hBitmap = OS.CreateCompatibleBitmap (hDC, width * count, height);
4597 long hOldBitmap = OS.SelectObject (memDC, hBitmap);
4598 RECT rect = new RECT ();
4599 OS.SetRect (rect, 0, 0, width * count, height);
4601 * NOTE: DrawFrameControl() draws a black and white
4602 * mask when not drawing a push button. In order to
4603 * make the box surrounding the check mark transparent,
4604 * fill it with a color that is neither black or white.
4606 int clrBackground = 0;
4607 if (OS.IsAppThemed ()) {
4608 Control control = findBackgroundControl ();
4609 if (control == null) control = this;
4610 clrBackground = control.getBackgroundPixel ();
4612 clrBackground = 0x020000FF;
4613 if ((clrBackground & 0xFFFFFF) == OS.GetSysColor (OS.COLOR_WINDOW)) {
4614 clrBackground = 0x0200FF00;
4617 long hBrush = OS.CreateSolidBrush (clrBackground);
4618 OS.FillRect (memDC, rect, hBrush);
4619 OS.DeleteObject (hBrush);
4620 long oldFont = OS.SelectObject (hDC, defaultFont ());
4621 TEXTMETRIC tm = new TEXTMETRIC ();
4622 OS.GetTextMetrics (hDC, tm);
4623 OS.SelectObject (hDC, oldFont);
4624 int itemWidth = Math.min (tm.tmHeight, width);
4625 int itemHeight = Math.min (tm.tmHeight, height);
4626 if (OS.IsAppThemed()) {
4628 * Feature in Windows. DrawThemeBackground stretches the checkbox
4629 * bitmap to fill the provided rectangle. To avoid stretching
4630 * artifacts, limit the rectangle to actual checkbox bitmap size.
4632 SIZE size = new SIZE();
4633 OS.GetThemePartSize(display.hButtonTheme(), memDC, OS.BP_CHECKBOX, 0, null, OS.TS_TRUE, size);
4634 itemWidth = Math.min (size.cx, itemWidth);
4635 itemHeight = Math.min (size.cy, itemHeight);
4637 int left = (width - itemWidth) / 2, top = (height - itemHeight) / 2 + 1;
4638 OS.SetRect (rect, left + width, top, left + width + itemWidth, top + itemHeight);
4639 if (OS.IsAppThemed ()) {
4640 long hTheme = display.hButtonTheme ();
4641 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4642 rect.left += width; rect.right += width;
4643 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_CHECKEDNORMAL, rect, null);
4644 rect.left += width; rect.right += width;
4645 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_UNCHECKEDNORMAL, rect, null);
4646 rect.left += width; rect.right += width;
4647 OS.DrawThemeBackground (hTheme, memDC, OS.BP_CHECKBOX, OS.CBS_MIXEDNORMAL, rect, null);
4649 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_FLAT);
4650 rect.left += width; rect.right += width;
4651 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_FLAT);
4652 rect.left += width; rect.right += width;
4653 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4654 rect.left += width; rect.right += width;
4655 OS.DrawFrameControl (memDC, rect, OS.DFC_BUTTON, OS.DFCS_BUTTONCHECK | OS.DFCS_CHECKED | OS.DFCS_INACTIVE | OS.DFCS_FLAT);
4657 OS.SelectObject (memDC, hOldBitmap);
4658 OS.DeleteDC (memDC);
4659 OS.ReleaseDC (handle, hDC);
4660 if (OS.IsAppThemed ()) {
4661 OS.ImageList_Add (hStateList, hBitmap, 0);
4663 OS.ImageList_AddMasked (hStateList, hBitmap, clrBackground);
4665 OS.DeleteObject (hBitmap);
4666 long hOldStateList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_STATE, 0);
4667 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_STATE, hStateList);
4668 if (hOldStateList != 0) OS.ImageList_Destroy (hOldStateList);
4672 public void setFont (Font font) {
4674 super.setFont (font);
4675 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
4679 void setForegroundPixel (int pixel) {
4681 * Bug in Windows. When the tree is using the explorer
4682 * theme, it does not use COLOR_WINDOW_TEXT for the
4683 * foreground. When TVM_SETTEXTCOLOR is called with -1,
4684 * it resets the color to black, not COLOR_WINDOW_TEXT.
4685 * The fix is to explicitly set the color.
4687 if (explorerTheme) {
4688 if (pixel == -1) pixel = defaultForeground ();
4690 OS.SendMessage (handle, OS.TVM_SETTEXTCOLOR, 0, pixel);
4694 * Sets the header background color to the color specified
4695 * by the argument, or to the default system color if the argument is null.
4697 * Note: This operation is a <em>HINT</em> and is not supported on all platforms. If
4698 * the native header has a 3D look and feel (e.g. Windows 7), this method
4699 * will cause the header to look FLAT irrespective of the state of the tree style.
4701 * @param color the new color (or null)
4703 * @exception IllegalArgumentException <ul>
4704 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
4706 * @exception SWTException <ul>
4707 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4708 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4712 public void setHeaderBackground (Color color) {
4715 if (color != null) {
4716 if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4717 pixel = color.handle;
4719 if (pixel == headerBackground) return;
4720 headerBackground = pixel;
4721 if (getHeaderVisible()) {
4722 OS.InvalidateRect (hwndHeader, null, true);
4727 * Sets the header foreground color to the color specified
4728 * by the argument, or to the default system color if the argument is null.
4730 * Note: This operation is a <em>HINT</em> and is not supported on all platforms. If
4731 * the native header has a 3D look and feel (e.g. Windows 7), this method
4732 * will cause the header to look FLAT irrespective of the state of the tree style.
4734 * @param color the new color (or null)
4736 * @exception IllegalArgumentException <ul>
4737 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
4739 * @exception SWTException <ul>
4740 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4741 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4745 public void setHeaderForeground (Color color) {
4748 if (color != null) {
4749 if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
4750 pixel = color.handle;
4752 if (pixel == headerForeground) return;
4753 headerForeground = pixel;
4754 if (getHeaderVisible()) {
4755 OS.InvalidateRect (hwndHeader, null, true);
4760 * Marks the receiver's header as visible if the argument is <code>true</code>,
4761 * and marks it invisible otherwise.
4763 * If one of the receiver's ancestors is not visible or some
4764 * other condition makes the receiver not visible, marking
4765 * it visible may not actually cause it to be displayed.
4768 * @param show the new visibility state
4770 * @exception SWTException <ul>
4771 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4772 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4777 public void setHeaderVisible (boolean show) {
4779 if (hwndHeader == 0) {
4783 int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE);
4785 if ((bits & OS.HDS_HIDDEN) == 0) return;
4786 bits &= ~OS.HDS_HIDDEN;
4787 OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4788 OS.ShowWindow (hwndHeader, OS.SW_SHOW);
4790 if ((bits & OS.HDS_HIDDEN) != 0) return;
4791 bits |= OS.HDS_HIDDEN;
4792 OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits);
4793 OS.ShowWindow (hwndHeader, OS.SW_HIDE);
4796 updateHeaderToolTips ();
4801 public void setRedraw (boolean redraw) {
4804 * Feature in Windows. When WM_SETREDRAW is used to
4805 * turn off redraw, the scroll bars are updated when
4806 * items are added and removed. The fix is to call
4807 * the default window proc to stop all drawing.
4809 * Bug in Windows. For some reason, when WM_SETREDRAW
4810 * is used to turn redraw on for a tree and the tree
4811 * contains no items, the last item in the tree does
4812 * not redraw properly. If the tree has only one item,
4813 * that item is not drawn. If another window is dragged
4814 * on top of the item, parts of the item are redrawn
4815 * and erased at random. The fix is to ensure that this
4816 * case doesn't happen by inserting and deleting an item
4817 * when redraw is turned on and there are no items in
4821 boolean willEnableDraw = redraw && (drawCount == 1);
4822 if (willEnableDraw) {
4823 int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
4825 TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT ();
4826 tvInsert.hInsertAfter = OS.TVI_FIRST;
4827 hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert);
4829 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
4833 super.setRedraw (redraw);
4835 boolean haveDisabledDraw = !redraw && (drawCount == 1);
4836 if (haveDisabledDraw) {
4837 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
4840 ignoreShrink = true;
4841 OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem);
4842 ignoreShrink = false;
4846 void setScrollWidth () {
4847 if (hwndHeader == 0 || hwndParent == 0) return;
4849 HDITEM hdItem = new HDITEM ();
4850 for (int i=0; i<columnCount; i++) {
4851 hdItem.mask = OS.HDI_WIDTH;
4852 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
4853 width += hdItem.cxy;
4855 setScrollWidth (Math.max (scrollWidth, width));
4858 void setScrollWidth (int width) {
4859 if (hwndHeader == 0 || hwndParent == 0) return;
4861 //scrollWidth = width;
4863 RECT rect = new RECT ();
4864 SCROLLINFO info = new SCROLLINFO ();
4865 info.cbSize = SCROLLINFO.sizeof;
4866 info.fMask = OS.SIF_RANGE | OS.SIF_PAGE;
4867 if (columnCount == 0 && width == 0) {
4868 OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4869 info.nPage = info.nMax + 1;
4870 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4871 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
4872 info.nPage = info.nMax + 1;
4873 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
4875 if ((style & SWT.H_SCROLL) != 0) {
4876 OS.GetClientRect (hwndParent, rect);
4877 OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4879 info.nPage = rect.right - rect.left + 1;
4880 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
4881 info.fMask = OS.SIF_POS;
4882 OS.GetScrollInfo (hwndParent, OS.SB_HORZ, info);
4886 if (horizontalBar != null) {
4887 horizontalBar.setIncrement (INCREMENT);
4888 horizontalBar.setPageIncrement (info.nPage);
4890 OS.GetClientRect (hwndParent, rect);
4891 long hHeap = OS.GetProcessHeap ();
4892 HDLAYOUT playout = new HDLAYOUT ();
4893 playout.prc = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, RECT.sizeof);
4894 playout.pwpos = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, WINDOWPOS.sizeof);
4895 OS.MoveMemory (playout.prc, rect, RECT.sizeof);
4896 OS.SendMessage (hwndHeader, OS.HDM_LAYOUT, 0, playout);
4897 WINDOWPOS pos = new WINDOWPOS ();
4898 OS.MoveMemory (pos, playout.pwpos, WINDOWPOS.sizeof);
4899 if (playout.prc != 0) OS.HeapFree (hHeap, 0, playout.prc);
4900 if (playout.pwpos != 0) OS.HeapFree (hHeap, 0, playout.pwpos);
4901 OS.SetWindowPos (hwndHeader, OS.HWND_TOP, pos.x - left, pos.y, pos.cx + left, pos.cy, OS.SWP_NOACTIVATE);
4902 int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE);
4903 int b = (bits & OS.WS_EX_CLIENTEDGE) != 0 ? OS.GetSystemMetrics (OS.SM_CXEDGE) : 0;
4904 int w = pos.cx + (columnCount == 0 && width == 0 ? 0 : OS.GetSystemMetrics (OS.SM_CXVSCROLL));
4905 int h = rect.bottom - rect.top - pos.cy;
4906 boolean oldIgnore = ignoreResize;
4907 ignoreResize = true;
4908 OS.SetWindowPos (handle, 0, pos.x - left - b, pos.y + pos.cy - b, w + left + b * 2, h + b * 2, OS.SWP_NOACTIVATE | OS.SWP_NOZORDER);
4909 ignoreResize = oldIgnore;
4912 void setSelection (long hItem, TVITEM tvItem, TreeItem [] selection) {
4913 while (hItem != 0) {
4915 while (index < selection.length) {
4916 TreeItem item = selection [index];
4917 if (item != null && item.handle == hItem) break;
4920 tvItem.hItem = hItem;
4921 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
4922 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
4923 if (index == selection.length) {
4925 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4928 if (index != selection.length) {
4929 expandToItem(_getItem(hItem));
4930 tvItem.state = OS.TVIS_SELECTED;
4931 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
4934 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem);
4935 setSelection (hFirstItem, tvItem, selection);
4936 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem);
4941 * Sets the receiver's selection to the given item.
4942 * The current selection is cleared before the new item is selected,
4943 * and if necessary the receiver is scrolled to make the new selection visible.
4945 * If the item is not in the receiver, then it is ignored.
4948 * @param item the item to select
4950 * @exception IllegalArgumentException <ul>
4951 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
4952 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
4954 * @exception SWTException <ul>
4955 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4956 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4961 public void setSelection (TreeItem item) {
4963 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
4964 setSelection (new TreeItem [] {item});
4968 * Sets the receiver's selection to be the given array of items.
4969 * The current selection is cleared before the new items are selected,
4970 * and if necessary the receiver is scrolled to make the new selection visible.
4972 * Items that are not in the receiver are ignored.
4973 * If the receiver is single-select and multiple items are specified,
4974 * then all items are ignored.
4977 * @param items the array of items
4979 * @exception IllegalArgumentException <ul>
4980 * <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
4981 * <li>ERROR_INVALID_ARGUMENT - if one of the items has been disposed</li>
4983 * @exception SWTException <ul>
4984 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4985 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4988 * @see Tree#deselectAll()
4990 public void setSelection (TreeItem [] items) {
4992 if (items == null) error (SWT.ERROR_NULL_ARGUMENT);
4993 int length = items.length;
4994 if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) {
4999 /* Select/deselect the first item */
5000 TreeItem item = items [0];
5002 if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5003 long hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5004 long hNewItem = hAnchor = item.handle;
5007 * Bug in Windows. When TVM_SELECTITEM is used to select and
5008 * scroll an item to be visible and the client area of the tree
5009 * is smaller that the size of one item, TVM_SELECTITEM makes
5010 * the next item in the tree visible by making it the top item
5011 * instead of making the desired item visible. The fix is to
5012 * detect the case when the client area is too small and make
5013 * the desired visible item be the top item in the tree.
5015 * Note that TVM_SELECTITEM when called with TVGN_FIRSTVISIBLE
5016 * also requires the work around for scrolling.
5018 boolean fixScroll = checkScroll (hNewItem);
5020 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5021 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5023 ignoreSelect = true;
5024 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
5025 ignoreSelect = false;
5026 if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
5027 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hNewItem);
5028 long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hNewItem);
5029 if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5032 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5033 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5037 * Feature in Windows. When the old and new focused item
5038 * are the same, Windows does not check to make sure that
5039 * the item is actually selected, not just focused. The
5040 * fix is to force the item to draw selected by setting
5041 * the state mask, and to ensure that it is visible.
5043 if (hOldItem == hNewItem) {
5044 TVITEM tvItem = new TVITEM ();
5045 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5046 tvItem.state = OS.TVIS_SELECTED;
5047 tvItem.stateMask = OS.TVIS_SELECTED;
5048 tvItem.hItem = hNewItem;
5049 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5050 showItem (hNewItem);
5053 if ((style & SWT.SINGLE) != 0) return;
5055 /* Select/deselect the rest of the items */
5056 TVITEM tvItem = new TVITEM ();
5057 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
5058 tvItem.stateMask = OS.TVIS_SELECTED;
5059 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
5060 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
5061 if ((style & SWT.VIRTUAL) != 0) {
5062 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
5063 setSelection (hItem, tvItem, items);
5065 for (int i=0; i<this.items.length; i++) {
5066 item = this.items [i];
5069 while (index < length) {
5070 if (items [index] == item) break;
5073 tvItem.hItem = item.handle;
5074 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
5075 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
5076 if (index == length) {
5078 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5081 if (index != length) {
5083 tvItem.state = OS.TVIS_SELECTED;
5084 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
5090 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
5093 void expandToItem(TreeItem item) {
5094 TreeItem parentItem = item.getParentItem();
5095 if (parentItem != null && !parentItem.getExpanded()) {
5096 expandToItem(parentItem);
5097 parentItem.setExpanded(true);
5098 Event event = new Event ();
5099 event.item = parentItem;
5100 sendEvent (SWT.Expand, event);
5105 * Sets the column used by the sort indicator for the receiver. A null
5106 * value will clear the sort indicator. The current sort column is cleared
5107 * before the new column is set.
5109 * @param column the column used by the sort indicator or <code>null</code>
5111 * @exception IllegalArgumentException <ul>
5112 * <li>ERROR_INVALID_ARGUMENT - if the column is disposed</li>
5114 * @exception SWTException <ul>
5115 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5116 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5121 public void setSortColumn (TreeColumn column) {
5123 if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5124 if (sortColumn != null && !sortColumn.isDisposed ()) {
5125 sortColumn.setSortDirection (SWT.NONE);
5127 sortColumn = column;
5128 if (sortColumn != null && sortDirection != SWT.NONE) {
5129 sortColumn.setSortDirection (sortDirection);
5134 * Sets the direction of the sort indicator for the receiver. The value
5135 * can be one of <code>UP</code>, <code>DOWN</code> or <code>NONE</code>.
5137 * @param direction the direction of the sort indicator
5139 * @exception SWTException <ul>
5140 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5141 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5146 public void setSortDirection (int direction) {
5148 if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) return;
5149 sortDirection = direction;
5150 if (sortColumn != null && !sortColumn.isDisposed ()) {
5151 sortColumn.setSortDirection (direction);
5156 * Sets the item which is currently at the top of the receiver.
5157 * This item can change when items are expanded, collapsed, scrolled
5158 * or new items are added or removed.
5160 * @param item the item to be shown
5162 * @exception IllegalArgumentException <ul>
5163 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5164 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5166 * @exception SWTException <ul>
5167 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5168 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5171 * @see Tree#getTopItem()
5175 public void setTopItem (TreeItem item) {
5177 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
5178 if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
5179 long hItem = item.handle;
5180 long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5181 if (hItem == hTopItem) return;
5182 boolean fixScroll = checkScroll (hItem), redraw = false;
5184 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5185 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5187 redraw = getDrawing () && OS.IsWindowVisible (handle);
5188 if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5190 SCROLLINFO hInfo = null;
5191 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
5192 long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
5193 if (hParent != 0 && (bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) {
5194 hInfo = new SCROLLINFO ();
5195 hInfo.cbSize = SCROLLINFO.sizeof;
5196 hInfo.fMask = OS.SIF_ALL;
5197 OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo);
5199 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
5201 if (hInfo != null) {
5202 long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos);
5203 OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0);
5206 OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5209 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5210 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5213 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5214 OS.InvalidateRect (handle, null, true);
5220 void showItem (long hItem) {
5222 * Bug in Windows. When TVM_ENSUREVISIBLE is used to ensure
5223 * that an item is visible and the client area of the tree is
5224 * smaller that the size of one item, TVM_ENSUREVISIBLE makes
5225 * the next item in the tree visible by making it the top item
5226 * instead of making the desired item visible. The fix is to
5227 * detect the case when the client area is too small and make
5228 * the desired visible item be the top item in the tree.
5230 if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) {
5231 boolean fixScroll = checkScroll (hItem);
5233 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5234 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5236 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem);
5237 /* This code is intentionally commented */
5238 //int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
5239 //if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5240 OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0);
5242 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5243 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5246 boolean scroll = true;
5247 RECT itemRect = new RECT ();
5248 if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) {
5250 RECT rect = new RECT ();
5251 OS.GetClientRect (handle, rect);
5252 POINT pt = new POINT ();
5253 pt.x = itemRect.left;
5254 pt.y = itemRect.top;
5255 if (OS.PtInRect (rect, pt)) {
5256 pt.y = itemRect.bottom;
5257 if (OS.PtInRect (rect, pt)) scroll = false;
5261 boolean fixScroll = checkScroll (hItem);
5263 OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0);
5264 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
5266 OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
5268 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
5269 OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0);
5273 if (hwndParent != 0) {
5274 RECT itemRect = new RECT ();
5275 if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) {
5277 RECT rect = new RECT ();
5278 OS.GetClientRect (hwndParent, rect);
5279 OS.MapWindowPoints (hwndParent, handle, rect, 2);
5280 POINT pt = new POINT ();
5281 pt.x = itemRect.left;
5282 pt.y = itemRect.top;
5283 if (!OS.PtInRect (rect, pt)) {
5284 pt.y = itemRect.bottom;
5285 if (!OS.PtInRect (rect, pt)) {
5286 SCROLLINFO info = new SCROLLINFO ();
5287 info.cbSize = SCROLLINFO.sizeof;
5288 info.fMask = OS.SIF_POS;
5289 info.nPos = Math.max (0, pt.x - Tree.INSET / 2);
5290 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
5300 * Shows the column. If the column is already showing in the receiver,
5301 * this method simply returns. Otherwise, the columns are scrolled until
5302 * the column is visible.
5304 * @param column the column to be shown
5306 * @exception IllegalArgumentException <ul>
5307 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5308 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5310 * @exception SWTException <ul>
5311 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5312 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5317 public void showColumn (TreeColumn column) {
5319 if (column == null) error (SWT.ERROR_NULL_ARGUMENT);
5320 if (column.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
5321 if (column.parent != this) return;
5322 int index = indexOf (column);
5323 if (index == -1) return;
5324 if (0 <= index && index < columnCount) {
5326 RECT rect = new RECT ();
5327 OS.GetClientRect (hwndParent, rect);
5328 OS.MapWindowPoints (hwndParent, handle, rect, 2);
5329 RECT headerRect = new RECT ();
5330 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect);
5331 boolean scroll = headerRect.left < rect.left;
5333 int width = Math.min (rect.right - rect.left, headerRect.right - headerRect.left);
5334 scroll = headerRect.left + width > rect.right;
5337 SCROLLINFO info = new SCROLLINFO ();
5338 info.cbSize = SCROLLINFO.sizeof;
5339 info.fMask = OS.SIF_POS;
5340 info.nPos = Math.max (0, headerRect.left - Tree.INSET / 2);
5341 OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true);
5348 * Shows the item. If the item is already showing in the receiver,
5349 * this method simply returns. Otherwise, the items are scrolled
5350 * and expanded until the item is visible.
5352 * @param item the item to be shown
5354 * @exception IllegalArgumentException <ul>
5355 * <li>ERROR_NULL_ARGUMENT - if the item is null</li>
5356 * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
5358 * @exception SWTException <ul>
5359 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5360 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5363 * @see Tree#showSelection()
5365 public void showItem (TreeItem item) {
5367 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
5368 if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT);
5369 showItem (item.handle);
5373 * Shows the selection. If the selection is already showing in the receiver,
5374 * this method simply returns. Otherwise, the items are scrolled until
5375 * the selection is visible.
5377 * @exception SWTException <ul>
5378 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5379 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5382 * @see Tree#showItem(TreeItem)
5384 public void showSelection () {
5387 if ((style & SWT.SINGLE) != 0) {
5388 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
5389 if (hItem == 0) return;
5390 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED);
5391 if ((state & OS.TVIS_SELECTED) == 0) return;
5393 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
5394 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
5395 if ((style & SWT.VIRTUAL) != 0) {
5396 long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
5397 hItem = getNextSelection (hRoot);
5399 //FIXME - this code expands first selected item it finds
5401 while (index <items.length) {
5402 TreeItem item = items [index];
5404 int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, item.handle, OS.TVIS_SELECTED);
5405 if ((state & OS.TVIS_SELECTED) != 0) {
5406 hItem = item.handle;
5413 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
5415 if (hItem != 0) showItem (hItem);
5418 /*public*/ void sort () {
5420 if ((style & SWT.VIRTUAL) != 0) return;
5421 sort (OS.TVI_ROOT, false);
5424 void sort (long hParent, boolean all) {
5425 int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
5426 if (itemCount == 0 || itemCount == 1) return;
5427 hFirstIndexOf = hLastIndexOf = 0;
5429 if (sortDirection == SWT.UP || sortDirection == SWT.NONE) {
5430 OS.SendMessage (handle, OS.TVM_SORTCHILDREN, all ? 1 : 0, hParent);
5432 Callback compareCallback = new Callback (this, "CompareFunc", 3);
5433 long lpfnCompare = compareCallback.getAddress ();
5434 TVSORTCB psort = new TVSORTCB ();
5435 psort.hParent = hParent;
5436 psort.lpfnCompare = lpfnCompare;
5437 psort.lParam = sortColumn == null ? 0 : indexOf (sortColumn);
5438 OS.SendMessage (handle, OS.TVM_SORTCHILDRENCB, all ? 1 : 0, psort);
5439 compareCallback.dispose ();
5446 if (hwndHeader != 0) {
5447 OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, display.windowProc);
5451 RECT toolTipInset (RECT rect) {
5452 RECT insetRect = new RECT ();
5453 OS.SetRect (insetRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
5457 RECT toolTipRect (RECT rect) {
5458 RECT toolRect = new RECT ();
5459 OS.SetRect (toolRect, rect.left - 1, rect.top - 1, rect.right + 1, rect.bottom + 1);
5464 String toolTipText (NMTTDISPINFO hdr) {
5465 long hwndToolTip = OS.SendMessage (handle, OS.TVM_GETTOOLTIPS, 0, 0);
5466 if (hwndToolTip == hdr.hwndFrom && toolTipText != null) return ""; //$NON-NLS-1$
5467 if (headerToolTipHandle == hdr.hwndFrom) {
5468 for (int i=0; i<columnCount; i++) {
5469 TreeColumn column = columns [i];
5470 if (column.id == hdr.idFrom) return column.toolTipText;
5472 return super.toolTipText (hdr);
5474 if (itemToolTipHandle == hdr.hwndFrom) {
5475 if (toolTipText != null) return "";
5476 int pos = OS.GetMessagePos ();
5477 POINT pt = new POINT();
5478 OS.POINTSTOPOINT (pt, pos);
5479 OS.ScreenToClient (handle, pt);
5480 int [] index = new int [1];
5481 TreeItem [] item = new TreeItem [1];
5482 RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
5483 if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
5485 if (index [0] == 0) {
5486 text = item [0].text;
5488 String[] strings = item [0].strings;
5489 if (strings != null) text = strings [index [0]];
5492 if (isCustomToolTip ()) text = " ";
5493 if (text != null) return text;
5496 return super.toolTipText (hdr);
5501 return hwndParent != 0 ? hwndParent : handle;
5504 void updateFullSelection () {
5505 if ((style & SWT.FULL_SELECTION) != 0) {
5506 int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
5507 if ((newBits & OS.TVS_FULLROWSELECT) != 0) {
5508 if (!OS.IsWindowEnabled (handle) || findImageControl () != null) {
5509 if (!explorerTheme) newBits &= ~OS.TVS_FULLROWSELECT;
5512 if (OS.IsWindowEnabled (handle) && findImageControl () == null) {
5513 if (!hooks (SWT.EraseItem) && !hooks (SWT.PaintItem)) {
5514 newBits |= OS.TVS_FULLROWSELECT;
5518 if (newBits != oldBits) {
5519 OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
5520 OS.InvalidateRect (handle, null, true);
5525 void updateHeaderToolTips () {
5526 if (headerToolTipHandle == 0) return;
5527 RECT rect = new RECT ();
5528 TOOLINFO lpti = new TOOLINFO ();
5529 lpti.cbSize = TOOLINFO.sizeof;
5530 lpti.uFlags = OS.TTF_SUBCLASS;
5531 lpti.hwnd = hwndHeader;
5532 lpti.lpszText = OS.LPSTR_TEXTCALLBACK;
5533 for (int i=0; i<columnCount; i++) {
5534 TreeColumn column = columns [i];
5535 if (OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, rect) != 0) {
5536 lpti.uId = column.id = display.nextToolTipId++;
5537 lpti.left = rect.left;
5538 lpti.top = rect.top;
5539 lpti.right = rect.right;
5540 lpti.bottom = rect.bottom;
5541 OS.SendMessage (headerToolTipHandle, OS.TTM_ADDTOOL, 0, lpti);
5546 void updateImageList () {
5547 if (imageList == null) return;
5548 if (hwndHeader == 0) return;
5549 int i = 0, index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
5550 while (i < items.length) {
5551 TreeItem item = items [i];
5557 Image [] images = item.images;
5558 if (images != null) image = images [index];
5560 if (image != null) break;
5565 * Feature in Windows. When setting the same image list multiple
5566 * times, Windows does work making this operation slow. The fix
5567 * is to test for the same image list before setting the new one.
5569 long hImageList = i == items.length ? 0 : imageList.getHandle ();
5570 long hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0);
5571 if (hImageList != hOldImageList) {
5572 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
5577 void updateMenuLocation (Event event) {
5578 Rectangle clientArea = getClientAreaInPixels ();
5579 int x = clientArea.x, y = clientArea.y;
5580 TreeItem focusItem = getFocusItem ();
5581 if (focusItem != null) {
5582 Rectangle bounds = focusItem.getBoundsInPixels (0);
5583 if (focusItem.text != null && focusItem.text.length () != 0) {
5584 bounds = focusItem.getBoundsInPixels ();
5586 x = Math.max (x, bounds.x + bounds.width / 2);
5587 x = Math.min (x, clientArea.x + clientArea.width);
5588 y = Math.max (y, bounds.y + bounds.height);
5589 y = Math.min (y, clientArea.y + clientArea.height);
5591 Point pt = toDisplayInPixels (x, y);
5592 event.setLocationInPixels(pt.x, pt.y);
5596 void updateOrientation () {
5597 super.updateOrientation ();
5598 RECT rect = new RECT ();
5599 OS.GetWindowRect (handle, rect);
5600 int width = rect.right - rect.left, height = rect.bottom - rect.top;
5601 OS.SetWindowPos (handle, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5602 OS.SetWindowPos (handle, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5603 if (hwndParent != 0) {
5604 int bits = OS.GetWindowLong (hwndParent, OS.GWL_EXSTYLE);
5605 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
5606 bits |= OS.WS_EX_LAYOUTRTL;
5608 bits &= ~OS.WS_EX_LAYOUTRTL;
5610 bits &= ~OS.WS_EX_RTLREADING;
5611 OS.SetWindowLong (hwndParent, OS.GWL_EXSTYLE, bits);
5613 OS.GetWindowRect (hwndParent, rect);
5614 width = rect.right - rect.left; height = rect.bottom - rect.top;
5615 OS.SetWindowPos (hwndParent, 0, 0, 0, width - 1, height - 1, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5616 OS.SetWindowPos (hwndParent, 0, 0, 0, width, height, OS.SWP_NOMOVE | OS.SWP_NOZORDER);
5618 if (hwndHeader != 0) {
5619 int bits = OS.GetWindowLong (hwndHeader, OS.GWL_EXSTYLE);
5620 if ((style & SWT.RIGHT_TO_LEFT) != 0) {
5621 bits |= OS.WS_EX_LAYOUTRTL;
5623 bits &= ~OS.WS_EX_LAYOUTRTL;
5625 OS.SetWindowLong (hwndHeader, OS.GWL_EXSTYLE, bits);
5626 OS.InvalidateRect (hwndHeader, null, true);
5628 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
5629 if (imageList != null) {
5630 Point size = imageList.getImageSize ();
5631 display.releaseImageList (imageList);
5632 imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, size.x, size.y);
5633 for (int i = 0; i < items.length; i++) {
5634 TreeItem item = items[i];
5636 Image image = item.image;
5637 if (image != null) {
5638 int index = imageList.indexOf (image);
5639 if (index == -1) imageList.add (image);
5643 long hImageList = imageList.getHandle ();
5644 OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList);
5646 if (hwndHeader != 0) {
5647 if (headerImageList != null) {
5648 Point size = headerImageList.getImageSize ();
5649 display.releaseImageList (headerImageList);
5650 headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, size.x, size.y);
5651 if (columns != null) {
5652 for (int i = 0; i < columns.length; i++) {
5653 TreeColumn column = columns[i];
5654 if (column != null) {
5655 Image image = column.image;
5656 if (image != null) {
5657 HDITEM hdItem = new HDITEM ();
5658 hdItem.mask = OS.HDI_FORMAT;
5659 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, i, hdItem);
5660 if ((hdItem.fmt & OS.HDF_IMAGE)!= 0) {
5661 int index = headerImageList.indexOf (image);
5662 if (index == -1) index = headerImageList.add (image);
5663 hdItem.mask = OS.HDI_IMAGE;
5664 hdItem.iImage = index;
5665 OS.SendMessage (hwndHeader, OS.HDM_SETITEM, i, hdItem);
5671 long hImageListHeader = headerImageList.getHandle ();
5672 OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageListHeader);
5678 * Copies Tree's scrollbar state to intermediate parent.
5680 * If Tree has a header, then (Tree+header) get wrapped into intermediate
5681 * parent. This parent also has scrollbar, and it is configured to
5682 * obscure the Tree's scrollbar - I think this is due to aesthetic
5683 * reasons where the new scrollbar also extends over header. Since it
5684 * obscures the true scrollbar, it always needs to be in sync with the
5687 void updateScrollBar () {
5688 if (hwndParent != 0) {
5689 if (columnCount != 0 || scrollWidth != 0) {
5690 SCROLLINFO info = new SCROLLINFO ();
5691 info.cbSize = SCROLLINFO.sizeof;
5692 info.fMask = OS.SIF_ALL;
5693 int itemCount = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0);
5694 if (itemCount == 0) {
5695 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5696 info.nPage = info.nMax + 1;
5697 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5699 OS.GetScrollInfo (handle, OS.SB_VERT, info);
5700 if (info.nPage == 0) {
5701 SCROLLBARINFO psbi = new SCROLLBARINFO ();
5702 psbi.cbSize = SCROLLBARINFO.sizeof;
5703 OS.GetScrollBarInfo (handle, OS.OBJID_VSCROLL, psbi);
5704 if ((psbi.rgstate [0] & OS.STATE_SYSTEM_INVISIBLE) != 0) {
5705 info.nPage = info.nMax + 1;
5708 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5715 void unsubclass () {
5716 super.unsubclass ();
5717 if (hwndHeader != 0) {
5718 OS.SetWindowLongPtr (hwndHeader, OS.GWLP_WNDPROC, HeaderProc);
5723 int widgetStyle () {
5724 int bits = super.widgetStyle () | OS.TVS_SHOWSELALWAYS | OS.TVS_LINESATROOT | OS.TVS_HASBUTTONS | OS.TVS_NONEVENHEIGHT;
5725 if (OS.IsAppThemed ()) {
5726 bits |= OS.TVS_TRACKSELECT;
5727 if ((style & SWT.FULL_SELECTION) != 0) bits |= OS.TVS_FULLROWSELECT;
5729 if ((style & SWT.FULL_SELECTION) != 0) {
5730 bits |= OS.TVS_FULLROWSELECT;
5732 bits |= OS.TVS_HASLINES;
5735 if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) {
5736 bits &= ~(OS.WS_HSCROLL | OS.WS_VSCROLL);
5737 bits |= OS.TVS_NOSCROLL;
5739 if ((style & SWT.H_SCROLL) == 0) {
5740 bits &= ~OS.WS_HSCROLL;
5741 bits |= OS.TVS_NOHSCROLL;
5744 // bits |= OS.TVS_NOTOOLTIPS | OS.TVS_DISABLEDRAGDROP;
5745 return bits | OS.TVS_DISABLEDRAGDROP;
5749 TCHAR windowClass () {
5754 long windowProc () {
5759 long windowProc (long hwnd, int msg, long wParam, long lParam) {
5760 if (hwndHeader != 0 && hwnd == hwndHeader) {
5762 case OS.WM_CONTEXTMENU: {
5763 LRESULT result = wmContextMenu (hwnd, wParam, lParam);
5764 if (result != null) return result.value;
5767 case OS.WM_MOUSELEAVE: {
5769 * Bug in Windows. On XP, when a tooltip is hidden
5770 * due to a time out or mouse press, the tooltip
5771 * remains active although no longer visible and
5772 * won't show again until another tooltip becomes
5773 * active. The fix is to reset the tooltip bounds.
5775 updateHeaderToolTips ();
5776 updateHeaderToolTips ();
5779 case OS.WM_NOTIFY: {
5780 NMHDR hdr = new NMHDR ();
5781 OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
5785 case OS.TTN_GETDISPINFO:
5786 return OS.SendMessage (handle, msg, wParam, lParam);
5790 case OS.WM_SETCURSOR: {
5791 if (wParam == hwnd) {
5792 int hitTest = (short) OS.LOWORD (lParam);
5793 if (hitTest == OS.HTCLIENT) {
5794 HDHITTESTINFO pinfo = new HDHITTESTINFO ();
5795 int pos = OS.GetMessagePos ();
5796 POINT pt = new POINT ();
5797 OS.POINTSTOPOINT (pt, pos);
5798 OS.ScreenToClient (hwnd, pt);
5801 int index = (int)OS.SendMessage (hwndHeader, OS.HDM_HITTEST, 0, pinfo);
5802 if (0 <= index && index < columnCount && !columns [index].resizable) {
5803 if ((pinfo.flags & (OS.HHT_ONDIVIDER | OS.HHT_ONDIVOPEN)) != 0) {
5804 OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
5813 return callWindowProc (hwnd, msg, wParam, lParam);
5815 if (hwndParent != 0 && hwnd == hwndParent) {
5818 sendEvent (SWT.Move);
5823 if (ignoreResize) return 0;
5824 setResizeChildren (false);
5825 long code = callWindowProc (hwnd, OS.WM_SIZE, wParam, lParam);
5826 sendEvent (SWT.Resize);
5827 if (isDisposed ()) return 0;
5828 if (layout != null) {
5829 markLayout (false, false);
5830 updateLayout (false, false);
5832 setResizeChildren (true);
5836 case OS.WM_NCPAINT: {
5837 LRESULT result = wmNCPaint (hwnd, wParam, lParam);
5838 if (result != null) return result.value;
5842 LRESULT result = wmPrint (hwnd, wParam, lParam);
5843 if (result != null) return result.value;
5848 case OS.WM_SYSCOLORCHANGE: {
5849 return OS.SendMessage (handle, msg, wParam, lParam);
5851 case OS.WM_HSCROLL: {
5853 * Bug on WinCE. lParam should be NULL when the message is not sent
5854 * by a scroll bar control, but it contains the handle to the window.
5855 * When the message is sent by a scroll bar control, it correctly
5856 * contains the handle to the scroll bar. The fix is to check for
5859 if (horizontalBar != null && (lParam == 0 || lParam == hwndParent)) {
5860 wmScroll (horizontalBar, true, hwndParent, OS.WM_HSCROLL, wParam, lParam);
5865 case OS.WM_VSCROLL: {
5866 SCROLLINFO info = new SCROLLINFO ();
5867 info.cbSize = SCROLLINFO.sizeof;
5868 info.fMask = OS.SIF_ALL;
5869 OS.GetScrollInfo (hwndParent, OS.SB_VERT, info);
5871 * Update the nPos field to match the nTrackPos field
5872 * so that the tree scrolls when the scroll bar of the
5873 * parent is dragged.
5875 * NOTE: For some reason, this code is only necessary
5878 if (OS.LOWORD (wParam) == OS.SB_THUMBTRACK) {
5879 info.nPos = info.nTrackPos;
5881 OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
5882 long code = OS.SendMessage (handle, OS.WM_VSCROLL, wParam, lParam);
5883 OS.GetScrollInfo (handle, OS.SB_VERT, info);
5884 OS.SetScrollInfo (hwndParent, OS.SB_VERT, info, true);
5888 return callWindowProc (hwnd, msg, wParam, lParam);
5890 if (msg == Display.DI_GETDRAGIMAGE) {
5892 * When there is more than one item selected, DI_GETDRAGIMAGE
5893 * returns the item under the cursor. This happens because
5894 * the tree does not have implement multi-select. The fix
5895 * is to disable DI_GETDRAGIMAGE when more than one item is
5898 if ((style & SWT.MULTI) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) {
5899 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
5900 TreeItem [] items = new TreeItem [10];
5901 TVITEM tvItem = new TVITEM ();
5902 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
5903 int count = getSelection (hItem, tvItem, items, 0, 10, false, true);
5904 if (count == 0) return 0;
5905 POINT mousePos = new POINT ();
5906 OS.POINTSTOPOINT (mousePos, OS.GetMessagePos ());
5907 OS.MapWindowPoints (0, handle, mousePos, 1);
5908 RECT clientRect = new RECT ();
5909 OS.GetClientRect(handle, clientRect);
5910 RECT rect = items [0].getBounds (0, true, true, false);
5911 if ((style & SWT.FULL_SELECTION) != 0) {
5912 int width = DRAG_IMAGE_SIZE;
5913 rect.left = Math.max (clientRect.left, mousePos.x - width / 2);
5914 if (clientRect.right > rect.left + width) {
5915 rect.right = rect.left + width;
5917 rect.right = clientRect.right;
5918 rect.left = Math.max (clientRect.left, rect.right - width);
5921 rect.left = Math.max (rect.left, clientRect.left);
5922 rect.right = Math.min (rect.right, clientRect.right);
5924 long hRgn = OS.CreateRectRgn (rect.left, rect.top, rect.right, rect.bottom);
5925 for (int i = 1; i < count; i++) {
5926 if (rect.bottom - rect.top > DRAG_IMAGE_SIZE) break;
5927 if (rect.bottom > clientRect.bottom) break;
5928 RECT itemRect = items[i].getBounds (0, true, true, false);
5929 if ((style & SWT.FULL_SELECTION) != 0) {
5930 itemRect.left = rect.left;
5931 itemRect.right = rect.right;
5933 itemRect.left = Math.max (itemRect.left, clientRect.left);
5934 itemRect.right = Math.min (itemRect.right, clientRect.right);
5936 long rectRgn = OS.CreateRectRgn (itemRect.left, itemRect.top, itemRect.right, itemRect.bottom);
5937 OS.CombineRgn (hRgn, hRgn, rectRgn, OS.RGN_OR);
5938 OS.DeleteObject (rectRgn);
5939 rect.bottom = itemRect.bottom;
5942 OS.GetRgnBox (hRgn, rect);
5944 /* Create resources */
5945 long hdc = OS.GetDC (handle);
5946 long memHdc = OS.CreateCompatibleDC (hdc);
5947 BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER ();
5948 bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
5949 bmiHeader.biWidth = rect.right - rect.left;
5950 bmiHeader.biHeight = -(rect.bottom - rect.top);
5951 bmiHeader.biPlanes = 1;
5952 bmiHeader.biBitCount = 32;
5953 bmiHeader.biCompression = OS.BI_RGB;
5954 byte [] bmi = new byte [BITMAPINFOHEADER.sizeof];
5955 OS.MoveMemory (bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
5956 long [] pBits = new long [1];
5957 long memDib = OS.CreateDIBSection (0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
5958 if (memDib == 0) error (SWT.ERROR_NO_HANDLES);
5959 long oldMemBitmap = OS.SelectObject (memHdc, memDib);
5960 int colorKey = 0x0000FD;
5961 POINT pt = new POINT ();
5962 OS.SetWindowOrgEx (memHdc, rect.left, rect.top, pt);
5963 OS.FillRect (memHdc, rect, findBrush (colorKey, OS.BS_SOLID));
5964 OS.OffsetRgn (hRgn, -rect.left, -rect.top);
5965 OS.SelectClipRgn (memHdc, hRgn);
5966 OS.PrintWindow (handle, memHdc, 0);
5967 OS.SetWindowOrgEx (memHdc, pt.x, pt.y, null);
5968 OS.SelectObject (memHdc, oldMemBitmap);
5969 OS.DeleteDC (memHdc);
5970 OS.ReleaseDC (0, hdc);
5971 OS.DeleteObject (hRgn);
5973 SHDRAGIMAGE shdi = new SHDRAGIMAGE ();
5974 shdi.hbmpDragImage = memDib;
5975 shdi.crColorKey = colorKey;
5976 shdi.sizeDragImage.cx = bmiHeader.biWidth;
5977 shdi.sizeDragImage.cy = -bmiHeader.biHeight;
5978 shdi.ptOffset.x = mousePos.x - rect.left;
5979 shdi.ptOffset.y = mousePos.y - rect.top;
5980 if ((style & SWT.MIRRORED) != 0) {
5981 shdi.ptOffset.x = shdi.sizeDragImage.cx - shdi.ptOffset.x;
5983 OS.MoveMemory (lParam, shdi, SHDRAGIMAGE.sizeof);
5987 return super.windowProc (hwnd, msg, wParam, lParam);
5991 LRESULT WM_CHAR (long wParam, long lParam) {
5992 LRESULT result = super.WM_CHAR (wParam, lParam);
5993 if (result != null) return result;
5995 * Feature in Windows. The tree control beeps
5996 * in WM_CHAR when the search for the item that
5997 * matches the key stroke fails. This is the
5998 * standard tree behavior but is unexpected when
5999 * the key that was typed was ESC, CR or SPACE.
6000 * The fix is to avoid calling the tree window
6001 * proc in these cases.
6003 switch ((int)wParam) {
6005 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6008 OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem);
6009 TVITEM tvItem = new TVITEM ();
6010 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE | OS.TVIF_PARAM;
6011 tvItem.hItem = hItem;
6012 if ((style & SWT.CHECK) != 0) {
6013 tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6014 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6015 int state = tvItem.state >> 12;
6016 if ((state & 0x1) != 0) {
6021 tvItem.state = state << 12;
6022 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6023 long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, hItem, 0);
6024 OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6026 tvItem.stateMask = OS.TVIS_SELECTED;
6027 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6028 if ((style & SWT.MULTI) != 0 && OS.GetKeyState (OS.VK_CONTROL) < 0) {
6029 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
6030 tvItem.state &= ~OS.TVIS_SELECTED;
6032 tvItem.state |= OS.TVIS_SELECTED;
6035 tvItem.state |= OS.TVIS_SELECTED;
6037 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6038 TreeItem item = _getItem (hItem, (int)tvItem.lParam);
6039 Event event = new Event ();
6041 sendSelectionEvent (SWT.Selection, event, false);
6042 if ((style & SWT.CHECK) != 0) {
6043 event = new Event ();
6045 event.detail = SWT.CHECK;
6046 sendSelectionEvent (SWT.Selection, event, false);
6049 return LRESULT.ZERO;
6053 * Feature in Windows. Windows sends NM_RETURN from WM_KEYDOWN
6054 * instead of using WM_CHAR. This means that application code
6055 * that expects to consume the key press and therefore avoid a
6056 * SWT.DefaultSelection event from WM_CHAR will fail. The fix
6057 * is to implement SWT.DefaultSelection in WM_CHAR instead of
6060 Event event = new Event ();
6061 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6062 if (hItem != 0) event.item = _getItem (hItem);
6063 sendSelectionEvent (SWT.DefaultSelection, event, false);
6064 return LRESULT.ZERO;
6067 return LRESULT.ZERO;
6073 LRESULT WM_ERASEBKGND (long wParam, long lParam) {
6074 LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
6075 if ((style & SWT.DOUBLE_BUFFERED) != 0) return LRESULT.ONE;
6076 if (findImageControl () != null) return LRESULT.ONE;
6081 LRESULT WM_GETOBJECT (long wParam, long lParam) {
6083 * Ensure that there is an accessible object created for this
6084 * control because support for checked item and tree column
6085 * accessibility is temporarily implemented in the accessibility
6088 if ((style & SWT.CHECK) != 0 || hwndParent != 0) {
6089 if (accessible == null) accessible = new_Accessible (this);
6091 return super.WM_GETOBJECT (wParam, lParam);
6095 LRESULT WM_HSCROLL (long wParam, long lParam) {
6096 boolean fixScroll = false;
6097 if ((style & SWT.DOUBLE_BUFFERED) != 0) {
6098 fixScroll = (style & SWT.VIRTUAL) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem);
6101 style &= ~SWT.DOUBLE_BUFFERED;
6102 if (explorerTheme) {
6103 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, 0);
6106 LRESULT result = super.WM_HSCROLL (wParam, lParam);
6108 style |= SWT.DOUBLE_BUFFERED;
6109 if (explorerTheme) {
6110 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, OS.TVS_EX_DOUBLEBUFFER);
6113 if (result != null) return result;
6118 LRESULT WM_KEYDOWN (long wParam, long lParam) {
6119 LRESULT result = super.WM_KEYDOWN (wParam, lParam);
6120 if (result != null) return result;
6121 switch ((int)wParam) {
6125 * Bug in Windows. The behavior for the left and right keys is not
6126 * changed if the orientation changes after the control was created.
6127 * The fix is to replace VK_LEFT by VK_RIGHT and VK_RIGHT by VK_LEFT
6128 * when the current orientation differs from the orientation used to
6129 * create the control.
6131 boolean isRTL = (style & SWT.RIGHT_TO_LEFT) != 0;
6132 if (isRTL != createdAsRTL) {
6133 long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam == OS.VK_RIGHT ? OS.VK_LEFT : OS.VK_RIGHT, lParam);
6134 return new LRESULT (code);
6139 * Ensure that the window proc does not process VK_SPACE
6140 * so that it can be handled in WM_CHAR. This allows the
6141 * application to cancel an operation that is normally
6142 * performed in WM_KEYDOWN from WM_CHAR.
6144 return LRESULT.ZERO;
6146 if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
6147 if (hwndHeader != 0) {
6148 TreeColumn [] newColumns = new TreeColumn [columnCount];
6149 System.arraycopy (columns, 0, newColumns, 0, columnCount);
6150 for (int i=0; i<columnCount; i++) {
6151 TreeColumn column = newColumns [i];
6152 if (!column.isDisposed () && column.getResizable ()) {
6165 OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
6166 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6167 if ((style & SWT.SINGLE) != 0) break;
6168 if (OS.GetKeyState (OS.VK_SHIFT) < 0) {
6169 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6171 if (hAnchor == 0) hAnchor = hItem;
6172 ignoreSelect = ignoreDeselect = true;
6173 long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
6174 ignoreSelect = ignoreDeselect = false;
6175 long hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6176 TVITEM tvItem = new TVITEM ();
6177 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6178 tvItem.stateMask = OS.TVIS_SELECTED;
6179 long hDeselectItem = hItem;
6180 RECT rect1 = new RECT ();
6181 if (!OS.TreeView_GetItemRect (handle, hAnchor, rect1, false)) {
6183 OS.TreeView_GetItemRect (handle, hAnchor, rect1, false);
6185 RECT rect2 = new RECT ();
6186 OS.TreeView_GetItemRect (handle, hDeselectItem, rect2, false);
6187 int flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
6188 while (hDeselectItem != hAnchor) {
6189 tvItem.hItem = hDeselectItem;
6190 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6191 hDeselectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hDeselectItem);
6193 long hSelectItem = hAnchor;
6194 OS.TreeView_GetItemRect (handle, hNewItem, rect1, false);
6195 OS.TreeView_GetItemRect (handle, hSelectItem, rect2, false);
6196 tvItem.state = OS.TVIS_SELECTED;
6197 flags = rect1.top < rect2.top ? OS.TVGN_PREVIOUSVISIBLE : OS.TVGN_NEXTVISIBLE;
6198 while (hSelectItem != hNewItem) {
6199 tvItem.hItem = hSelectItem;
6200 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6201 hSelectItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hSelectItem);
6203 tvItem.hItem = hNewItem;
6204 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6205 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6206 tvItem.hItem = hNewItem;
6207 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6208 Event event = new Event ();
6209 event.item = _getItem (hNewItem, (int)tvItem.lParam);
6210 sendSelectionEvent (SWT.Selection, event, false);
6211 return new LRESULT (code);
6214 if (OS.GetKeyState (OS.VK_CONTROL) < 0) {
6215 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6217 TVITEM tvItem = new TVITEM ();
6218 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6219 tvItem.stateMask = OS.TVIS_SELECTED;
6220 tvItem.hItem = hItem;
6221 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6222 boolean oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6224 switch ((int)wParam) {
6226 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUSVISIBLE, hItem);
6229 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem);
6232 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
6235 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6236 if (hNewItem == hItem) {
6237 OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEUP, 0);
6238 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6242 RECT rect = new RECT (), clientRect = new RECT ();
6243 OS.GetClientRect (handle, clientRect);
6244 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0);
6246 long hVisible = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNewItem);
6247 if (hVisible == 0) break;
6248 if (!OS.TreeView_GetItemRect (handle, hVisible, rect, false)) break;
6249 if (rect.bottom > clientRect.bottom) break;
6250 if ((hNewItem = hVisible) == hItem) {
6251 OS.SendMessage (handle, OS.WM_VSCROLL, OS.SB_PAGEDOWN, 0);
6253 } while (hNewItem != 0);
6256 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0);
6259 if (hNewItem != 0) {
6260 OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hNewItem);
6261 tvItem.hItem = hNewItem;
6262 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6263 boolean newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6264 boolean redraw = !newSelected && getDrawing () && OS.IsWindowVisible (handle);
6266 OS.UpdateWindow (handle);
6267 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
6270 ignoreSelect = true;
6271 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem);
6272 ignoreSelect = false;
6275 tvItem.state = OS.TVIS_SELECTED;
6276 tvItem.hItem = hItem;
6277 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6281 tvItem.hItem = hNewItem;
6282 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6285 RECT rect1 = new RECT (), rect2 = new RECT ();
6286 OS.TreeView_GetItemRect (handle, hItem, rect1, false);
6287 OS.TreeView_GetItemRect (handle, hNewItem, rect2, false);
6288 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
6289 OS.InvalidateRect (handle, rect1, true);
6290 OS.InvalidateRect (handle, rect2, true);
6291 OS.UpdateWindow (handle);
6293 return LRESULT.ZERO;
6297 long code = callWindowProc (handle, OS.WM_KEYDOWN, wParam, lParam);
6298 hAnchor = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6299 return new LRESULT (code);
6306 LRESULT WM_KILLFOCUS (long wParam, long lParam) {
6308 * Bug in Windows. When a tree item that has an image
6309 * with alpha is expanded or collapsed, the area where
6310 * the image is drawn is not erased before it is drawn.
6311 * This means that the image gets darker each time.
6312 * The fix is to redraw the selection.
6314 * Feature in Windows. When multiple item have
6315 * the TVIS_SELECTED state, Windows redraws only
6316 * the focused item in the color used to show the
6317 * selection when the tree loses or gains focus.
6318 * The fix is to force Windows to redraw the
6319 * selection when focus is gained or lost.
6321 boolean redraw = (style & SWT.MULTI) != 0;
6322 if (!redraw && imageList != null) {
6323 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6324 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
6328 if (redraw) redrawSelection ();
6329 return super.WM_KILLFOCUS (wParam, lParam);
6333 LRESULT WM_LBUTTONDBLCLK (long wParam, long lParam) {
6334 TVHITTESTINFO lpht = new TVHITTESTINFO ();
6335 lpht.x = OS.GET_X_LPARAM (lParam);
6336 lpht.y = OS.GET_Y_LPARAM (lParam);
6337 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6338 if (lpht.hItem != 0) {
6339 if ((style & SWT.CHECK) != 0) {
6340 if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
6341 Display display = this.display;
6342 display.captureChanged = false;
6343 sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6344 if (!sendMouseEvent (SWT.MouseDoubleClick, 1, handle, OS.WM_LBUTTONDBLCLK, wParam, lParam)) {
6345 if (!display.captureChanged && !isDisposed ()) {
6346 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6348 return LRESULT.ZERO;
6350 if (!display.captureChanged && !isDisposed ()) {
6351 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6353 OS.SetFocus (handle);
6354 TVITEM tvItem = new TVITEM ();
6355 tvItem.hItem = lpht.hItem;
6356 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
6357 tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6358 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6359 int state = tvItem.state >> 12;
6360 if ((state & 0x1) != 0) {
6365 tvItem.state = state << 12;
6366 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6367 long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
6368 OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6369 Event event = new Event ();
6370 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6371 event.detail = SWT.CHECK;
6372 sendSelectionEvent (SWT.Selection, event, false);
6373 return LRESULT.ZERO;
6377 LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam);
6378 if (result == LRESULT.ZERO) return result;
6379 if (lpht.hItem != 0) {
6380 int flags = OS.TVHT_ONITEM;
6381 if ((style & SWT.FULL_SELECTION) != 0) {
6382 flags |= OS.TVHT_ONITEMRIGHT | OS.TVHT_ONITEMINDENT;
6384 if (hooks (SWT.MeasureItem)) {
6385 lpht.flags &= ~(OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL);
6386 if (hitTestSelection (lpht.hItem, lpht.x, lpht.y)) {
6387 lpht.flags |= OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
6391 if ((lpht.flags & flags) != 0) {
6392 Event event = new Event ();
6393 event.item = _getItem (lpht.hItem);
6394 sendSelectionEvent (SWT.DefaultSelection, event, false);
6401 LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
6403 * In a multi-select tree, if the user is collapsing a subtree that
6404 * contains selected items, clear the selection from these items and
6405 * issue a selection event. Only items that are selected and visible
6406 * are cleared. This code also runs in the case when the white space
6407 * below the last item is selected.
6409 TVHITTESTINFO lpht = new TVHITTESTINFO ();
6410 lpht.x = OS.GET_X_LPARAM (lParam);
6411 lpht.y = OS.GET_Y_LPARAM (lParam);
6412 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6413 if (lpht.hItem == 0 || (lpht.flags & OS.TVHT_ONITEMBUTTON) != 0) {
6414 Display display = this.display;
6415 display.captureChanged = false;
6416 if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6417 if (!display.captureChanged && !isDisposed ()) {
6418 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6420 return LRESULT.ZERO;
6422 boolean fixSelection = false, deselected = false;
6423 long hOldSelection = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6424 if (lpht.hItem != 0 && (style & SWT.MULTI) != 0) {
6425 if (hOldSelection != 0) {
6426 TVITEM tvItem = new TVITEM ();
6427 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6428 tvItem.hItem = lpht.hItem;
6429 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6430 if ((tvItem.state & OS.TVIS_EXPANDED) != 0) {
6431 fixSelection = true;
6432 tvItem.stateMask = OS.TVIS_SELECTED;
6433 long hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, lpht.hItem);
6434 while (hNext != 0) {
6435 if (hNext == hAnchor) hAnchor = 0;
6436 tvItem.hItem = hNext;
6437 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6438 if ((tvItem.state & OS.TVIS_SELECTED) != 0) deselected = true;
6440 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6441 long hItem = hNext = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hNext);
6442 while (hItem != 0 && hItem != lpht.hItem) {
6443 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem);
6445 if (hItem == 0) break;
6450 dragStarted = gestureCompleted = false;
6452 hSelect = lpht.hItem;
6453 ignoreDeselect = ignoreSelect = lockSelection = true;
6455 long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6457 if (OS.GetFocus () != handle) OS.SetFocus (handle);
6460 ignoreDeselect = ignoreSelect = lockSelection = false;
6462 long hNewSelection = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6463 if (hOldSelection != hNewSelection) hAnchor = hNewSelection;
6465 if (!display.captureChanged && !isDisposed ()) {
6466 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6470 * Bug in Windows. When a tree has no images and an item is
6471 * expanded or collapsed, for some reason, Windows changes
6472 * the size of the selection. When the user expands a tree
6473 * item, the selection rectangle is made a few pixels larger.
6474 * When the user collapses an item, the selection rectangle
6475 * is restored to the original size but the selection is not
6476 * redrawn, causing pixel corruption. The fix is to detect
6477 * this case and redraw the item.
6479 if ((lpht.flags & OS.TVHT_ONITEMBUTTON) != 0) {
6480 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6481 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
6482 if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) == 0) {
6483 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6485 RECT rect = new RECT ();
6486 if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) {
6487 OS.InvalidateRect (handle, rect, true);
6494 Event event = new Event ();
6495 event.item = _getItem (lpht.hItem);
6496 sendSelectionEvent (SWT.Selection, event, false);
6498 return new LRESULT (code);
6501 /* Look for check/uncheck */
6502 if ((style & SWT.CHECK) != 0) {
6503 if ((lpht.flags & OS.TVHT_ONITEMSTATEICON) != 0) {
6504 Display display = this.display;
6505 display.captureChanged = false;
6506 if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6507 if (!display.captureChanged && !isDisposed ()) {
6508 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6510 return LRESULT.ZERO;
6512 if (!display.captureChanged && !isDisposed ()) {
6513 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6515 OS.SetFocus (handle);
6516 TVITEM tvItem = new TVITEM ();
6517 tvItem.hItem = lpht.hItem;
6518 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE;
6519 tvItem.stateMask = OS.TVIS_STATEIMAGEMASK;
6520 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6521 int state = tvItem.state >> 12;
6522 if ((state & 0x1) != 0) {
6527 tvItem.state = state << 12;
6528 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6529 long id = OS.SendMessage (handle, OS.TVM_MAPHTREEITEMTOACCID, tvItem.hItem, 0);
6530 OS.NotifyWinEvent (OS.EVENT_OBJECT_FOCUS, handle, OS.OBJID_CLIENT, (int)id);
6531 Event event = new Event ();
6532 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6533 event.detail = SWT.CHECK;
6534 sendSelectionEvent (SWT.Selection, event, false);
6535 return LRESULT.ZERO;
6540 * Feature in Windows. When the tree has the style
6541 * TVS_FULLROWSELECT, the background color for the
6542 * entire row is filled when an item is painted,
6543 * drawing on top of any custom drawing. The fix
6544 * is to emulate TVS_FULLROWSELECT.
6546 boolean selected = false;
6547 boolean fakeSelection = false;
6548 if (lpht.hItem != 0) {
6549 if ((style & SWT.FULL_SELECTION) != 0) {
6550 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6551 if ((bits & OS.TVS_FULLROWSELECT) == 0) fakeSelection = true;
6553 if (hooks (SWT.MeasureItem)) {
6554 selected = hitTestSelection (lpht.hItem, lpht.x, lpht.y);
6556 if ((lpht.flags & OS.TVHT_ONITEM) == 0) fakeSelection = true;
6562 /* Process the mouse when an item is not selected */
6563 if (!selected && (style & SWT.FULL_SELECTION) == 0) {
6564 if ((lpht.flags & OS.TVHT_ONITEM) == 0) {
6565 Display display = this.display;
6566 display.captureChanged = false;
6567 if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6568 if (!display.captureChanged && !isDisposed ()) {
6569 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6571 return LRESULT.ZERO;
6573 long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6575 if (OS.GetFocus () != handle) OS.SetFocus (handle);
6576 if (!display.captureChanged && !isDisposed ()) {
6577 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6579 return new LRESULT (code);
6583 /* Get the selected state of the item under the mouse */
6584 TVITEM tvItem = new TVITEM ();
6585 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6586 tvItem.stateMask = OS.TVIS_SELECTED;
6587 boolean hittestSelected = false;
6588 if ((style & SWT.MULTI) != 0) {
6589 tvItem.hItem = lpht.hItem;
6590 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6591 hittestSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
6594 /* Get the selected state of the last selected item */
6595 long hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6596 if ((style & SWT.MULTI) != 0) {
6597 tvItem.hItem = hOldItem;
6598 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6600 /* Check for CONTROL or drag selection */
6601 if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
6603 * Feature in Windows. When the tree is not drawing focus
6604 * and the user selects a tree item while the CONTROL key
6605 * is down, the tree window proc sends WM_UPDATEUISTATE
6606 * to the top level window, causing controls within the shell
6607 * to redraw. When drag detect is enabled, the tree window
6608 * proc runs a modal loop that allows WM_PAINT messages to be
6609 * delivered during WM_LBUTTONDOWN. When WM_SETREDRAW is used
6610 * to disable drawing for the tree and a WM_PAINT happens for
6611 * a parent of the tree (or a sibling that overlaps), the parent
6612 * will draw on top of the tree. If WM_SETREDRAW is turned back
6613 * on without redrawing the entire tree, pixel corruption occurs.
6614 * This case only seems to happen when the tree has been given
6615 * focus from WM_MOUSEACTIVATE of the shell. The fix is to
6616 * force the WM_UPDATEUISTATE to be sent before disabling
6619 * NOTE: Any redraw of a parent (or sibling) will be dispatched
6620 * during the modal drag detect loop. This code only fixes the
6621 * case where the tree causes a redraw from WM_UPDATEUISTATE.
6622 * In SWT, the InvalidateRect() that caused the pixel corruption
6623 * is found in Composite.WM_UPDATEUISTATE().
6625 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
6626 if ((uiState & OS.UISF_HIDEFOCUS) != 0) {
6627 OS.SendMessage (handle, OS.WM_CHANGEUISTATE, OS.UIS_INITIALIZE, 0);
6629 OS.UpdateWindow (handle);
6630 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
6636 /* Do the selection */
6637 Display display = this.display;
6638 display.captureChanged = false;
6639 if (!sendMouseEvent (SWT.MouseDown, 1, handle, OS.WM_LBUTTONDOWN, wParam, lParam)) {
6640 if (!display.captureChanged && !isDisposed ()) {
6641 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6643 return LRESULT.ZERO;
6645 hSelect = lpht.hItem;
6646 dragStarted = gestureCompleted = false;
6647 ignoreDeselect = ignoreSelect = true;
6648 long code = callWindowProc (handle, OS.WM_LBUTTONDOWN, wParam, lParam);
6650 if (OS.GetFocus () != handle) OS.SetFocus (handle);
6651 long hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6652 if (fakeSelection) {
6653 if (hOldItem == 0 || (hNewItem == hOldItem && lpht.hItem != hOldItem)) {
6654 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
6655 hNewItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0);
6657 if (!dragStarted && (state & DRAG_DETECT) != 0 && hooks (SWT.DragDetect)) {
6658 dragStarted = dragDetect (handle, lpht.x, lpht.y, false, null, null);
6661 ignoreDeselect = ignoreSelect = false;
6664 if (!display.captureChanged && !isDisposed ()) {
6665 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6670 * Feature in Windows. When the old and new focused item
6671 * are the same, Windows does not check to make sure that
6672 * the item is actually selected, not just focused. The
6673 * fix is to force the item to draw selected by setting
6674 * the state mask. This is only necessary when the tree
6677 if ((style & SWT.SINGLE) != 0) {
6678 if (hOldItem == hNewItem) {
6679 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6680 tvItem.state = OS.TVIS_SELECTED;
6681 tvItem.stateMask = OS.TVIS_SELECTED;
6682 tvItem.hItem = hNewItem;
6683 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6687 /* Reselect the last item that was unselected */
6688 if ((style & SWT.MULTI) != 0) {
6690 /* Check for CONTROL and reselect the last item */
6691 if (hittestSelected || (wParam & OS.MK_CONTROL) != 0) {
6692 if (hOldItem == hNewItem && hOldItem == lpht.hItem) {
6693 if ((wParam & OS.MK_CONTROL) != 0) {
6694 tvItem.state ^= OS.TVIS_SELECTED;
6695 if (dragStarted) tvItem.state = OS.TVIS_SELECTED;
6696 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6699 if ((tvItem.state & OS.TVIS_SELECTED) != 0) {
6700 tvItem.state = OS.TVIS_SELECTED;
6701 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6703 if ((wParam & OS.MK_CONTROL) != 0 && !dragStarted) {
6704 if (hittestSelected) {
6706 tvItem.hItem = lpht.hItem;
6707 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6711 RECT rect1 = new RECT (), rect2 = new RECT ();
6712 OS.TreeView_GetItemRect (handle, hOldItem, rect1, false);
6713 OS.TreeView_GetItemRect (handle, hNewItem, rect2, false);
6714 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
6715 OS.InvalidateRect (handle, rect1, true);
6716 OS.InvalidateRect (handle, rect2, true);
6717 OS.UpdateWindow (handle);
6720 /* Check for SHIFT or normal select and deselect/reselect items */
6721 if ((wParam & OS.MK_CONTROL) == 0) {
6722 if (!hittestSelected || !dragStarted) {
6724 long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC);
6725 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc);
6726 if ((style & SWT.VIRTUAL) != 0) {
6727 long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0);
6728 deselect (hItem, tvItem, hNewItem);
6730 for (int i=0; i<items.length; i++) {
6731 TreeItem item = items [i];
6732 if (item != null && item.handle != hNewItem) {
6733 tvItem.hItem = item.handle;
6734 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6738 tvItem.hItem = hNewItem;
6739 tvItem.state = OS.TVIS_SELECTED;
6740 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6741 OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc);
6742 if ((wParam & OS.MK_SHIFT) != 0) {
6743 RECT rect1 = new RECT ();
6744 if (hAnchor == 0) hAnchor = hNewItem;
6745 if (OS.TreeView_GetItemRect (handle, hAnchor, rect1, false)) {
6746 RECT rect2 = new RECT ();
6747 if (OS.TreeView_GetItemRect (handle, hNewItem, rect2, false)) {
6748 int flags = rect1.top < rect2.top ? OS.TVGN_NEXTVISIBLE : OS.TVGN_PREVIOUSVISIBLE;
6749 tvItem.state = OS.TVIS_SELECTED;
6750 long hItem = tvItem.hItem = hAnchor;
6751 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6752 while (hItem != hNewItem) {
6753 tvItem.hItem = hItem;
6754 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
6755 hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, flags, hItem);
6763 if ((wParam & OS.MK_SHIFT) == 0) hAnchor = hNewItem;
6765 /* Issue notification */
6766 if (!gestureCompleted) {
6767 tvItem.hItem = hNewItem;
6768 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
6769 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6770 Event event = new Event ();
6771 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
6772 sendSelectionEvent (SWT.Selection, event, false);
6774 gestureCompleted = false;
6777 * Feature in Windows. Inside WM_LBUTTONDOWN and WM_RBUTTONDOWN,
6778 * the widget starts a modal loop to determine if the user wants
6779 * to begin a drag/drop operation or marquee select. Unfortunately,
6780 * this modal loop eats the corresponding mouse up. The fix is to
6781 * detect the cases when the modal loop has eaten the mouse up and
6782 * issue a fake mouse up.
6785 sendDragEvent (1, OS.GET_X_LPARAM (lParam), OS.GET_Y_LPARAM (lParam));
6787 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
6788 if ((bits & OS.TVS_DISABLEDRAGDROP) == 0) {
6789 sendMouseEvent (SWT.MouseUp, 1, handle, OS.WM_LBUTTONUP, wParam, lParam);
6792 dragStarted = false;
6793 return new LRESULT (code);
6797 LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
6798 Display display = this.display;
6799 LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
6800 if (result != null) return result;
6801 if (itemToolTipHandle != 0) {
6803 * Bug in Windows. On some machines that do not have XBUTTONs,
6804 * the MK_XBUTTON1 and OS.MK_XBUTTON2 bits are sometimes set,
6805 * causing mouse capture to become stuck. The fix is to test
6806 * for the extra buttons only when they exist.
6808 int mask = OS.MK_LBUTTON | OS.MK_MBUTTON | OS.MK_RBUTTON;
6809 if (display.xMouse) mask |= OS.MK_XBUTTON1 | OS.MK_XBUTTON2;
6810 if ((wParam & mask) == 0) {
6811 int x = OS.GET_X_LPARAM (lParam);
6812 int y = OS.GET_Y_LPARAM (lParam);
6813 int [] index = new int [1];
6814 TreeItem [] item = new TreeItem [1];
6815 RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
6816 if (findCell (x, y, item, index, cellRect, itemRect)) {
6818 * Feature in Windows. When the new tool rectangle is
6819 * set using TTM_NEWTOOLRECT and the tooltip is visible,
6820 * Windows draws the tooltip right away and the sends
6821 * WM_NOTIFY with TTN_SHOW. This means that the tooltip
6822 * shows first at the wrong location and then moves to
6823 * the right one. The fix is to hide the tooltip window.
6825 if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, 0) == 0) {
6826 if (OS.IsWindowVisible (itemToolTipHandle)) {
6827 OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6830 TOOLINFO lpti = new TOOLINFO ();
6831 lpti.cbSize = TOOLINFO.sizeof;
6834 lpti.uFlags = OS.TTF_SUBCLASS | OS.TTF_TRANSPARENT;
6835 lpti.left = cellRect [0].left;
6836 lpti.top = cellRect [0].top;
6837 lpti.right = cellRect [0].right;
6838 lpti.bottom = cellRect [0].bottom;
6839 OS.SendMessage (itemToolTipHandle, OS.TTM_NEWTOOLRECT, 0, lpti);
6847 LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
6848 LRESULT result = super.WM_MOUSEWHEEL (wParam, lParam);
6849 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6854 LRESULT WM_MOVE (long wParam, long lParam) {
6855 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
6856 if (ignoreResize) return null;
6857 return super.WM_MOVE (wParam, lParam);
6861 LRESULT WM_RBUTTONDOWN (long wParam, long lParam) {
6863 * Feature in Windows. The receiver uses WM_RBUTTONDOWN
6864 * to initiate a drag/drop operation depending on how the
6865 * user moves the mouse. If the user clicks the right button,
6866 * without moving the mouse, the tree consumes the corresponding
6867 * WM_RBUTTONUP. The fix is to avoid calling the window proc for
6870 Display display = this.display;
6871 display.captureChanged = false;
6872 if (!sendMouseEvent (SWT.MouseDown, 3, handle, OS.WM_RBUTTONDOWN, wParam, lParam)) {
6873 if (!display.captureChanged && !isDisposed ()) {
6874 if (OS.GetCapture () != handle) OS.SetCapture (handle);
6876 return LRESULT.ZERO;
6879 * This code is intentionally commented.
6881 // if (OS.GetCapture () != handle) OS.SetCapture (handle);
6883 if (OS.GetFocus () != handle) OS.SetFocus (handle);
6886 * Feature in Windows. When the user selects a tree item
6887 * with the right mouse button, the item remains selected
6888 * only as long as the user does not release or move the
6889 * mouse. As soon as this happens, the selection snaps
6890 * back to the previous selection. This behavior can be
6891 * observed in the Explorer but is not instantly apparent
6892 * because the Explorer explicitly sets the selection when
6893 * the user chooses a menu item. If the user cancels the
6894 * menu, the selection snaps back. The fix is to avoid
6895 * calling the window proc and do the selection ourselves.
6896 * This behavior is consistent with the table.
6898 TVHITTESTINFO lpht = new TVHITTESTINFO ();
6899 lpht.x = OS.GET_X_LPARAM (lParam);
6900 lpht.y = OS.GET_Y_LPARAM (lParam);
6901 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
6902 if (lpht.hItem != 0) {
6903 boolean fakeSelection = (style & SWT.FULL_SELECTION) != 0;
6904 if (!fakeSelection) {
6905 if (hooks (SWT.MeasureItem)) {
6906 fakeSelection = hitTestSelection (lpht.hItem, lpht.x, lpht.y);
6908 int flags = OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL;
6909 fakeSelection = (lpht.flags & flags) != 0;
6912 if (fakeSelection) {
6913 if ((wParam & (OS.MK_CONTROL | OS.MK_SHIFT)) == 0) {
6914 TVITEM tvItem = new TVITEM ();
6915 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE;
6916 tvItem.stateMask = OS.TVIS_SELECTED;
6917 tvItem.hItem = lpht.hItem;
6918 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
6919 if ((tvItem.state & OS.TVIS_SELECTED) == 0) {
6920 ignoreSelect = true;
6921 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, 0);
6922 ignoreSelect = false;
6923 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, lpht.hItem);
6928 return LRESULT.ZERO;
6932 LRESULT WM_PAINT (long wParam, long lParam) {
6933 if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
6935 if (shrink && !ignoreShrink && items != null) {
6936 /* Resize the item array to fit the last item */
6937 int count = items.length - 1;
6938 while (count >= 0) {
6939 if (items [count] != null) break;
6943 if (items.length > 4 && items.length - count > 3) {
6944 int length = Math.max (4, (count + 3) / 4 * 4);
6945 TreeItem [] newItems = new TreeItem [length];
6946 System.arraycopy (items, 0, newItems, 0, count);
6951 if ((style & SWT.DOUBLE_BUFFERED) != 0 || findImageControl () != null) {
6952 boolean doubleBuffer = true;
6953 if (explorerTheme) {
6954 int exStyle = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
6955 if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) doubleBuffer = false;
6960 PAINTSTRUCT ps = new PAINTSTRUCT ();
6961 boolean hooksPaint = hooks (SWT.Paint) || filters (SWT.Paint);
6963 GCData data = new GCData ();
6966 gc = GC.win32_new (this, data);
6967 paintDC = gc.handle;
6969 paintDC = OS.BeginPaint (handle, ps);
6971 int width = ps.right - ps.left;
6972 int height = ps.bottom - ps.top;
6973 if (width != 0 && height != 0) {
6974 long hDC = OS.CreateCompatibleDC (paintDC);
6975 POINT lpPoint1 = new POINT (), lpPoint2 = new POINT ();
6976 OS.SetWindowOrgEx (hDC, ps.left, ps.top, lpPoint1);
6977 OS.SetBrushOrgEx (hDC, ps.left, ps.top, lpPoint2);
6978 long hBitmap = OS.CreateCompatibleBitmap (paintDC, width, height);
6979 long hOldBitmap = OS.SelectObject (hDC, hBitmap);
6980 RECT rect = new RECT ();
6981 OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
6982 drawBackground (hDC, rect);
6983 callWindowProc (handle, OS.WM_PAINT, hDC, 0);
6984 OS.SetWindowOrgEx (hDC, lpPoint1.x, lpPoint1.y, null);
6985 OS.SetBrushOrgEx (hDC, lpPoint2.x, lpPoint2.y, null);
6986 OS.BitBlt (paintDC, ps.left, ps.top, width, height, hDC, 0, 0, OS.SRCCOPY);
6987 OS.SelectObject (hDC, hOldBitmap);
6988 OS.DeleteObject (hBitmap);
6989 OS.DeleteObject (hDC);
6991 Event event = new Event ();
6993 event.setBoundsInPixels(new Rectangle(ps.left, ps.top, ps.right - ps.left, ps.bottom - ps.top));
6994 sendEvent (SWT.Paint, event);
6995 // widget could be disposed at this point
7002 OS.EndPaint (handle, ps);
7004 return LRESULT.ZERO;
7007 return super.WM_PAINT (wParam, lParam);
7011 LRESULT WM_SETCURSOR (long wParam, long lParam) {
7012 LRESULT result = super.WM_SETCURSOR (wParam, lParam);
7013 if (result != null) return result;
7016 * Feature in Windows. On Windows 7, the tree control show the
7017 * hand cursor when the mouse is over an item. This is the
7018 * correct Windows 7 behavior but not correct for SWT. The fix
7019 * is to always ensure a cursor is set.
7021 if (OS.WIN32_VERSION >= OS.VERSION (6, 1)) {
7022 if (wParam == handle) {
7023 int hitTest = (short) OS.LOWORD (lParam);
7024 if (hitTest == OS.HTCLIENT) {
7025 OS.SetCursor (OS.LoadCursor (0, OS.IDC_ARROW));
7034 LRESULT WM_SETFOCUS (long wParam, long lParam) {
7036 * Bug in Windows. When a tree item that has an image
7037 * with alpha is expanded or collapsed, the area where
7038 * the image is drawn is not erased before it is drawn.
7039 * This means that the image gets darker each time.
7040 * The fix is to redraw the selection.
7042 * Feature in Windows. When multiple item have
7043 * the TVIS_SELECTED state, Windows redraws only
7044 * the focused item in the color used to show the
7045 * selection when the tree loses or gains focus.
7046 * The fix is to force Windows to redraw the
7047 * selection when focus is gained or lost.
7049 boolean redraw = (style & SWT.MULTI) != 0;
7050 if (!redraw && imageList != null) {
7051 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7052 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
7056 if (redraw) redrawSelection ();
7057 return super.WM_SETFOCUS (wParam, lParam);
7061 LRESULT WM_SETFONT (long wParam, long lParam) {
7062 LRESULT result = super.WM_SETFONT (wParam, lParam);
7063 if (result != null) return result;
7064 if (hwndHeader != 0) {
7066 * Bug in Windows. When a header has a sort indicator
7067 * triangle, Windows resizes the indicator based on the
7068 * size of the n-1th font. The fix is to always make
7069 * the n-1th font be the default. This makes the sort
7070 * indicator always be the default size.
7072 OS.SendMessage (hwndHeader, OS.WM_SETFONT, 0, lParam);
7073 OS.SendMessage (hwndHeader, OS.WM_SETFONT, wParam, lParam);
7075 if (itemToolTipHandle != 0) {
7076 OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7077 OS.SendMessage (itemToolTipHandle, OS.WM_SETFONT, wParam, lParam);
7079 if (headerToolTipHandle != 0) {
7080 OS.SendMessage (headerToolTipHandle, OS.WM_SETFONT, wParam, lParam);
7081 updateHeaderToolTips ();
7087 LRESULT WM_SETREDRAW (long wParam, long lParam) {
7088 LRESULT result = super.WM_SETREDRAW (wParam, lParam);
7089 if (result != null) return result;
7090 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7092 * Bug in Windows. Under certain circumstances, when
7093 * WM_SETREDRAW is used to turn off drawing and then
7094 * TVM_GETITEMRECT is sent to get the bounds of an item
7095 * that is not inside the client area, Windows segment
7096 * faults. The fix is to call the default window proc
7097 * rather than the default tree proc.
7099 * NOTE: This problem is intermittent and happens on
7100 * Windows Vista running under the theme manager.
7102 long code = OS.DefWindowProc (handle, OS.WM_SETREDRAW, wParam, lParam);
7103 return code == 0 ? LRESULT.ZERO : new LRESULT (code);
7107 LRESULT WM_SIZE (long wParam, long lParam) {
7108 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7110 * Bug in Windows. When TVS_NOHSCROLL is set when the
7111 * size of the tree is zero, the scroll bar is shown the
7112 * next time the tree resizes. The fix is to hide the
7113 * scroll bar every time the tree is resized.
7115 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7116 if ((bits & OS.TVS_NOHSCROLL) != 0) {
7117 OS.ShowScrollBar (handle, OS.SB_HORZ, false);
7120 * Bug in Windows. On Vista, when the Explorer theme
7121 * is used with a full selection tree, when the tree
7122 * is resized to be smaller, the rounded right edge
7123 * of the selected items is not drawn. The fix is the
7124 * redraw the entire tree.
7126 if (explorerTheme && (style & SWT.FULL_SELECTION) != 0) {
7127 OS.InvalidateRect (handle, null, false);
7129 if (ignoreResize) return null;
7130 return super.WM_SIZE (wParam, lParam);
7134 LRESULT WM_SYSCOLORCHANGE (long wParam, long lParam) {
7135 LRESULT result = super.WM_SYSCOLORCHANGE (wParam, lParam);
7136 if (result != null) return result;
7138 * Bug in Windows. When the tree is using the explorer
7139 * theme, it does not use COLOR_WINDOW_TEXT for the
7140 * default foreground color. The fix is to explicitly
7141 * set the foreground.
7143 if (explorerTheme) {
7144 if (foreground == -1) setForegroundPixel (-1);
7146 if ((style & SWT.CHECK) != 0) setCheckboxImageList ();
7151 LRESULT WM_VSCROLL (long wParam, long lParam) {
7152 boolean fixScroll = false;
7153 if ((style & SWT.DOUBLE_BUFFERED) != 0) {
7154 int code = OS.LOWORD (wParam);
7158 case OS.SB_LINEDOWN:
7160 case OS.SB_PAGEDOWN:
7162 fixScroll = (style & SWT.VIRTUAL) != 0 || hooks (SWT.EraseItem) || hooks (SWT.PaintItem);
7167 style &= ~SWT.DOUBLE_BUFFERED;
7168 if (explorerTheme) {
7169 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, 0);
7172 LRESULT result = super.WM_VSCROLL (wParam, lParam);
7174 style |= SWT.DOUBLE_BUFFERED;
7175 if (explorerTheme) {
7176 OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, OS.TVS_EX_DOUBLEBUFFER, OS.TVS_EX_DOUBLEBUFFER);
7179 if (result != null) return result;
7184 LRESULT WM_TIMER (long wParam, long lParam) {
7185 LRESULT result = super.WM_TIMER (wParam, lParam);
7186 if (result != null) return result;
7188 /* Bug in Windows. When the expandos are visible (or in process of fading away)
7189 * and the tree control is hidden the animation timer does not stop calling the
7190 * window proc till the tree is visible again. This can cause performance problems
7191 * specially in cases there the application has several tree controls in this state.
7192 * The fix is to detect a timer that repeats itself several times when the control
7193 * is not visible and stop it. The timer is stopped by sending a fake mouse move event.
7195 * Note: Just killing the timer could cause some internal clean up task related to the
7196 * animation not to run.
7198 long bits = OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0);
7199 if ((bits & OS.TVS_EX_FADEINOUTEXPANDOS) != 0) {
7200 if (!OS.IsWindowVisible (handle)) {
7201 if (lastTimerID == wParam) {
7206 lastTimerID = wParam;
7207 if (lastTimerCount >= TIMER_MAX_COUNT) {
7208 OS.CallWindowProc (TreeProc, handle, OS.WM_MOUSEMOVE, 0, 0);
7221 LRESULT wmColorChild (long wParam, long lParam) {
7222 if (findImageControl () != null) {
7223 return new LRESULT (OS.GetStockObject (OS.NULL_BRUSH));
7226 * Feature in Windows. Tree controls send WM_CTLCOLOREDIT
7227 * to allow application code to change the default colors.
7228 * This is undocumented and conflicts with TVM_SETTEXTCOLOR
7229 * and TVM_SETBKCOLOR, the documented way to do this. The
7230 * fix is to ignore WM_CTLCOLOREDIT messages from trees.
7236 LRESULT wmNotify (NMHDR hdr, long wParam, long lParam) {
7237 if (hdr.hwndFrom == itemToolTipHandle) {
7238 LRESULT result = wmNotifyToolTip (hdr, wParam, lParam);
7239 if (result != null) return result;
7241 if (hdr.hwndFrom == hwndHeader) {
7242 LRESULT result = wmNotifyHeader (hdr, wParam, lParam);
7243 if (result != null) return result;
7245 return super.wmNotify (hdr, wParam, lParam);
7249 LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
7251 case OS.TVN_GETDISPINFO: {
7252 NMTVDISPINFO lptvdi = new NMTVDISPINFO ();
7253 OS.MoveMemory (lptvdi, lParam, NMTVDISPINFO.sizeof);
7254 if ((style & SWT.VIRTUAL) != 0) {
7256 * Feature in Windows. When a new tree item is inserted
7257 * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
7258 * TVM_INSERTITEM returns and before the item is added to
7259 * the items array. The fix is to check for null.
7261 * NOTE: This only happens on XP with the version 6.00 of
7264 boolean checkVisible = true;
7266 * When an item is being deleted from a virtual tree, do not
7267 * allow the application to provide data for a new item that
7268 * becomes visible until the item has been removed from the
7269 * items array. Because arbitrary application code can run
7270 * during the callback, the items array might be accessed
7271 * in an inconsistent state. Rather than answering the data
7272 * right away, queue a redraw for later.
7274 if (!ignoreShrink) {
7275 if (items != null && lptvdi.lParam != -1) {
7276 if (items [(int)lptvdi.lParam] != null && items [(int)lptvdi.lParam].cached) {
7277 checkVisible = false;
7282 if (!getDrawing () || !OS.IsWindowVisible (handle)) break;
7283 RECT itemRect = new RECT ();
7284 if (!OS.TreeView_GetItemRect (handle, lptvdi.hItem, itemRect, false)) {
7287 RECT rect = new RECT ();
7288 OS.GetClientRect (handle, rect);
7289 if (!OS.IntersectRect (rect, rect, itemRect)) break;
7291 OS.InvalidateRect (handle, rect, true);
7296 if (items == null) break;
7298 * Bug in Windows. If the lParam field of TVITEM
7299 * is changed during custom draw using TVM_SETITEM,
7300 * the lItemlParam field of the NMTVCUSTOMDRAW struct
7301 * is not updated until the next custom draw. The
7302 * fix is to query the field from the item instead
7303 * of using the struct.
7305 int id = (int)lptvdi.lParam;
7306 if ((style & SWT.VIRTUAL) != 0) {
7308 TVITEM tvItem = new TVITEM ();
7309 tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM;
7310 tvItem.hItem = lptvdi.hItem;
7311 OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem);
7312 id = (int)tvItem.lParam;
7315 TreeItem item = _getItem (lptvdi.hItem, id);
7317 * Feature in Windows. When a new tree item is inserted
7318 * using TVM_INSERTITEM, a TVN_GETDISPINFO is sent before
7319 * TVM_INSERTITEM returns and before the item is added to
7320 * the items array. The fix is to check for null.
7322 * NOTE: This only happens on XP with the version 6.00 of
7325 * Feature in Windows. When TVM_DELETEITEM is called with
7326 * TVI_ROOT to remove all items from a tree, under certain
7327 * circumstances, the tree sends TVN_GETDISPINFO for items
7328 * that are about to be disposed. The fix is to check for
7331 if (item == null) break;
7332 if (item.isDisposed ()) break;
7334 if ((style & SWT.VIRTUAL) != 0) {
7335 if (!checkData (item, false)) break;
7337 if (painted) item.cached = true;
7340 if (hwndHeader != 0) {
7341 index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0);
7343 if ((lptvdi.mask & OS.TVIF_TEXT) != 0) {
7344 String string = null;
7348 String [] strings = item.strings;
7349 if (strings != null) string = strings [index];
7351 if (string != null) {
7352 int length = Math.min (string.length() + 1, lptvdi.cchTextMax);
7353 char [] buffer = new char [length];
7354 string.getChars(0, length - 1, buffer, 0);
7355 OS.MoveMemory (lptvdi.pszText, buffer, length * TCHAR.sizeof);
7356 lptvdi.cchTextMax = length;
7359 if ((lptvdi.mask & (OS.TVIF_IMAGE | OS.TVIF_SELECTEDIMAGE)) != 0) {
7364 Image [] images = item.images;
7365 if (images != null) image = images [index];
7367 lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
7368 if (image != null) {
7369 lptvdi.iImage = lptvdi.iSelectedImage = imageIndex (image, index);
7371 if (explorerTheme && OS.IsWindowEnabled (handle)) {
7372 if (findImageControl () != null) {
7373 lptvdi.iImage = lptvdi.iSelectedImage = OS.I_IMAGENONE;
7377 OS.MoveMemory (lParam, lptvdi, NMTVDISPINFO.sizeof);
7380 case OS.NM_CUSTOMDRAW: {
7381 if (hdr.hwndFrom == hwndHeader) break;
7382 if (hooks (SWT.MeasureItem)) {
7383 if (hwndHeader == 0) createParent ();
7385 if (!customDraw && findImageControl () == null) {
7386 if (OS.IsAppThemed ()) {
7387 if (sortColumn == null || sortDirection == SWT.NONE) {
7392 NMTVCUSTOMDRAW nmcd = new NMTVCUSTOMDRAW ();
7393 OS.MoveMemory (nmcd, lParam, NMTVCUSTOMDRAW.sizeof);
7394 switch (nmcd.dwDrawStage) {
7395 case OS.CDDS_PREPAINT: return CDDS_PREPAINT (nmcd, wParam, lParam);
7396 case OS.CDDS_ITEMPREPAINT: return CDDS_ITEMPREPAINT (nmcd, wParam, lParam);
7397 case OS.CDDS_ITEMPOSTPAINT: return CDDS_ITEMPOSTPAINT (nmcd, wParam, lParam);
7398 case OS.CDDS_POSTPAINT: return CDDS_POSTPAINT (nmcd, wParam, lParam);
7402 case OS.NM_DBLCLK: {
7404 * When the user double clicks on a tree item
7405 * or a line beside the item, the window proc
7406 * for the tree collapses or expand the branch.
7407 * When application code associates an action
7408 * with double clicking, then the tree expand
7409 * is unexpected and unwanted. The fix is to
7410 * avoid the operation by testing to see whether
7411 * the mouse was inside a tree item.
7413 if (hooks (SWT.MeasureItem)) return LRESULT.ONE;
7414 if (hooks (SWT.DefaultSelection)) {
7415 POINT pt = new POINT ();
7416 int pos = OS.GetMessagePos ();
7417 OS.POINTSTOPOINT (pt, pos);
7418 OS.ScreenToClient (handle, pt);
7419 TVHITTESTINFO lpht = new TVHITTESTINFO ();
7422 OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht);
7423 if (lpht.hItem != 0 && (lpht.flags & OS.TVHT_ONITEM) != 0) {
7430 * Bug in Windows. On Vista, when TVM_SELECTITEM is called
7431 * with TVGN_CARET in order to set the selection, for some
7432 * reason, Windows deselects the previous two items that
7433 * were selected. The fix is to stop the selection from
7434 * changing on all but the item that is supposed to be
7437 case OS.TVN_ITEMCHANGING: {
7438 if ((style & SWT.MULTI) != 0) {
7440 NMTVITEMCHANGE pnm = new NMTVITEMCHANGE ();
7441 OS.MoveMemory (pnm, lParam, NMTVITEMCHANGE.sizeof);
7442 if (hSelect == pnm.hItem) break;
7448 case OS.TVN_SELCHANGING: {
7449 if ((style & SWT.MULTI) != 0) {
7450 if (lockSelection) {
7451 /* Save the old selection state for both items */
7452 NMTREEVIEW treeView = new NMTREEVIEW ();
7453 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7454 TVITEM tvItem = treeView.itemOld;
7455 oldSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
7456 tvItem = treeView.itemNew;
7457 newSelected = (tvItem.state & OS.TVIS_SELECTED) != 0;
7460 if (!ignoreSelect && !ignoreDeselect) {
7462 if ((style & SWT.MULTI) != 0) deselectAll ();
7466 case OS.TVN_SELCHANGED: {
7467 NMTREEVIEW treeView = null;
7468 if ((style & SWT.MULTI) != 0) {
7469 if (lockSelection) {
7470 /* Restore the old selection state of both items */
7472 if (treeView == null) {
7473 treeView = new NMTREEVIEW ();
7474 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7476 TVITEM tvItem = treeView.itemOld;
7477 tvItem.mask = OS.TVIF_STATE;
7478 tvItem.stateMask = OS.TVIS_SELECTED;
7479 tvItem.state = OS.TVIS_SELECTED;
7480 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
7482 if (!newSelected && ignoreSelect) {
7483 if (treeView == null) {
7484 treeView = new NMTREEVIEW ();
7485 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7487 TVITEM tvItem = treeView.itemNew;
7488 tvItem.mask = OS.TVIF_STATE;
7489 tvItem.stateMask = OS.TVIS_SELECTED;
7491 OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem);
7495 if (!ignoreSelect) {
7496 if (treeView == null) {
7497 treeView = new NMTREEVIEW ();
7498 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7500 TVITEM tvItem = treeView.itemNew;
7501 hAnchor = tvItem.hItem;
7502 Event event = new Event ();
7503 event.item = _getItem (tvItem.hItem, (int)tvItem.lParam);
7504 sendSelectionEvent (SWT.Selection, event, false);
7509 case OS.TVN_ITEMEXPANDING: {
7510 if (itemToolTipHandle != 0) OS.ShowWindow (itemToolTipHandle, OS.SW_HIDE);
7511 boolean runExpanded = false;
7512 if ((style & SWT.VIRTUAL) != 0) style &= ~SWT.DOUBLE_BUFFERED;
7513 if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style &= ~SWT.DOUBLE_BUFFERED;
7514 if (findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle)) {
7515 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0);
7518 * Bug in Windows. When TVM_SETINSERTMARK is used to set
7519 * an insert mark for a tree and an item is expanded or
7520 * collapsed near the insert mark, the tree does not redraw
7521 * the insert mark properly. The fix is to hide and show
7522 * the insert mark whenever an item is expanded or collapsed.
7525 OS.SendMessage (handle, OS.TVM_SETINSERTMARK, 0, 0);
7527 if (!ignoreExpand) {
7528 NMTREEVIEW treeView = new NMTREEVIEW ();
7529 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7530 TVITEM tvItem = treeView.itemNew;
7532 * Feature in Windows. In some cases, TVM_ITEMEXPANDING
7533 * is sent from within TVM_DELETEITEM for the tree item
7534 * being destroyed. By the time the message is sent,
7535 * the item has already been removed from the list of
7536 * items. The fix is to check for null.
7538 if (items == null) break;
7539 TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam);
7540 if (item == null) break;
7541 Event event = new Event ();
7543 switch (treeView.action) {
7546 * Bug in Windows. When the numeric keypad asterisk
7547 * key is used to expand every item in the tree, Windows
7548 * sends TVN_ITEMEXPANDING to items in the tree that
7549 * have already been expanded. The fix is to detect
7550 * that the item is already expanded and ignore the
7553 if ((tvItem.state & OS.TVIS_EXPANDED) == 0) {
7554 sendEvent (SWT.Expand, event);
7555 if (isDisposed ()) return LRESULT.ZERO;
7558 case OS.TVE_COLLAPSE:
7559 sendEvent (SWT.Collapse, event);
7560 if (isDisposed ()) return LRESULT.ZERO;
7564 * Bug in Windows. When all of the items are deleted during
7565 * TVN_ITEMEXPANDING, Windows does not send TVN_ITEMEXPANDED.
7566 * The fix is to detect this case and run the TVN_ITEMEXPANDED
7567 * code in this method.
7569 long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, tvItem.hItem);
7570 runExpanded = hFirstItem == 0;
7572 if (!runExpanded) break;
7575 case OS.TVN_ITEMEXPANDED: {
7576 if ((style & SWT.VIRTUAL) != 0) style |= SWT.DOUBLE_BUFFERED;
7577 if (hooks (SWT.EraseItem) || hooks (SWT.PaintItem)) style |= SWT.DOUBLE_BUFFERED;
7578 if (findImageControl () != null && getDrawing () /*&& OS.IsWindowVisible (handle)*/) {
7579 OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0);
7580 OS.InvalidateRect (handle, null, true);
7583 * Bug in Windows. When TVM_SETINSERTMARK is used to set
7584 * an insert mark for a tree and an item is expanded or
7585 * collapsed near the insert mark, the tree does not redraw
7586 * the insert mark properly. The fix is to hide and show
7587 * the insert mark whenever an item is expanded or collapsed.
7590 OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert);
7593 * Bug in Windows. When a tree item that has an image
7594 * with alpha is expanded or collapsed, the area where
7595 * the image is drawn is not erased before it is drawn.
7596 * This means that the image gets darker each time.
7597 * The fix is to redraw the item.
7599 if (imageList != null) {
7600 NMTREEVIEW treeView = new NMTREEVIEW ();
7601 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7602 TVITEM tvItem = treeView.itemNew;
7603 if (tvItem.hItem != 0) {
7604 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
7605 if ((bits & OS.TVS_FULLROWSELECT) == 0) {
7606 RECT rect = new RECT ();
7607 if (OS.TreeView_GetItemRect (handle, tvItem.hItem, rect, false)) {
7608 OS.InvalidateRect (handle, rect, true);
7616 case OS.TVN_BEGINDRAG:
7617 if (OS.GetKeyState (OS.VK_LBUTTON) >= 0) break;
7619 case OS.TVN_BEGINRDRAG: {
7621 NMTREEVIEW treeView = new NMTREEVIEW ();
7622 OS.MoveMemory (treeView, lParam, NMTREEVIEW.sizeof);
7623 TVITEM tvItem = treeView.itemNew;
7624 if (tvItem.hItem != 0 && (tvItem.state & OS.TVIS_SELECTED) == 0) {
7625 hSelect = tvItem.hItem;
7626 ignoreSelect = ignoreDeselect = true;
7627 OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, tvItem.hItem);
7628 ignoreSelect = ignoreDeselect = false;
7634 return super.wmNotifyChild (hdr, wParam, lParam);
7637 LRESULT wmNotifyHeader (NMHDR hdr, long wParam, long lParam) {
7639 * Feature in Windows. On NT, the automatically created
7640 * header control is created as a UNICODE window, not an
7641 * ANSI window despite the fact that the parent is created
7642 * as an ANSI window. This means that it sends UNICODE
7643 * notification messages to the parent window on NT for
7644 * no good reason. The data and size in the NMHEADER and
7645 * HDITEM structs is identical between the platforms so no
7646 * different message is actually necessary. Despite this,
7647 * Windows sends different messages. The fix is to look
7648 * for both messages, despite the platform. This works
7649 * because only one will be sent on either platform, never
7653 case OS.HDN_BEGINTRACK:
7654 case OS.HDN_DIVIDERDBLCLICK: {
7655 NMHEADER phdn = new NMHEADER ();
7656 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7657 TreeColumn column = columns [phdn.iItem];
7658 if (column != null && !column.getResizable ()) {
7661 ignoreColumnMove = true;
7662 if (hdr.code == OS.HDN_DIVIDERDBLCLICK) {
7663 if (column != null) column.pack ();
7667 case OS.NM_CUSTOMDRAW: {
7668 NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW();
7669 OS.MoveMemory(nmcd, lParam, NMCUSTOMDRAW.sizeof);
7670 switch (nmcd.dwDrawStage) {
7671 case OS.CDDS_PREPAINT: {
7672 /* Drawing here will be deleted by further drawing steps, even with OS.CDRF_SKIPDEFAULT.
7673 Changing the TextColor and returning OS.CDRF_NEWFONT has no effect. */
7674 return new LRESULT (customHeaderDrawing() ? OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT : OS.CDRF_DODEFAULT);
7676 case OS.CDDS_ITEMPREPAINT: {
7678 RECT rect = new RECT();
7679 OS.SetRect(rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
7680 int pixel = getHeaderBackgroundPixel();
7681 if ((nmcd.uItemState & OS.CDIS_SELECTED) != 0) {
7682 pixel = getDifferentColor(pixel);
7683 } else if (columns[(int) nmcd.dwItemSpec] == sortColumn && sortDirection != SWT.NONE) {
7684 pixel = getSlightlyDifferentColor(pixel);
7686 long brush = OS.CreateSolidBrush(pixel);
7687 OS.FillRect(nmcd.hdc, rect, brush);
7688 OS.DeleteObject(brush);
7690 return new LRESULT(OS.CDRF_SKIPDEFAULT); // if we got here, we will paint everything ourself
7692 case OS.CDDS_POSTPAINT: {
7693 // get the cursor position
7694 POINT cursorPos = new POINT();
7695 OS.GetCursorPos(cursorPos);
7696 OS.MapWindowPoints(0, hwndHeader, cursorPos, 1);
7698 // drawing all cells
7699 int highlightedHeaderDividerX = -1;
7700 int lastColumnRight = -1;
7701 RECT [] rects = new RECT [columnCount];
7702 for (int i=0; i<columnCount; i++) {
7703 rects [i] = new RECT ();
7704 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, i, rects [i]);
7705 if (rects[i].right > lastColumnRight) {
7706 lastColumnRight = rects[i].right;
7709 if (columns[i] == sortColumn && sortDirection != SWT.NONE) {
7710 // the display.getSortImage looks terrible after scaling up.
7711 long pen = OS.CreatePen (OS.PS_SOLID, 1, getHeaderForegroundPixel());
7712 long oldPen = OS.SelectObject (nmcd.hdc, pen);
7713 int center = rects[i].left + (rects[i].right - rects[i].left) / 2;
7715 * Sort indicator size needs to scale as per the Native Windows OS DPI level
7716 * when header is custom drawn. For more details refer bug 537097.
7718 int leg = DPIUtil.autoScaleUpUsingNativeDPI(3);
7719 if (sortDirection == SWT.UP) {
7720 OS.Polyline(nmcd.hdc, new int[] {center-leg, 1+leg, center+1, 0}, 2);
7721 OS.Polyline(nmcd.hdc, new int[] {center+leg, 1+leg, center-1, 0}, 2);
7722 } else if (sortDirection == SWT.DOWN) {
7723 OS.Polyline(nmcd.hdc, new int[] {center-leg, 1, center+1, 1+leg+1}, 2);
7724 OS.Polyline(nmcd.hdc, new int[] {center+leg, 1, center-1, 1+leg+1}, 2);
7726 OS.SelectObject (nmcd.hdc, oldPen);
7727 OS.DeleteObject (pen);
7730 /* Windows 7 and 10 always draw a nearly invisible vertical line between the columns, even if lines are disabled.
7731 This line uses no fixed color constant, but calculates it from the background color.
7732 The method getSlightlyDifferentColor gives us a color, that is near enough to the windows algorithm. */
7733 long pen = OS.CreatePen (OS.PS_SOLID, getGridLineWidthInPixels(), getSlightlyDifferentColor(getHeaderBackgroundPixel()));
7734 long oldPen = OS.SelectObject (nmcd.hdc, pen);
7735 OS.Polyline(nmcd.hdc, new int[] {rects[i].right-1, rects[i].top, rects[i].right-1, rects[i].bottom}, 2);
7736 OS.SelectObject (nmcd.hdc, oldPen);
7737 OS.DeleteObject (pen);
7739 pen = OS.CreatePen (OS.PS_SOLID, getGridLineWidthInPixels(), OS.GetSysColor(OS.COLOR_3DFACE));
7740 oldPen = OS.SelectObject (nmcd.hdc, pen);
7741 /* To differentiate headers, always draw header column separator. */
7742 OS.Polyline(nmcd.hdc, new int[] {rects[i].right-1, rects[i].top, rects[i].right-1, rects[i].bottom}, 2);
7743 /* To differentiate header & content area, always draw the line separator between header & first row. */
7744 if (i == 0) OS.Polyline(nmcd.hdc, new int[] {nmcd.left, nmcd.bottom-1, nmcd.right, nmcd.bottom-1}, 2);
7745 OS.SelectObject (nmcd.hdc, oldPen);
7746 OS.DeleteObject (pen);
7748 if (headerItemDragging && highlightedHeaderDividerX == -1) {
7749 int distanceToLeftBorder = cursorPos.x - rects[i].left;
7750 int distanceToRightBorder = rects[i].right - cursorPos.x;
7751 if (distanceToLeftBorder >= 0 && distanceToRightBorder >= 0) {
7752 // the cursor is in the current rectangle
7753 highlightedHeaderDividerX = distanceToLeftBorder <= distanceToRightBorder ? rects[i].left-1 : rects[i].right;
7757 int x = rects[i].left + INSET + 2;
7758 if (columns[i].image != null) {
7759 GCData data = new GCData();
7760 data.device = display;
7761 GC gc = GC.win32_new (nmcd.hdc, data);
7762 int y = Math.max (0, (nmcd.bottom - columns[i].image.getBoundsInPixels().height) / 2);
7763 gc.drawImage (columns[i].image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y));
7764 x += columns[i].image.getBoundsInPixels().width + 12;
7768 if (columns[i].text != null) {
7769 int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
7770 if ((columns[i].style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
7771 if ((columns[i].style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
7772 char [] buffer = columns[i].text.toCharArray ();
7773 OS.SetBkMode(nmcd.hdc, OS.TRANSPARENT);
7774 OS.SetTextColor(nmcd.hdc, getHeaderForegroundPixel());
7775 RECT textRect = new RECT();
7777 textRect.top = rects[i].top;
7778 textRect.right = rects[i].right;
7779 textRect.bottom = rects[i].bottom;
7780 OS.DrawText (nmcd.hdc, buffer, buffer.length, textRect, flags);
7784 if (lastColumnRight < nmcd.right) {
7785 // draw background of the 'no column' area
7786 RECT rect = new RECT();
7787 OS.SetRect(rect, lastColumnRight, nmcd.top, nmcd.right, nmcd.bottom-1);
7788 long brush = OS.CreateSolidBrush(getHeaderBackgroundPixel());
7789 OS.FillRect(nmcd.hdc, rect, brush);
7790 OS.DeleteObject(brush);
7793 // always draw the highlighted border at the end, to avoid overdrawing by other borders.
7794 if (highlightedHeaderDividerX != -1) {
7795 long pen = OS.CreatePen (OS.PS_SOLID, 4, OS.GetSysColor(OS.COLOR_HIGHLIGHT));
7796 long oldPen = OS.SelectObject (nmcd.hdc, pen);
7797 OS.Polyline(nmcd.hdc, new int[] {highlightedHeaderDividerX, nmcd.top, highlightedHeaderDividerX, nmcd.bottom}, 2);
7798 OS.SelectObject (nmcd.hdc, oldPen);
7799 OS.DeleteObject (pen);
7802 return new LRESULT(OS.CDRF_DODEFAULT);
7807 case OS.NM_RELEASEDCAPTURE: {
7808 if (!ignoreColumnMove) {
7809 for (int i=0; i<columnCount; i++) {
7810 TreeColumn column = columns [i];
7811 column.updateToolTip (i);
7815 ignoreColumnMove = false;
7818 case OS.HDN_BEGINDRAG: {
7819 if (ignoreColumnMove) return LRESULT.ONE;
7820 NMHEADER phdn = new NMHEADER ();
7821 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7822 if (phdn.iItem != -1) {
7823 TreeColumn column = columns [phdn.iItem];
7824 if (column != null && !column.getMoveable ()) {
7825 ignoreColumnMove = true;
7828 headerItemDragging = true;
7832 case OS.HDN_ENDDRAG: {
7833 headerItemDragging = false;
7834 NMHEADER phdn = new NMHEADER ();
7835 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7836 if (phdn.iItem != -1 && phdn.pitem != 0) {
7837 HDITEM pitem = new HDITEM ();
7838 OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
7839 if ((pitem.mask & OS.HDI_ORDER) != 0 && pitem.iOrder != -1) {
7840 int [] order = new int [columnCount];
7841 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
7843 while (index < order.length) {
7844 if (order [index] == phdn.iItem) break;
7847 if (index == order.length) index = 0;
7848 if (index == pitem.iOrder) break;
7849 int start = Math.min (index, pitem.iOrder);
7850 int end = Math.max (index, pitem.iOrder);
7851 RECT rect = new RECT (), headerRect = new RECT ();
7852 OS.GetClientRect (handle, rect);
7853 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [start], headerRect);
7854 rect.left = Math.max (rect.left, headerRect.left);
7855 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, order [end], headerRect);
7856 rect.right = Math.min (rect.right, headerRect.right);
7857 OS.InvalidateRect (handle, rect, true);
7858 ignoreColumnMove = false;
7859 for (int i=start; i<=end; i++) {
7860 TreeColumn column = columns [order [i]];
7861 if (!column.isDisposed ()) {
7862 column.postEvent (SWT.Move);
7869 case OS.HDN_ITEMCHANGING: {
7870 NMHEADER phdn = new NMHEADER ();
7871 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7872 if (phdn.pitem != 0) {
7873 HDITEM newItem = new HDITEM ();
7874 OS.MoveMemory (newItem, phdn.pitem, HDITEM.sizeof);
7875 if ((newItem.mask & OS.HDI_WIDTH) != 0) {
7876 RECT rect = new RECT ();
7877 OS.GetClientRect (handle, rect);
7878 HDITEM oldItem = new HDITEM ();
7879 oldItem.mask = OS.HDI_WIDTH;
7880 OS.SendMessage (hwndHeader, OS.HDM_GETITEM, phdn.iItem, oldItem);
7881 int deltaX = newItem.cxy - oldItem.cxy;
7882 RECT headerRect = new RECT ();
7883 OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, phdn.iItem, headerRect);
7884 int gridWidth = linesVisible ? GRID_WIDTH : 0;
7885 rect.left = headerRect.right - gridWidth;
7886 int newX = rect.left + deltaX;
7887 rect.right = Math.max (rect.right, rect.left + Math.abs (deltaX));
7888 if (explorerTheme || (findImageControl () != null || hooks (SWT.MeasureItem) || hooks (SWT.EraseItem) || hooks (SWT.PaintItem))) {
7889 rect.left -= OS.GetSystemMetrics (OS.SM_CXFOCUSBORDER);
7890 OS.InvalidateRect (handle, rect, true);
7891 OS.OffsetRect (rect, deltaX, 0);
7892 OS.InvalidateRect (handle, rect, true);
7894 int flags = OS.SW_INVALIDATE | OS.SW_ERASE;
7895 OS.ScrollWindowEx (handle, deltaX, 0, rect, null, 0, null, flags);
7897 if (OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, phdn.iItem, 0) != 0) {
7898 rect.left = headerRect.left;
7900 OS.InvalidateRect (handle, rect, true);
7907 case OS.HDN_ITEMCHANGED: {
7908 NMHEADER phdn = new NMHEADER ();
7909 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7910 if (phdn.pitem != 0) {
7911 HDITEM pitem = new HDITEM ();
7912 OS.MoveMemory (pitem, phdn.pitem, HDITEM.sizeof);
7913 if ((pitem.mask & OS.HDI_WIDTH) != 0) {
7914 if (ignoreColumnMove) {
7915 int flags = OS.RDW_UPDATENOW | OS.RDW_ALLCHILDREN;
7916 OS.RedrawWindow (handle, null, 0, flags);
7918 TreeColumn column = columns [phdn.iItem];
7919 if (column != null) {
7920 column.updateToolTip (phdn.iItem);
7921 column.sendEvent (SWT.Resize);
7922 if (isDisposed ()) return LRESULT.ZERO;
7923 TreeColumn [] newColumns = new TreeColumn [columnCount];
7924 System.arraycopy (columns, 0, newColumns, 0, columnCount);
7925 int [] order = new int [columnCount];
7926 OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order);
7927 boolean moved = false;
7928 for (int i=0; i<columnCount; i++) {
7929 TreeColumn nextColumn = newColumns [order [i]];
7930 if (moved && !nextColumn.isDisposed ()) {
7931 nextColumn.updateToolTip (order [i]);
7932 nextColumn.sendEvent (SWT.Move);
7934 if (nextColumn == column) moved = true;
7942 case OS.HDN_ITEMCLICK: {
7943 NMHEADER phdn = new NMHEADER ();
7944 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7945 TreeColumn column = columns [phdn.iItem];
7946 if (column != null) {
7947 column.sendSelectionEvent (SWT.Selection);
7951 case OS.HDN_ITEMDBLCLICK: {
7952 NMHEADER phdn = new NMHEADER ();
7953 OS.MoveMemory (phdn, lParam, NMHEADER.sizeof);
7954 TreeColumn column = columns [phdn.iItem];
7955 if (column != null) {
7956 column.sendSelectionEvent (SWT.DefaultSelection);
7964 LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
7966 case OS.NM_CUSTOMDRAW: {
7967 NMTTCUSTOMDRAW nmcd = new NMTTCUSTOMDRAW ();
7968 OS.MoveMemory (nmcd, lParam, NMTTCUSTOMDRAW.sizeof);
7969 return wmNotifyToolTip (nmcd, lParam);
7972 LRESULT result = super.wmNotify (hdr, wParam, lParam);
7973 if (result != null) return result;
7974 int pos = OS.GetMessagePos ();
7975 POINT pt = new POINT();
7976 OS.POINTSTOPOINT (pt, pos);
7977 OS.ScreenToClient (handle, pt);
7978 int [] index = new int [1];
7979 TreeItem [] item = new TreeItem [1];
7980 RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
7981 if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
7982 RECT toolRect = toolTipRect (itemRect [0]);
7983 OS.MapWindowPoints (handle, 0, toolRect, 2);
7984 int width = toolRect.right - toolRect.left;
7985 int height = toolRect.bottom - toolRect.top;
7986 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER | OS.SWP_NOSIZE;
7987 if (isCustomToolTip ()) flags &= ~OS.SWP_NOSIZE;
7988 OS.SetWindowPos (itemToolTipHandle, 0, toolRect.left, toolRect.top, width, height, flags);
7997 LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd, long lParam) {
7998 switch (nmcd.dwDrawStage) {
7999 case OS.CDDS_PREPAINT: {
8000 if (isCustomToolTip ()) {
8002 //nmcd.uDrawFlags |= OS.DT_CALCRECT;
8003 //OS.MoveMemory (lParam, nmcd, NMTTCUSTOMDRAW.sizeof);
8004 return new LRESULT (OS.CDRF_NOTIFYPOSTPAINT | OS.CDRF_NEWFONT);
8008 case OS.CDDS_POSTPAINT: {
8009 if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, 0) != 0) {
8010 TOOLINFO lpti = new TOOLINFO ();
8011 lpti.cbSize = TOOLINFO.sizeof;
8012 if (OS.SendMessage (itemToolTipHandle, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
8013 int [] index = new int [1];
8014 TreeItem [] item = new TreeItem [1];
8015 RECT [] cellRect = new RECT [1], itemRect = new RECT [1];
8016 int pos = OS.GetMessagePos ();
8017 POINT pt = new POINT();
8018 OS.POINTSTOPOINT (pt, pos);
8019 OS.ScreenToClient (handle, pt);
8020 if (findCell (pt.x, pt.y, item, index, cellRect, itemRect)) {
8021 long hDC = OS.GetDC (handle);
8022 long hFont = item [0].fontHandle (index [0]);
8023 if (hFont == -1) hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
8024 long oldFont = OS.SelectObject (hDC, hFont);
8025 boolean drawForeground = true;
8026 cellRect [0] = item [0].getBounds (index [0], true, true, false, false, false, hDC);
8027 if (hooks (SWT.EraseItem)) {
8028 Event event = sendEraseItemEvent (item [0], nmcd, index [0], cellRect [0]);
8029 if (isDisposed () || item [0].isDisposed ()) break;
8031 drawForeground = (event.detail & SWT.FOREGROUND) != 0;
8033 drawForeground = false;
8036 if (drawForeground) {
8037 int nSavedDC = OS.SaveDC (nmcd.hdc);
8038 int gridWidth = getLinesVisible () ? Table.GRID_WIDTH : 0;
8039 RECT insetRect = toolTipInset (cellRect [0]);
8040 OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null);
8041 GCData data = new GCData ();
8042 data.device = display;
8043 data.foreground = OS.GetTextColor (nmcd.hdc);
8044 data.background = OS.GetBkColor (nmcd.hdc);
8045 data.font = Font.win32_new (display, hFont);
8046 GC gc = GC.win32_new (nmcd.hdc, data);
8047 int x = cellRect [0].left + INSET;
8048 if (index [0] != 0) x -= gridWidth;
8049 Image image = item [0].getImage (index [0]);
8050 if (image != null || index [0] == 0) {
8051 Point size = getImageSize ();
8052 RECT imageRect = item [0].getBounds (index [0], false, true, false, false, false, hDC);
8053 if (imageList == null) size.x = imageRect.right - imageRect.left;
8054 if (image != null) {
8055 Rectangle rect = image.getBounds (); // Points
8056 gc.drawImage (image, rect.x, rect.y, rect.width, rect.height, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(imageRect.top), DPIUtil.autoScaleDown(size.x), DPIUtil.autoScaleDown(size.y));
8057 x += INSET + (index [0] == 0 ? 1 : 0);
8063 String string = item [0].getText (index [0]);
8064 if (string != null) {
8065 int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER;
8066 TreeColumn column = columns != null ? columns [index [0]] : null;
8067 if (column != null) {
8068 if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER;
8069 if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT;
8071 char [] buffer = string.toCharArray ();
8072 RECT textRect = new RECT ();
8073 OS.SetRect (textRect, x, cellRect [0].top, cellRect [0].right, cellRect [0].bottom);
8074 OS.DrawText (nmcd.hdc, buffer, buffer.length, textRect, flags);
8077 OS.RestoreDC (nmcd.hdc, nSavedDC);
8079 if (hooks (SWT.PaintItem)) {
8080 itemRect [0] = item [0].getBounds (index [0], true, true, false, false, false, hDC);
8081 sendPaintItemEvent (item [0], nmcd, index[0], itemRect [0]);
8083 OS.SelectObject (hDC, oldFont);
8084 OS.ReleaseDC (handle, hDC);