/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.win32.*; /** * Instances of this class provide a selectable user interface object * that displays a hierarchy of items and issues notification when an * item in the hierarchy is selected. *

* The item children that may be added to instances of this class * must be of type TreeItem. *

* Style VIRTUAL is used to create a Tree whose * TreeItems are to be populated by the client on an on-demand basis * instead of up-front. This can provide significant performance improvements for * trees that are very large or for which TreeItem population is * expensive (for example, retrieving values from an external source). *

* Here is an example of using a Tree with style VIRTUAL:

*

 *  final Tree tree = new Tree(parent, SWT.VIRTUAL | SWT.BORDER);
 *  tree.setItemCount(20);
 *  tree.addListener(SWT.SetData, new Listener() {
 *      public void handleEvent(Event event) {
 *          TreeItem item = (TreeItem)event.item;
 *          TreeItem parentItem = item.getParentItem();
 *          String text = null;
 *          if (parentItem == null) {
 *              text = "node " + tree.indexOf(item);
 *          } else {
 *              text = parentItem.getText() + " - " + parentItem.indexOf(item);
 *          }
 *          item.setText(text);
 *          System.out.println(text);
 *          item.setItemCount(10);
 *      }
 *  });
 * 
*

* Note that although this class is a subclass of Composite, * it does not normally make sense to add Control children to * it, or set a layout on it, unless implementing something like a cell * editor. *

*
*
Styles:
*
SINGLE, MULTI, CHECK, FULL_SELECTION, VIRTUAL, NO_SCROLL
*
Events:
*
Selection, DefaultSelection, Collapse, Expand, SetData, MeasureItem, EraseItem, PaintItem
*
*

* Note: Only one of the styles SINGLE and MULTI may be specified. *

* IMPORTANT: This class is not intended to be subclassed. *

* * @see Tree, TreeItem, TreeColumn snippets * @see SWT Example: ControlExample * @see Sample code and further information * @noextend This class is not intended to be subclassed by clients. */ public class Tree extends Composite { TreeItem [] items; TreeColumn [] columns; int columnCount; ImageList imageList, headerImageList; TreeItem currentItem; TreeColumn sortColumn; RECT focusRect; long hwndParent, hwndHeader, hAnchor, hInsert, hSelect; int lastID; long hFirstIndexOf, hLastIndexOf; int lastIndexOf, itemCount, sortDirection; boolean dragStarted, gestureCompleted, insertAfter, shrink, ignoreShrink; boolean ignoreSelect, ignoreExpand, ignoreDeselect, ignoreResize; boolean lockSelection, oldSelected, newSelected, ignoreColumnMove; boolean linesVisible, customDraw, painted, ignoreItemHeight; boolean ignoreCustomDraw, ignoreDrawForeground, ignoreDrawBackground, ignoreDrawFocus; boolean ignoreDrawSelection, ignoreDrawHot, ignoreFullSelection, explorerTheme; boolean createdAsRTL; boolean headerItemDragging; int scrollWidth, selectionForeground; long headerToolTipHandle, itemToolTipHandle; long lastTimerID = -1; int lastTimerCount; int headerBackground = -1; int headerForeground = -1; static final boolean ENABLE_TVS_EX_FADEINOUTEXPANDOS = System.getProperty("org.eclipse.swt.internal.win32.enableFadeInOutExpandos") != null; static final int TIMER_MAX_COUNT = 8; static final int INSET = 3; static final int GRID_WIDTH = 1; static final int SORT_WIDTH = 10; static final int HEADER_MARGIN = 12; static final int HEADER_EXTRA = 3; static final int INCREMENT = 5; static final int EXPLORER_EXTRA = 2; static final int DRAG_IMAGE_SIZE = 301; static final long TreeProc; static final TCHAR TreeClass = new TCHAR (0, OS.WC_TREEVIEW, true); static final long HeaderProc; static final TCHAR HeaderClass = new TCHAR (0, OS.WC_HEADER, true); static { WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, TreeClass, lpWndClass); TreeProc = lpWndClass.lpfnWndProc; OS.GetClassInfo (0, HeaderClass, lpWndClass); HeaderProc = lpWndClass.lpfnWndProc; } /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* * @param parent a composite control which will be the parent of the new instance (cannot be null) * @param style the style of control to construct * * @exception IllegalArgumentException * @exception SWTException * * @see SWT#SINGLE * @see SWT#MULTI * @see SWT#CHECK * @see SWT#FULL_SELECTION * @see SWT#VIRTUAL * @see SWT#NO_SCROLL * @see Widget#checkSubclass * @see Widget#getStyle */ public Tree (Composite parent, int style) { super (parent, checkStyle (style)); } static int checkStyle (int style) { /* * Feature in Windows. Even when WS_HSCROLL or * WS_VSCROLL is not specified, Windows creates * trees and tables with scroll bars. The fix * is to set H_SCROLL and V_SCROLL. * * NOTE: This code appears on all platforms so that * applications have consistent scroll bar behavior. */ if ((style & SWT.NO_SCROLL) == 0) { style |= SWT.H_SCROLL | SWT.V_SCROLL; } /* * Note: Windows only supports TVS_NOSCROLL and TVS_NOHSCROLL. */ if ((style & SWT.H_SCROLL) != 0 && (style & SWT.V_SCROLL) == 0) { style |= SWT.V_SCROLL; } return checkBits (style, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0); } @Override void _addListener (int eventType, Listener listener) { super._addListener (eventType, listener); switch (eventType) { case SWT.DragDetect: { if ((state & DRAG_DETECT) != 0) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); bits &= ~OS.TVS_DISABLEDRAGDROP; OS.SetWindowLong (handle, OS.GWL_STYLE, bits); } break; } case SWT.MeasureItem: case SWT.EraseItem: case SWT.PaintItem: { customDraw = true; style |= SWT.DOUBLE_BUFFERED; if (isCustomToolTip ()) createItemToolTips (); OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0); int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if (eventType == SWT.MeasureItem) { /* * This code is intentionally commented. */ // if (explorerTheme) { // int bits1 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0); // bits1 &= ~OS.TVS_EX_AUTOHSCROLL; // OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits1); // } bits |= OS.TVS_NOHSCROLL; } /* * Feature in Windows. When the tree has the style * TVS_FULLROWSELECT, the background color for the * entire row is filled when an item is painted, * drawing on top of any custom drawing. The fix * is to clear TVS_FULLROWSELECT. */ if ((style & SWT.FULL_SELECTION) != 0) { if (eventType != SWT.MeasureItem) { if (!explorerTheme) bits &= ~OS.TVS_FULLROWSELECT; } } if (bits != OS.GetWindowLong (handle, OS.GWL_STYLE)) { OS.SetWindowLong (handle, OS.GWL_STYLE, bits); OS.InvalidateRect (handle, null, true); /* * Bug in Windows. When TVS_NOHSCROLL is set after items * have been inserted into the tree, Windows shows the * scroll bar. The fix is to check for this case and * explicitly hide the scroll bar. */ int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0); if (count != 0 && (bits & OS.TVS_NOHSCROLL) != 0) { OS.ShowScrollBar (handle, OS.SB_HORZ, false); } } break; } } } TreeItem _getItem (long hItem) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; tvItem.hItem = hItem; if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) { return _getItem (tvItem.hItem, (int)tvItem.lParam); } return null; } TreeItem _getItem (long hItem, int id) { if ((style & SWT.VIRTUAL) == 0) return items [id]; return id != -1 ? items [id] : new TreeItem (this, SWT.NONE, -1, -1, hItem); } @Override void _removeListener (int eventType, Listener listener) { super._removeListener (eventType, listener); switch (eventType) { case SWT.MeasureItem: { /** * If H_SCROLL is set, reverting the TVS_NOHSCROLL settings which * was applied while adding SWT.MeasureItem event Listener. */ if ((style & SWT.H_SCROLL) != 0 && (state & DISPOSE_SENT) == 0) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); bits &= ~OS.TVS_NOHSCROLL; OS.SetWindowLong (handle, OS.GWL_STYLE, bits); OS.InvalidateRect (handle, null, true); } break; } } } void _setBackgroundPixel (int newPixel) { int oldPixel = (int)OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0); if (oldPixel != newPixel) { /* * Bug in Windows. When TVM_SETBKCOLOR is used more * than once to set the background color of a tree, * the background color of the lines and the plus/minus * does not change to the new color. The fix is to set * the background color to the default before setting * the new color. */ if (oldPixel != -1) { OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1); } /* Set the background color */ OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, newPixel); /* * Feature in Windows. When TVM_SETBKCOLOR is used to * set the background color of a tree, the plus/minus * animation draws badly. The fix is to clear the effect. */ if (explorerTheme && ENABLE_TVS_EX_FADEINOUTEXPANDOS) { int bits2 = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0); if (newPixel == -1 && findImageControl () == null) { bits2 |= OS.TVS_EX_FADEINOUTEXPANDOS; } else { bits2 &= ~OS.TVS_EX_FADEINOUTEXPANDOS; } OS.SendMessage (handle, OS.TVM_SETEXTENDEDSTYLE, 0, bits2); } /* Set the checkbox image list */ if ((style & SWT.CHECK) != 0) setCheckboxImageList (); } } /** * Adds the listener to the collection of listeners who will * be notified when the user changes the receiver's selection, by sending * it one of the messages defined in the SelectionListener * interface. *

* When widgetSelected is called, the item field of the event object is valid. * If the receiver has the SWT.CHECK style and the check selection changes, * the event object detail field contains the value SWT.CHECK. * widgetDefaultSelected is typically called when an item is double-clicked. * The item field of the event object is valid for default selection, but the detail field is not used. *

* * @param listener the listener which should be notified when the user changes the receiver's selection * * @exception IllegalArgumentException * @exception SWTException * * @see SelectionListener * @see #removeSelectionListener * @see SelectionEvent */ public void addSelectionListener(SelectionListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Selection, typedListener); addListener (SWT.DefaultSelection, typedListener); } /** * Adds the listener to the collection of listeners who will * be notified when an item in the receiver is expanded or collapsed * by sending it one of the messages defined in the TreeListener * interface. * * @param listener the listener which should be notified * * @exception IllegalArgumentException * @exception SWTException * * @see TreeListener * @see #removeTreeListener */ public void addTreeListener(TreeListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Expand, typedListener); addListener (SWT.Collapse, typedListener); } @Override long borderHandle () { return hwndParent != 0 ? hwndParent : handle; } LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) { if (ignoreCustomDraw) return null; if (nmcd.left == nmcd.right) return new LRESULT (OS.CDRF_DODEFAULT); long hDC = nmcd.hdc; OS.RestoreDC (hDC, -1); TreeItem item = getItem (nmcd); /* * Feature in Windows. When a new tree item is inserted * using TVM_INSERTITEM and the tree is using custom draw, * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns * and before the item is added to the items array. The * fix is to check for null. * * NOTE: This only happens on XP with the version 6.00 of * COMCTL32.DLL, */ if (item == null) return null; /* * Feature in Windows. Under certain circumstances, Windows * sends CDDS_ITEMPOSTPAINT for an empty rectangle. This is * not a problem providing that graphics do not occur outside * the rectangle. The fix is to test for the rectangle and * draw nothing. * * NOTE: This seems to happen when both I_IMAGECALLBACK * and LPSTR_TEXTCALLBACK are used at the same time with * TVM_SETITEM. */ if (nmcd.left >= nmcd.right || nmcd.top >= nmcd.bottom) return null; if (!OS.IsWindowVisible (handle)) return null; if ((style & SWT.FULL_SELECTION) != 0 || findImageControl () != null || ignoreDrawSelection || explorerTheme) { OS.SetBkMode (hDC, OS.TRANSPARENT); } boolean selected = isItemSelected (nmcd); boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0; if (OS.IsWindowEnabled (handle)) { if (explorerTheme) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & OS.TVS_TRACKSELECT) != 0) { if ((style & SWT.FULL_SELECTION) != 0 && (selected || hot)) { OS.SetTextColor (hDC, OS.GetSysColor (OS.COLOR_WINDOWTEXT)); } else { OS.SetTextColor (hDC, getForegroundPixel ()); } } } } int [] order = null; RECT clientRect = new RECT (); OS.GetClientRect (scrolledHandle (), clientRect); if (hwndHeader != 0) { OS.MapWindowPoints (hwndParent, handle, clientRect, 2); if (columnCount != 0) { order = new int [columnCount]; OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order); } } int sortIndex = -1, clrSortBk = -1; if (OS.IsAppThemed ()) { if (sortColumn != null && sortDirection != SWT.NONE) { if (findImageControl () == null) { sortIndex = indexOf (sortColumn); clrSortBk = getSortColumnPixel (); } } } int x = 0; Point size = null; for (int i=0; i 0 && hwndHeader != 0) { HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); width = hdItem.cxy; } if (i == 0) { if ((style & SWT.FULL_SELECTION) != 0) { boolean clear = !explorerTheme && !ignoreDrawSelection && findImageControl () == null; if (clear || (selected && !ignoreDrawSelection) || (hot && !ignoreDrawHot)) { boolean draw = true; RECT pClipRect = new RECT (); OS.SetRect (pClipRect, width, nmcd.top, nmcd.right, nmcd.bottom); if (explorerTheme) { if (hooks (SWT.EraseItem)) { RECT itemRect = item.getBounds (index, true, true, false, false, true, hDC); itemRect.left -= EXPLORER_EXTRA; itemRect.right += EXPLORER_EXTRA + 1; pClipRect.left = itemRect.left; pClipRect.right = itemRect.right; if (columnCount > 0 && hwndHeader != 0) { HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); pClipRect.right = Math.min (pClipRect.right, nmcd.left + hdItem.cxy); } } RECT pRect = new RECT (); OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); if (columnCount > 0 && hwndHeader != 0) { int totalWidth = 0; HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; for (int j=0; j clientRect.right - clientRect.left) { pRect.left = 0; pRect.right = totalWidth; } else { pRect.left = clientRect.left; pRect.right = clientRect.right; } } draw = false; long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW); int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT; if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS; OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect); OS.CloseThemeData (hTheme); } if (draw) fillBackground (hDC, OS.GetBkColor (hDC), pClipRect); } } } if (x + width > clientRect.left) { RECT rect = new RECT (), backgroundRect = null; boolean drawItem = true, drawText = true, drawImage = true, drawBackground = false; if (i == 0) { drawItem = drawImage = drawText = false; if (findImageControl () != null) { if (explorerTheme) { if (OS.IsWindowEnabled (handle) && !hooks (SWT.EraseItem)) { Image image = null; if (index == 0) { image = item.image; } else { Image [] images = item.images; if (images != null) image = images [index]; } if (image != null) { Rectangle bounds = image.getBounds (); // Points if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points if (!ignoreDrawForeground) { GCData data = new GCData(); data.device = display; GC gc = GC.win32_new (hDC, data); RECT iconRect = item.getBounds (index, false, true, false, false, true, hDC); // Pixels gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(iconRect.left, iconRect.top, iconRect.right - iconRect.left, iconRect.bottom - iconRect.top))); gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(iconRect.left), DPIUtil.autoScaleDown(iconRect.top), size.x, size.y); OS.SelectClipRgn (hDC, 0); gc.dispose (); } } } } else { drawItem = drawText = drawBackground = true; rect = item.getBounds (index, true, false, false, false, true, hDC); if (linesVisible) { rect.right++; rect.bottom++; } } } if (selected && !ignoreDrawSelection && !ignoreDrawBackground) { if (!explorerTheme) fillBackground (hDC, OS.GetBkColor (hDC), rect); drawBackground = false; } backgroundRect = rect; if (hooks (SWT.EraseItem)) { drawItem = drawText = drawImage = true; rect = item.getBounds (index, true, true, false, false, true, hDC); if ((style & SWT.FULL_SELECTION) != 0) { backgroundRect = rect; } else { backgroundRect = item.getBounds (index, true, false, false, false, true, hDC); } } } else { selectionForeground = -1; ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = false; OS.SetRect (rect, x, nmcd.top, x + width, nmcd.bottom); backgroundRect = rect; } int clrText = -1, clrTextBk = -1; long hFont = item.fontHandle (index); if (selectionForeground != -1) clrText = selectionForeground; if (OS.IsWindowEnabled (handle)) { boolean drawForeground = false; if (selected) { if (i != 0 && (style & SWT.FULL_SELECTION) == 0) { OS.SetTextColor (hDC, getForegroundPixel ()); OS.SetBkColor (hDC, getBackgroundPixel ()); drawForeground = drawBackground = true; } } else { drawForeground = drawBackground = true; } if (drawForeground) { clrText = item.cellForeground != null ? item.cellForeground [index] : -1; if (clrText == -1) clrText = item.foreground; } if (drawBackground) { clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1; if (clrTextBk == -1) clrTextBk = item.background; if (clrTextBk == -1 && index == sortIndex) clrTextBk = clrSortBk; } } else { if (clrTextBk == -1 && index == sortIndex) { drawBackground = true; clrTextBk = clrSortBk; } } if (explorerTheme) { if (selected || (nmcd.uItemState & OS.CDIS_HOT) != 0) { if ((style & SWT.FULL_SELECTION) != 0) { drawBackground = false; } else { if (i == 0) { drawBackground = false; if (!hooks (SWT.EraseItem)) drawText = false; } } } } if (drawItem) { if (i != 0) { if (hooks (SWT.MeasureItem)) { sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0); if (isDisposed () || item.isDisposed ()) break; } if (hooks (SWT.EraseItem)) { RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC); int nSavedDC = OS.SaveDC (hDC); GCData data = new GCData (); data.device = display; data.foreground = OS.GetTextColor (hDC); data.background = OS.GetBkColor (hDC); if (!selected || (style & SWT.FULL_SELECTION) == 0) { if (clrText != -1) data.foreground = clrText; if (clrTextBk != -1) data.background = clrTextBk; } data.font = item.getFont (index); data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); GC gc = GC.win32_new (hDC, data); Event event = new Event (); event.item = item; event.index = index; event.gc = gc; event.detail |= SWT.FOREGROUND; if (clrTextBk != -1) event.detail |= SWT.BACKGROUND; if ((style & SWT.FULL_SELECTION) != 0) { if (hot) event.detail |= SWT.HOT; if (selected) event.detail |= SWT.SELECTED; if (!explorerTheme) { //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) { if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) { if (handle == OS.GetFocus ()) { int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED; } } } } Rectangle boundsInPixels = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top); event.setBoundsInPixels (boundsInPixels); gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels)); sendEvent (SWT.EraseItem, event); event.gc = null; int newTextClr = data.foreground; gc.dispose (); OS.RestoreDC (hDC, nSavedDC); if (isDisposed () || item.isDisposed ()) break; if (event.doit) { ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0; ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0; if ((style & SWT.FULL_SELECTION) != 0) { ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0; ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0; ignoreDrawHot = (event.detail & SWT.HOT) == 0; } } else { ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true; } if (selected && ignoreDrawSelection) ignoreDrawHot = true; if ((style & SWT.FULL_SELECTION) != 0) { if (ignoreDrawSelection) ignoreFullSelection = true; if (!ignoreDrawSelection || !ignoreDrawHot) { if (!selected && !hot) { selectionForeground = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT); } else { if (!explorerTheme) { drawBackground = true; ignoreDrawBackground = false; if ((handle == OS.GetFocus () || display.getHighContrast ()) && OS.IsWindowEnabled (handle)) { clrTextBk = OS.GetSysColor (OS.COLOR_HIGHLIGHT); } else { clrTextBk = OS.GetSysColor (OS.COLOR_3DFACE); } if (!ignoreFullSelection && index == columnCount - 1) { RECT selectionRect = new RECT (); OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, nmcd.right, backgroundRect.bottom); backgroundRect = selectionRect; } } else { RECT pRect = new RECT (); OS.SetRect (pRect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); if (columnCount > 0 && hwndHeader != 0) { int totalWidth = 0; HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; for (int j=0; j clientRect.right - clientRect.left) { pRect.left = 0; pRect.right = totalWidth; } else { pRect.left = clientRect.left; pRect.right = clientRect.right; } if (index == columnCount - 1) { RECT selectionRect = new RECT (); OS.SetRect (selectionRect, backgroundRect.left, backgroundRect.top, pRect.right, backgroundRect.bottom); backgroundRect = selectionRect; } } long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW); int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT; if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS; OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, backgroundRect); OS.CloseThemeData (hTheme); } } } else { if (selected) { selectionForeground = newTextClr; if (!explorerTheme) { if (clrTextBk == -1 && OS.IsWindowEnabled (handle)) { Control control = findBackgroundControl (); if (control == null) control = this; clrTextBk = control.getBackgroundPixel (); } } } } } } if (selectionForeground != -1) clrText = selectionForeground; } if (!ignoreDrawBackground) { if (clrTextBk != -1) { if (drawBackground) fillBackground (hDC, clrTextBk, backgroundRect); } else { Control control = findImageControl (); if (control != null) { if (i == 0) { int right = Math.min (rect.right, width); OS.SetRect (rect, rect.left, rect.top, right, rect.bottom); if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0); } else { if (drawBackground) fillImageBackground (hDC, control, rect, 0, 0); } } } } rect.left += INSET - 1; if (drawImage) { Image image = null; if (index == 0) { image = item.image; } else { Image [] images = item.images; if (images != null) image = images [index]; } int inset = i != 0 ? INSET : 0; int offset = i != 0 ? INSET : INSET + 2; if (image != null) { Rectangle bounds = image.getBounds (); // Points if (size == null) size = DPIUtil.autoScaleDown (getImageSize ()); // To Points if (!ignoreDrawForeground) { //int y1 = rect.top + (index == 0 ? (getItemHeight () - size.y) / 2 : 0); int y1 = rect.top + DPIUtil.autoScaleUp((getItemHeight () - size.y) / 2); int x1 = Math.max (rect.left, rect.left - inset + 1); GCData data = new GCData(); data.device = display; GC gc = GC.win32_new (hDC, data); gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(x1, rect.top, rect.right - x1, rect.bottom - rect.top))); gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(x1), DPIUtil.autoScaleDown(y1), size.x, size.y); OS.SelectClipRgn (hDC, 0); gc.dispose (); } OS.SetRect (rect, rect.left + DPIUtil.autoScaleUp(size.x) + offset, rect.top, rect.right - inset, rect.bottom); } else { if (i == 0) { if (OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0) != 0) { if (size == null) size = getImageSize (); rect.left = Math.min (rect.left + size.x + offset, rect.right); } } else { OS.SetRect (rect, rect.left + offset, rect.top, rect.right - inset, rect.bottom); } } } if (drawText) { /* * Bug in Windows. When DrawText() is used with DT_VCENTER * and DT_ENDELLIPSIS, the ellipsis can draw outside of the * rectangle when the rectangle is empty. The fix is avoid * all text drawing for empty rectangles. */ if (rect.left < rect.right) { String string = null; if (index == 0) { string = item.text; } else { String [] strings = item.strings; if (strings != null) string = strings [index]; } if (string != null) { if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText); if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk); int flags = OS.DT_NOPREFIX | OS.DT_SINGLELINE | OS.DT_VCENTER; if (i != 0) flags |= OS.DT_ENDELLIPSIS; TreeColumn column = columns != null ? columns [index] : null; if (column != null) { if ((column.style & SWT.CENTER) != 0) flags |= OS.DT_CENTER; if ((column.style & SWT.RIGHT) != 0) flags |= OS.DT_RIGHT; } if ((string != null) && (string.length() > Item.TEXT_LIMIT)) { string = string.substring(0, Item.TEXT_LIMIT - Item.ELLIPSIS.length()) + Item.ELLIPSIS; } char [] buffer = string.toCharArray (); if (!ignoreDrawForeground) OS.DrawText (hDC, buffer, buffer.length, rect, flags); OS.DrawText (hDC, buffer, buffer.length, rect, flags | OS.DT_CALCRECT); if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); if (clrText != -1) clrText = OS.SetTextColor (hDC, clrText); if (clrTextBk != -1) clrTextBk = OS.SetBkColor (hDC, clrTextBk); } } } } if (selectionForeground != -1) clrText = selectionForeground; if (hooks (SWT.PaintItem)) { RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC); int nSavedDC = OS.SaveDC (hDC); GCData data = new GCData (); data.device = display; data.font = item.getFont (index); data.foreground = OS.GetTextColor (hDC); data.background = OS.GetBkColor (hDC); if (selected && (style & SWT.FULL_SELECTION) != 0) { if (selectionForeground != -1) data.foreground = selectionForeground; } else { if (clrText != -1) data.foreground = clrText; if (clrTextBk != -1) data.background = clrTextBk; } data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); GC gc = GC.win32_new (hDC, data); Event event = new Event (); event.item = item; event.index = index; event.gc = gc; event.detail |= SWT.FOREGROUND; if (clrTextBk != -1) event.detail |= SWT.BACKGROUND; if (hot) event.detail |= SWT.HOT; if (selected && (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0)) { event.detail |= SWT.SELECTED; } if (!explorerTheme) { //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) { if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) { if (i == 0 /*nmcd.iSubItem == 0*/ || (style & SWT.FULL_SELECTION) != 0) { if (handle == OS.GetFocus ()) { int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); if ((uiState & OS.UISF_HIDEFOCUS) == 0) event.detail |= SWT.FOCUSED; } } } } event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top)); RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC); int cellWidth = cellRect.right - cellRect.left; int cellHeight = cellRect.bottom - cellRect.top; gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(cellRect.left, cellRect.top, cellWidth, cellHeight))); sendEvent (SWT.PaintItem, event); if (data.focusDrawn) focusRect = null; event.gc = null; gc.dispose (); OS.RestoreDC (hDC, nSavedDC); if (isDisposed () || item.isDisposed ()) break; } } x += width; if (x > clientRect.right) break; } if (linesVisible) { if ((style & SWT.FULL_SELECTION) != 0) { if (columnCount != 0) { HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, 0, hdItem); RECT rect = new RECT (); OS.SetRect (rect, nmcd.left + hdItem.cxy, nmcd.top, nmcd.right, nmcd.bottom); OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM); } } RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM); } if (!ignoreDrawFocus && focusRect != null) { OS.DrawFocusRect (hDC, focusRect); focusRect = null; } else { if (!explorerTheme) { if (handle == OS.GetFocus ()) { int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); if ((uiState & OS.UISF_HIDEFOCUS) == 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem == item.handle) { if (!ignoreDrawFocus && findImageControl () != null) { if ((style & SWT.FULL_SELECTION) != 0) { RECT focusRect = new RECT (); OS.SetRect (focusRect, 0, nmcd.top, clientRect.right + 1, nmcd.bottom); OS.DrawFocusRect (hDC, focusRect); } else { int index = (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0); RECT focusRect = item.getBounds (index, true, false, false, false, false, hDC); RECT clipRect = item.getBounds (index, true, false, false, false, true, hDC); OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); OS.DrawFocusRect (hDC, focusRect); OS.SelectClipRgn (hDC, 0); } } } } } } } return new LRESULT (OS.CDRF_DODEFAULT); } LRESULT CDDS_ITEMPREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) { /* * Even when custom draw is being ignored, the font needs * to be selected into the HDC so that the item bounds are * measured correctly. */ TreeItem item = getItem (nmcd); /* * Feature in Windows. When a new tree item is inserted * using TVM_INSERTITEM and the tree is using custom draw, * a NM_CUSTOMDRAW is sent before TVM_INSERTITEM returns * and before the item is added to the items array. The * fix is to check for null. * * NOTE: This only happens on XP with the version 6.00 of * COMCTL32.DLL, */ if (item == null) return null; long hDC = nmcd.hdc; int index = hwndHeader != 0 ? (int)OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) : 0; long hFont = item.fontHandle (index); if (hFont != -1) OS.SelectObject (hDC, hFont); if (ignoreCustomDraw || nmcd.left == nmcd.right) { return new LRESULT (hFont == -1 ? OS.CDRF_DODEFAULT : OS.CDRF_NEWFONT); } RECT clipRect = null; if (columnCount != 0) { clipRect = new RECT (); HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); OS.SetRect (clipRect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom); } int clrText = -1, clrTextBk = -1; if (OS.IsWindowEnabled (handle)) { clrText = item.cellForeground != null ? item.cellForeground [index] : -1; if (clrText == -1) clrText = item.foreground; clrTextBk = item.cellBackground != null ? item.cellBackground [index] : -1; if (clrTextBk == -1) clrTextBk = item.background; } int clrSortBk = -1; if (OS.IsAppThemed ()) { if (sortColumn != null && sortDirection != SWT.NONE) { if (findImageControl () == null) { if (indexOf (sortColumn) == index) { clrSortBk = getSortColumnPixel (); if (clrTextBk == -1) clrTextBk = clrSortBk; } } } } boolean selected = isItemSelected (nmcd); boolean hot = explorerTheme && (nmcd.uItemState & OS.CDIS_HOT) != 0; boolean focused = explorerTheme && (nmcd.uItemState & OS.CDIS_FOCUS) != 0; if (OS.IsWindowVisible (handle) && nmcd.left < nmcd.right && nmcd.top < nmcd.bottom) { if (hFont != -1) OS.SelectObject (hDC, hFont); if (linesVisible) { RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM); } //TODO - BUG - measure and erase sent when first column is clipped Event measureEvent = null; Rectangle boundsInPixels = null; if (hooks (SWT.MeasureItem)) { measureEvent = sendMeasureItemEvent (item, index, hDC, selected ? SWT.SELECTED : 0); boundsInPixels = measureEvent.getBoundsInPixels (); if (isDisposed () || item.isDisposed ()) return null; } selectionForeground = -1; ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = ignoreFullSelection = false; if (hooks (SWT.EraseItem)) { RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); RECT cellRect = item.getBounds (index, true, true, true, true, true, hDC); if (clrSortBk != -1) { drawBackground (hDC, cellRect, clrSortBk, 0, 0); } else { if (OS.IsWindowEnabled (handle) || findImageControl () != null) { drawBackground (hDC, rect); } else { fillBackground (hDC, OS.GetBkColor (hDC), rect); } } int nSavedDC = OS.SaveDC (hDC); GCData data = new GCData (); data.device = display; if (selected && explorerTheme) { data.foreground = OS.GetSysColor (OS.COLOR_WINDOWTEXT); } else { data.foreground = OS.GetTextColor (hDC); } data.background = OS.GetBkColor (hDC); if (!selected) { if (clrText != -1) data.foreground = clrText; if (clrTextBk != -1) data.background = clrTextBk; } data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); data.font = item.getFont (index); GC gc = GC.win32_new (hDC, data); Event event = new Event (); event.index = index; event.item = item; event.gc = gc; event.detail |= SWT.FOREGROUND; if (clrTextBk != -1) event.detail |= SWT.BACKGROUND; if (hot) event.detail |= SWT.HOT; if (selected) event.detail |= SWT.SELECTED; //if ((nmcd.uItemState & OS.CDIS_FOCUS) != 0) { if (OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0) == nmcd.dwItemSpec) { if (handle == OS.GetFocus ()) { int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); if ((uiState & OS.UISF_HIDEFOCUS) == 0) { if (!explorerTheme || !selected) { focused = true; event.detail |= SWT.FOCUSED; } } } } Rectangle boundsInPixels2 = new Rectangle (cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top); event.setBoundsInPixels (boundsInPixels2); gc.setClipping (DPIUtil.autoScaleDown (boundsInPixels2)); sendEvent (SWT.EraseItem, event); event.gc = null; int newTextClr = data.foreground; gc.dispose (); OS.RestoreDC (hDC, nSavedDC); if (isDisposed () || item.isDisposed ()) return null; if (event.doit) { ignoreDrawForeground = (event.detail & SWT.FOREGROUND) == 0; ignoreDrawBackground = (event.detail & SWT.BACKGROUND) == 0; ignoreDrawSelection = (event.detail & SWT.SELECTED) == 0; ignoreDrawFocus = (event.detail & SWT.FOCUSED) == 0; ignoreDrawHot = (event.detail & SWT.HOT) == 0; } else { ignoreDrawForeground = ignoreDrawBackground = ignoreDrawSelection = ignoreDrawFocus = ignoreDrawHot = true; } if (selected && ignoreDrawSelection) ignoreDrawHot = true; if (!ignoreDrawBackground && clrTextBk != -1) { boolean draw = !selected && !hot; if (!explorerTheme && selected) draw = !ignoreDrawSelection; if (draw) { if (columnCount == 0) { if ((style & SWT.FULL_SELECTION) != 0) { fillBackground (hDC, clrTextBk, rect); } else { RECT textRect = item.getBounds (index, true, false, false, false, true, hDC); if (measureEvent != null) { textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width); } fillBackground (hDC, clrTextBk, textRect); } } else { fillBackground (hDC, clrTextBk, cellRect); } } } if (ignoreDrawSelection) ignoreFullSelection = true; if (!ignoreDrawSelection || !ignoreDrawHot) { if (!selected && !hot) { selectionForeground = clrText = OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT); } if (explorerTheme) { if ((style & SWT.FULL_SELECTION) == 0) { RECT pRect = item.getBounds (index, true, true, false, false, false, hDC); RECT pClipRect = item.getBounds (index, true, true, true, false, true, hDC); if (measureEvent != null) { pRect.right = Math.min (pClipRect.right, boundsInPixels.x + boundsInPixels.width); } else { pRect.right += EXPLORER_EXTRA; pClipRect.right += EXPLORER_EXTRA; } pRect.left -= EXPLORER_EXTRA; pClipRect.left -= EXPLORER_EXTRA; long hTheme = OS.OpenThemeData (handle, Display.TREEVIEW); int iStateId = selected ? OS.TREIS_SELECTED : OS.TREIS_HOT; if (OS.GetFocus () != handle && selected && !hot) iStateId = OS.TREIS_SELECTEDNOTFOCUS; OS.DrawThemeBackground (hTheme, hDC, OS.TVP_TREEITEM, iStateId, pRect, pClipRect); OS.CloseThemeData (hTheme); } } else { /* * Feature in Windows. When the tree has the style * TVS_FULLROWSELECT, the background color for the * entire row is filled when an item is painted, * drawing on top of any custom drawing. The fix * is to emulate TVS_FULLROWSELECT. */ if ((style & SWT.FULL_SELECTION) != 0) { if ((style & SWT.FULL_SELECTION) != 0 && columnCount == 0) { fillBackground (hDC, OS.GetBkColor (hDC), rect); } else { fillBackground (hDC, OS.GetBkColor (hDC), cellRect); } } else { RECT textRect = item.getBounds (index, true, false, false, false, true, hDC); if (measureEvent != null) { textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width); } fillBackground (hDC, OS.GetBkColor (hDC), textRect); } } } else { if (selected || hot) { selectionForeground = clrText = newTextClr; ignoreDrawSelection = ignoreDrawHot = true; } if (explorerTheme) { nmcd.uItemState |= OS.CDIS_DISABLED; /* * Feature in Windows. On Vista only, when the text * color is unchanged and an item is asked to draw * disabled, it uses the disabled color. The fix is * to modify the color so that is it no longer equal. */ int newColor = clrText == -1 ? getForegroundPixel () : clrText; if (nmcd.clrText == newColor) { nmcd.clrText |= 0x20000000; if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000; } else { nmcd.clrText = newColor; } OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); } } if (focused && !ignoreDrawFocus && (style & SWT.FULL_SELECTION) == 0) { RECT textRect = item.getBounds (index, true, explorerTheme, false, false, true, hDC); if (measureEvent != null) { textRect.right = Math.min (cellRect.right, boundsInPixels.x + boundsInPixels.width); } nmcd.uItemState &= ~OS.CDIS_FOCUS; OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); focusRect = textRect; } if (explorerTheme) { if (selected || (hot && ignoreDrawHot)) nmcd.uItemState &= ~OS.CDIS_HOT; OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); } RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC); OS.SaveDC (hDC); OS.SelectClipRgn (hDC, 0); if (explorerTheme) { itemRect.left -= EXPLORER_EXTRA; itemRect.right += EXPLORER_EXTRA; } //TODO - bug in Windows selection or SWT itemRect /*if (selected)*/ itemRect.right++; if (linesVisible) itemRect.bottom++; if (clipRect != null) { OS.IntersectClipRect (hDC, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); } OS.ExcludeClipRect (hDC, itemRect.left, itemRect.top, itemRect.right, itemRect.bottom); return new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT); } /* * Feature in Windows. When the tree has the style * TVS_FULLROWSELECT, the background color for the * entire row is filled when an item is painted, * drawing on top of any custom drawing. The fix * is to emulate TVS_FULLROWSELECT. */ if ((style & SWT.FULL_SELECTION) != 0) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & OS.TVS_FULLROWSELECT) == 0) { RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); if (selected) { fillBackground (hDC, OS.GetBkColor (hDC), rect); } else { if (OS.IsWindowEnabled (handle)) drawBackground (hDC, rect); } nmcd.uItemState &= ~OS.CDIS_FOCUS; OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); } } } LRESULT result = null; if (clrText == -1 && clrTextBk == -1 && hFont == -1) { result = new LRESULT (OS.CDRF_DODEFAULT | OS.CDRF_NOTIFYPOSTPAINT); } else { result = new LRESULT (OS.CDRF_NEWFONT | OS.CDRF_NOTIFYPOSTPAINT); if (hFont != -1) OS.SelectObject (hDC, hFont); if (OS.IsWindowEnabled (handle) && OS.IsWindowVisible (handle)) { /* * Feature in Windows. Windows does not fill the entire cell * with the background color when TVS_FULLROWSELECT is not set. * The fix is to fill the cell with the background color. */ if (clrTextBk != -1) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & OS.TVS_FULLROWSELECT) == 0) { if (columnCount != 0 && hwndHeader != 0) { RECT rect = new RECT (); HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom); if (!OS.IsAppThemed ()) { RECT itemRect = new RECT (); if (OS.TreeView_GetItemRect (handle, item.handle, itemRect, true)) { rect.left = Math.min (itemRect.left, rect.right); } } if ((style & SWT.FULL_SELECTION) != 0) { if (!selected) fillBackground (hDC, clrTextBk, rect); } else { fillBackground (hDC, clrTextBk, rect); } } else { if ((style & SWT.FULL_SELECTION) != 0) { RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); if (!selected) fillBackground (hDC, clrTextBk, rect); } } } } if (!selected) { nmcd.clrText = clrText == -1 ? getForegroundPixel () : clrText; nmcd.clrTextBk = clrTextBk == -1 ? getBackgroundPixel () : clrTextBk; OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); } } } if (OS.IsWindowEnabled (handle)) { /* * On Vista only, when an item is asked to draw disabled, * the background of the text is not filled with the * background color of the tree. This is true for both * regular and full selection trees. In order to draw a * background image, mark the item as disabled using * CDIS_DISABLED (when not selected) and set the text * to the regular text color to avoid drawing disabled. */ if (explorerTheme) { if (findImageControl () != null) { if (!selected && (nmcd.uItemState & (OS.CDIS_HOT | OS.CDIS_SELECTED)) == 0) { nmcd.uItemState |= OS.CDIS_DISABLED; /* * Feature in Windows. On Vista only, when the text * color is unchanged and an item is asked to draw * disabled, it uses the disabled color. The fix is * to modify the color so it is no longer equal. */ int newColor = clrText == -1 ? getForegroundPixel () : clrText; if (nmcd.clrText == newColor) { nmcd.clrText |= 0x20000000; if (nmcd.clrText == newColor) nmcd.clrText &= ~0x20000000; } else { nmcd.clrText = newColor; } OS.MoveMemory (lParam, nmcd, NMTVCUSTOMDRAW.sizeof); if (clrTextBk != -1) { if ((style & SWT.FULL_SELECTION) != 0) { RECT rect = new RECT (); if (columnCount != 0) { HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom); } else { OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); } fillBackground (hDC, clrTextBk, rect); } else { RECT textRect = item.getBounds (index, true, false, true, false, true, hDC); fillBackground (hDC, clrTextBk, textRect); } } } } } } else { /* * Feature in Windows. When the tree is disabled, it draws * with a gray background over the sort column. The fix is * to fill the background with the sort column color. */ if (clrSortBk != -1) { RECT rect = new RECT (); HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; OS.SendMessage (hwndHeader, OS.HDM_GETITEM, index, hdItem); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.left + hdItem.cxy, nmcd.bottom); fillBackground (hDC, clrSortBk, rect); } } OS.SaveDC (hDC); if (clipRect != null) { long hRgn = OS.CreateRectRgn (clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); POINT lpPoint = new POINT (); OS.GetWindowOrgEx (hDC, lpPoint); OS.OffsetRgn (hRgn, -lpPoint.x, -lpPoint.y); OS.SelectClipRgn (hDC, hRgn); OS.DeleteObject (hRgn); } return result; } LRESULT CDDS_POSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) { if (ignoreCustomDraw) return null; if (OS.IsWindowVisible (handle)) { if (OS.IsAppThemed ()) { if (sortColumn != null && sortDirection != SWT.NONE) { if (findImageControl () == null) { int index = indexOf (sortColumn); if (index != -1) { int top = nmcd.top; /* * Bug in Windows. For some reason, during a collapse, * when TVM_GETNEXTITEM is sent with TVGN_LASTVISIBLE * and the collapse causes the item being collapsed * to become the last visible item in the tree, the * message takes a long time to process. In order for * the slowness to happen, the children of the item * must have children. Times of up to 11 seconds have * been observed with 23 children, each having one * child. The fix is to use the bottom partially * visible item rather than the last possible item * that could be visible. * * NOTE: This problem only happens on Vista during * WM_NOTIFY with NM_CUSTOMDRAW and CDDS_POSTPAINT. */ long hItem = 0; if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) { hItem = getBottomItem (); } else { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0); } if (hItem != 0) { RECT rect = new RECT (); if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) { top = rect.bottom; } } RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, top, nmcd.right, nmcd.bottom); RECT headerRect = new RECT (); OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect); rect.left = headerRect.left; rect.right = headerRect.right; fillBackground (nmcd.hdc, getSortColumnPixel (), rect); } } } } if (linesVisible) { long hDC = nmcd.hdc; if (hwndHeader != 0) { int x = 0; RECT rect = new RECT (); HDITEM hdItem = new HDITEM (); hdItem.mask = OS.HDI_WIDTH; for (int i=0; i= OS.VERSION (6, 0)) { hItem = getBottomItem (); } else { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_LASTVISIBLE, 0); } if (hItem != 0) { if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) { height = rect.bottom - rect.top; } } if (height == 0) { height = (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0); OS.GetClientRect (handle, rect); OS.SetRect (rect, rect.left, rect.top, rect.right, rect.top + height); OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM); } if (height != 0) { while (rect.bottom < nmcd.bottom) { int top = rect.top + height; OS.SetRect (rect, rect.left, top, rect.right, top + height); OS.DrawEdge (hDC, rect, OS.BDR_SUNKENINNER, OS.BF_BOTTOM); } } } } return new LRESULT (OS.CDRF_DODEFAULT); } LRESULT CDDS_PREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) { if (explorerTheme) { if ((OS.IsWindowEnabled (handle) && hooks (SWT.EraseItem)) || hasCustomBackground() || findImageControl () != null) { RECT rect = new RECT (); OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom); drawBackground (nmcd.hdc, rect); } } return new LRESULT (OS.CDRF_NOTIFYITEMDRAW | OS.CDRF_NOTIFYPOSTPAINT); } @Override long callWindowProc (long hwnd, int msg, long wParam, long lParam) { if (handle == 0) return 0; if (hwndParent != 0 && hwnd == hwndParent) { return OS.DefWindowProc (hwnd, msg, wParam, lParam); } if (hwndHeader != 0 && hwnd == hwndHeader) { return OS.CallWindowProc (HeaderProc, hwnd, msg, wParam, lParam); } switch (msg) { case OS.WM_SETFOCUS: { /* * Feature in Windows. When a tree control processes WM_SETFOCUS, * if no item is selected, the first item in the tree is selected. * This is unexpected and might clear the previous selection. * The fix is to detect that there is no selection and set it to * the first visible item in the tree. If the item was not selected, * only the focus is assigned. */ if ((style & SWT.SINGLE) != 0) break; long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem == 0) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); if (hItem != 0) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); hSelect = hItem; ignoreDeselect = ignoreSelect = lockSelection = true; OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hItem); ignoreDeselect = ignoreSelect = lockSelection = false; hSelect = 0; if ((tvItem.state & OS.TVIS_SELECTED) == 0) { OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); } } } break; } } long hItem = 0; boolean redraw = false; switch (msg) { /* Keyboard messages */ case OS.WM_KEYDOWN: if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break; //FALL THROUGH case OS.WM_CHAR: case OS.WM_IME_CHAR: case OS.WM_KEYUP: case OS.WM_SYSCHAR: case OS.WM_SYSKEYDOWN: case OS.WM_SYSKEYUP: //FALL THROUGH /* Scroll messages */ case OS.WM_HSCROLL: case OS.WM_VSCROLL: //FALL THROUGH /* Resize messages */ case OS.WM_SIZE: redraw = findImageControl () != null && getDrawing () && OS.IsWindowVisible (handle); if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); //FALL THROUGH /* Mouse messages */ case OS.WM_LBUTTONDBLCLK: case OS.WM_LBUTTONDOWN: case OS.WM_LBUTTONUP: case OS.WM_MBUTTONDBLCLK: case OS.WM_MBUTTONDOWN: case OS.WM_MBUTTONUP: case OS.WM_MOUSEHOVER: case OS.WM_MOUSELEAVE: case OS.WM_MOUSEMOVE: case OS.WM_MOUSEWHEEL: case OS.WM_RBUTTONDBLCLK: case OS.WM_RBUTTONDOWN: case OS.WM_RBUTTONUP: case OS.WM_XBUTTONDBLCLK: case OS.WM_XBUTTONDOWN: case OS.WM_XBUTTONUP: //FALL THROUGH /* Other messages */ case OS.WM_SETFONT: case OS.WM_TIMER: { if (findImageControl () != null) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); } break; } } long code = OS.CallWindowProc (TreeProc, hwnd, msg, wParam, lParam); switch (msg) { /* Keyboard messages */ case OS.WM_KEYDOWN: if (wParam == OS.VK_CONTROL || wParam == OS.VK_SHIFT) break; //FALL THROUGH case OS.WM_CHAR: case OS.WM_IME_CHAR: case OS.WM_KEYUP: case OS.WM_SYSCHAR: case OS.WM_SYSKEYDOWN: case OS.WM_SYSKEYUP: //FALL THROUGH /* Scroll messages */ case OS.WM_HSCROLL: case OS.WM_VSCROLL: //FALL THROUGH /* Resize messages */ case OS.WM_SIZE: if (redraw) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.InvalidateRect (handle, null, true); if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true); } //FALL THROUGH /* Mouse messages */ case OS.WM_LBUTTONDBLCLK: case OS.WM_LBUTTONDOWN: case OS.WM_LBUTTONUP: case OS.WM_MBUTTONDBLCLK: case OS.WM_MBUTTONDOWN: case OS.WM_MBUTTONUP: case OS.WM_MOUSEHOVER: case OS.WM_MOUSELEAVE: case OS.WM_MOUSEMOVE: case OS.WM_MOUSEWHEEL: case OS.WM_RBUTTONDBLCLK: case OS.WM_RBUTTONDOWN: case OS.WM_RBUTTONUP: case OS.WM_XBUTTONDBLCLK: case OS.WM_XBUTTONDOWN: case OS.WM_XBUTTONUP: //FALL THROUGH /* Other messages */ case OS.WM_SETFONT: case OS.WM_TIMER: { if (findImageControl () != null) { if (hItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) { OS.InvalidateRect (handle, null, true); } } updateScrollBar (); break; } case OS.WM_PAINT: painted = true; break; } return code; } @Override void checkBuffered () { super.checkBuffered (); if ((style & SWT.VIRTUAL) != 0) { style |= SWT.DOUBLE_BUFFERED; OS.SendMessage (handle, OS.TVM_SETSCROLLTIME, 0, 0); } if (OS.IsAppThemed ()) { int exStyle = (int)OS.SendMessage (handle, OS.TVM_GETEXTENDEDSTYLE, 0, 0); if ((exStyle & OS.TVS_EX_DOUBLEBUFFER) != 0) style |= SWT.DOUBLE_BUFFERED; } } boolean checkData (TreeItem item, boolean redraw) { if ((style & SWT.VIRTUAL) == 0) return true; if (!item.cached) { TreeItem parentItem = item.getParentItem (); return checkData (item, parentItem == null ? indexOf (item) : parentItem.indexOf (item), redraw); } return true; } boolean checkData (TreeItem item, int index, boolean redraw) { if ((style & SWT.VIRTUAL) == 0) return true; if (!item.cached) { item.cached = true; Event event = new Event (); event.item = item; event.index = index; TreeItem oldItem = currentItem; currentItem = item; /* * Bug in Windows. If the tree scrolls during WM_NOTIFY * with TVN_GETDISPINFO, pixel corruption occurs. The fix * is to detect that the top item has changed and redraw * the entire tree. */ long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); sendEvent (SWT.SetData, event); //widget could be disposed at this point currentItem = oldItem; if (isDisposed () || item.isDisposed ()) return false; if (redraw) item.redraw (); if (hTopItem != OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0)) { OS.InvalidateRect (handle, null, true); } } return true; } @Override boolean checkHandle (long hwnd) { return hwnd == handle || (hwndParent != 0 && hwnd == hwndParent) || (hwndHeader != 0 && hwnd == hwndHeader); } boolean checkScroll (long hItem) { /* * Feature in Windows. If redraw is turned off using WM_SETREDRAW * and a tree item that is not a child of the first root is selected or * scrolled using TVM_SELECTITEM or TVM_ENSUREVISIBLE, then scrolling * does not occur. The fix is to detect this case, and make sure * that redraw is temporarily enabled. To avoid flashing, DefWindowProc() * is called to disable redrawing. * * NOTE: The code that actually works around the problem is in the * callers of this method. */ if (getDrawing ()) return false; long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem); while (hParent != hRoot && hParent != 0) { hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hParent); } return hParent == 0; } @Override protected void checkSubclass () { if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); } /** * Clears the item at the given zero-relative index in the receiver. * The text, icon and other attributes of the item are set to the default * value. If the tree was created with the SWT.VIRTUAL style, * these attributes are requested again as needed. * * @param index the index of the item to clear * @param all true if all child items of the indexed item should be * cleared recursively, and false otherwise * * @exception IllegalArgumentException
    *
  • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
  • *
* @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
* * @see SWT#VIRTUAL * @see SWT#SetData * * @since 3.2 */ public void clear (int index, boolean all) { checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); if (hItem == 0) error (SWT.ERROR_INVALID_RANGE); hItem = findItem (hItem, index); if (hItem == 0) error (SWT.ERROR_INVALID_RANGE); TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; clear (hItem, tvItem); if (all) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem); clearAll (hItem, tvItem, all); } } void clear (long hItem, TVITEM tvItem) { tvItem.hItem = hItem; TreeItem item = null; if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) { item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null; } if (item != null) { if ((style & SWT.VIRTUAL) != 0 && !item.cached) return; item.clear (); item.redraw (); } } /** * Clears all the items in the receiver. The text, icon and other * attributes of the items are set to their default values. If the * tree was created with the SWT.VIRTUAL style, these * attributes are requested again as needed. * * @param all true if all child items should be cleared * recursively, and false otherwise * * @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
* * @see SWT#VIRTUAL * @see SWT#SetData * * @since 3.2 */ public void clearAll (boolean all) { checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); if (hItem == 0) return; if (all) { boolean redraw = false; for (int i=0; i *
  • ERROR_NULL_ARGUMENT - if the item is null
  • *
  • ERROR_INVALID_ARGUMENT - if the item has been disposed
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.4 */ public void deselect (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.stateMask = OS.TVIS_SELECTED; tvItem.hItem = item.handle; OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); } /** * Deselects all selected items in the receiver. * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void deselectAll () { checkWidget (); TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.stateMask = OS.TVIS_SELECTED; if ((style & SWT.SINGLE) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem != 0) { tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); } } else { long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); if ((style & SWT.VIRTUAL) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); deselect (hItem, tvItem, 0); } else { for (int i=0; i rect.right) { quit = true; } else { cellRect [0].right = Math.min (cellRect [0].right, rect.right); if (OS.PtInRect (cellRect [0], pt)) { if (isCustomToolTip ()) { int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, lpht.hItem, OS.TVIS_SELECTED); int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0; Event event = sendMeasureItemEvent (item [0], order [index [0]], hDC, detail); if (isDisposed () || item [0].isDisposed ()) break; Rectangle boundsInPixels = event.getBoundsInPixels(); itemRect [0] = new RECT (); itemRect [0].left = boundsInPixels.x; itemRect [0].right = boundsInPixels.x + boundsInPixels.width; itemRect [0].top = boundsInPixels.y; itemRect [0].bottom = boundsInPixels.y + boundsInPixels.height; } else { itemRect [0] = item [0].getBounds (order [index [0]], true, false, false, false, false, hDC); } if (itemRect [0].right > cellRect [0].right) found = true; quit = true; } } if (hFont != -1) OS.SelectObject (hDC, hFont); if (!found) index [0]++; } if (newFont != 0) OS.SelectObject (hDC, oldFont); OS.ReleaseDC (handle, hDC); } return found; } int findIndex (long hFirstItem, long hItem) { if (hFirstItem == 0) return -1; if (hFirstItem == hFirstIndexOf) { if (hFirstIndexOf == hItem) { hLastIndexOf = hFirstIndexOf; return lastIndexOf = 0; } if (hLastIndexOf == hItem) return lastIndexOf; long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf); if (hPrevItem == hItem) { hLastIndexOf = hPrevItem; return --lastIndexOf; } long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf); if (hNextItem == hItem) { hLastIndexOf = hNextItem; return ++lastIndexOf; } int previousIndex = lastIndexOf - 1; while (hPrevItem != 0 && hPrevItem != hItem) { hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem); --previousIndex; } if (hPrevItem == hItem) { hLastIndexOf = hPrevItem; return lastIndexOf = previousIndex; } int nextIndex = lastIndexOf + 1; while (hNextItem != 0 && hNextItem != hItem) { hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem); nextIndex++; } if (hNextItem == hItem) { hLastIndexOf = hNextItem; return lastIndexOf = nextIndex; } return -1; } int index = 0; long hNextItem = hFirstItem; while (hNextItem != 0 && hNextItem != hItem) { hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem); index++; } if (hNextItem == hItem) { itemCount = -1; hFirstIndexOf = hFirstItem; hLastIndexOf = hNextItem; return lastIndexOf = index; } return -1; } @Override Widget findItem (long hItem) { return _getItem (hItem); } long findItem (long hFirstItem, int index) { if (hFirstItem == 0) return 0; if (hFirstItem == hFirstIndexOf) { if (index == 0) { lastIndexOf = 0; return hLastIndexOf = hFirstIndexOf; } if (lastIndexOf == index) return hLastIndexOf; if (lastIndexOf - 1 == index) { --lastIndexOf; return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf); } if (lastIndexOf + 1 == index) { lastIndexOf++; return hLastIndexOf = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf); } if (index < lastIndexOf) { int previousIndex = lastIndexOf - 1; long hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hLastIndexOf); while (hPrevItem != 0 && index < previousIndex) { hPrevItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PREVIOUS, hPrevItem); --previousIndex; } if (index == previousIndex) { lastIndexOf = previousIndex; return hLastIndexOf = hPrevItem; } } else { int nextIndex = lastIndexOf + 1; long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hLastIndexOf); while (hNextItem != 0 && nextIndex < index) { hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem); nextIndex++; } if (index == nextIndex) { lastIndexOf = nextIndex; return hLastIndexOf = hNextItem; } } return 0; } int nextIndex = 0; long hNextItem = hFirstItem; while (hNextItem != 0 && nextIndex < index) { hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hNextItem); nextIndex++; } if (index == nextIndex) { itemCount = -1; lastIndexOf = nextIndex; hFirstIndexOf = hFirstItem; return hLastIndexOf = hNextItem; } return 0; } TreeItem getFocusItem () { // checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); return hItem != 0 ? _getItem (hItem) : null; } /** * Returns the width in points of a grid line. * * @return the width of a grid line in points * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public int getGridLineWidth () { checkWidget (); return DPIUtil.autoScaleDown(getGridLineWidthInPixels ()); } int getGridLineWidthInPixels () { return GRID_WIDTH; } /** * Returns the header background color. * * @return the receiver's header background color. * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @since 3.106 */ public Color getHeaderBackground () { checkWidget (); return Color.win32_new (display, getHeaderBackgroundPixel()); } private int getHeaderBackgroundPixel() { return headerBackground != -1 ? headerBackground : defaultBackground(); } /** * Returns the header foreground color. * * @return the receiver's header foreground color. * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @since 3.106 */ public Color getHeaderForeground () { checkWidget (); return Color.win32_new (display, getHeaderForegroundPixel()); } private int getHeaderForegroundPixel() { return headerForeground != -1 ? headerForeground : defaultForeground(); } /** * Returns the height of the receiver's header * * @return the height of the header or zero if the header is not visible * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public int getHeaderHeight () { checkWidget (); return DPIUtil.autoScaleDown(getHeaderHeightInPixels ()); } int getHeaderHeightInPixels () { if (hwndHeader == 0) return 0; RECT rect = new RECT (); OS.GetWindowRect (hwndHeader, rect); return rect.bottom - rect.top; } /** * Returns true if the receiver's header is visible, * and false otherwise. *

    * If one of the receiver's ancestors is not visible or some * other condition makes the receiver not visible, this method * may still indicate that it is considered visible even though * it may not actually be showing. *

    * * @return the receiver's header's visibility state * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public boolean getHeaderVisible () { checkWidget (); if (hwndHeader == 0) return false; int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE); return (bits & OS.WS_VISIBLE) != 0; } Point getImageSize () { if (imageList != null) return imageList.getImageSize (); return new Point (0, getItemHeightInPixels ()); } long getBottomItem () { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); if (hItem == 0) return 0; int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0); while (index <= count) { long hNextItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem); if (hNextItem == 0) return hItem; hItem = hNextItem; index++; } return hItem; } /** * Returns the column at the given, zero-relative index in the * receiver. Throws an exception if the index is out of range. * Columns are returned in the order that they were created. * If no TreeColumns were created by the programmer, * this method will throw ERROR_INVALID_RANGE despite * the fact that a single column of data may be visible in the tree. * This occurs when the programmer uses the tree like a list, adding * items but never creating a column. * * @param index the index of the column to return * @return the column at the given index * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#getColumnOrder() * @see Tree#setColumnOrder(int[]) * @see TreeColumn#getMoveable() * @see TreeColumn#setMoveable(boolean) * @see SWT#Move * * @since 3.1 */ public TreeColumn getColumn (int index) { checkWidget (); if (!(0 <= index && index < columnCount)) error (SWT.ERROR_INVALID_RANGE); return columns [index]; } /** * Returns the number of columns contained in the receiver. * If no TreeColumns were created by the programmer, * this value is zero, despite the fact that visually, one column * of items may be visible. This occurs when the programmer uses * the tree like a list, adding items but never creating a column. * * @return the number of columns * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public int getColumnCount () { checkWidget (); return columnCount; } /** * Returns an array of zero-relative integers that map * the creation order of the receiver's items to the * order in which they are currently being displayed. *

    * Specifically, the indices of the returned array represent * the current visual order of the items, and the contents * of the array represent the creation order of the items. *

    * Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. *

    * * @return the current visual order of the receiver's items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#setColumnOrder(int[]) * @see TreeColumn#getMoveable() * @see TreeColumn#setMoveable(boolean) * @see SWT#Move * * @since 3.2 */ public int[] getColumnOrder () { checkWidget (); if (columnCount == 0) return new int [0]; int [] order = new int [columnCount]; OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, order); return order; } /** * Returns an array of TreeColumns which are the * columns in the receiver. Columns are returned in the order * that they were created. If no TreeColumns were * created by the programmer, the array is empty, despite the fact * that visually, one column of items may be visible. This occurs * when the programmer uses the tree like a list, adding items but * never creating a column. *

    * Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. *

    * * @return the items in the receiver * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#getColumnOrder() * @see Tree#setColumnOrder(int[]) * @see TreeColumn#getMoveable() * @see TreeColumn#setMoveable(boolean) * @see SWT#Move * * @since 3.1 */ public TreeColumn [] getColumns () { checkWidget (); TreeColumn [] result = new TreeColumn [columnCount]; System.arraycopy (columns, 0, result, 0, columnCount); return result; } /** * Returns the item at the given, zero-relative index in the * receiver. Throws an exception if the index is out of range. * * @param index the index of the item to return * @return the item at the given index * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public TreeItem getItem (int index) { checkWidget (); if (index < 0) error (SWT.ERROR_INVALID_RANGE); long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); if (hFirstItem == 0) error (SWT.ERROR_INVALID_RANGE); long hItem = findItem (hFirstItem, index); if (hItem == 0) error (SWT.ERROR_INVALID_RANGE); return _getItem (hItem); } TreeItem getItem (NMTVCUSTOMDRAW nmcd) { /* * Bug in Windows. If the lParam field of TVITEM * is changed during custom draw using TVM_SETITEM, * the lItemlParam field of the NMTVCUSTOMDRAW struct * is not updated until the next custom draw. The * fix is to query the field from the item instead * of using the struct. */ int id = (int)nmcd.lItemlParam; if ((style & SWT.VIRTUAL) != 0) { if (id == -1) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; tvItem.hItem = nmcd.dwItemSpec; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); id = (int)tvItem.lParam; } } return _getItem (nmcd.dwItemSpec, id); } /** * Returns the item at the given point in the receiver * or null if no such item exists. The point is in the * coordinate system of the receiver. *

    * The item that is returned represents an item that could be selected by the user. * For example, if selection only occurs in items in the first column, then null is * returned if the point is outside of the item. * Note that the SWT.FULL_SELECTION style hint, which specifies the selection policy, * determines the extent of the selection. *

    * * @param point the point used to locate the item * @return the item at the given point, or null if the point is not in a selectable item * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the point is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public TreeItem getItem (Point point) { checkWidget (); if (point == null) error (SWT.ERROR_NULL_ARGUMENT); return getItemInPixels(DPIUtil.autoScaleUp(point)); } TreeItem getItemInPixels (Point point) { TVHITTESTINFO lpht = new TVHITTESTINFO (); lpht.x = point.x; lpht.y = point.y; OS.SendMessage (handle, OS.TVM_HITTEST, 0, lpht); if (lpht.hItem != 0) { int flags = OS.TVHT_ONITEM; if ((style & SWT.FULL_SELECTION) != 0) { flags |= OS.TVHT_ONITEMRIGHT | OS.TVHT_ONITEMINDENT; } else { if (hooks (SWT.MeasureItem)) { lpht.flags &= ~(OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL); if (hitTestSelection (lpht.hItem, lpht.x, lpht.y)) { lpht.flags |= OS.TVHT_ONITEMICON | OS.TVHT_ONITEMLABEL; } } } if ((lpht.flags & flags) != 0) return _getItem (lpht.hItem); } return null; } /** * Returns the number of items contained in the receiver * that are direct item children of the receiver. The * number that is returned is the number of roots in the * tree. * * @return the number of items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public int getItemCount () { checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); if (hItem == 0) return 0; return getItemCount (hItem); } int getItemCount (long hItem) { int count = 0; long hFirstItem = hItem; if (hItem == hFirstIndexOf) { if (itemCount != -1) return itemCount; hFirstItem = hLastIndexOf; count = lastIndexOf; } while (hFirstItem != 0) { hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hFirstItem); count++; } if (hItem == hFirstIndexOf) itemCount = count; return count; } /** * Returns the height of the area which would be used to * display one of the items in the tree. * * @return the height of one item * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public int getItemHeight () { checkWidget (); return DPIUtil.autoScaleDown(getItemHeightInPixels()); } int getItemHeightInPixels () { return (int)OS.SendMessage (handle, OS.TVM_GETITEMHEIGHT, 0, 0); } /** * Returns a (possibly empty) array of items contained in the * receiver that are direct item children of the receiver. These * are the roots of the tree. *

    * Note: This is not the actual structure used by the receiver * to maintain its list of items, so modifying the array will * not affect the receiver. *

    * * @return the items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public TreeItem [] getItems () { checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); if (hItem == 0) return new TreeItem [0]; return getItems (hItem); } TreeItem [] getItems (long hTreeItem) { int count = 0; long hItem = hTreeItem; while (hItem != 0) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); count++; } int index = 0; TreeItem [] result = new TreeItem [count]; TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; tvItem.hItem = hTreeItem; /* * Feature in Windows. In some cases an expand or collapse message * can occur from within TVM_DELETEITEM. When this happens, the item * being destroyed has been removed from the list of items but has not * been deleted from the tree. The fix is to check for null items and * remove them from the list. */ while (tvItem.hItem != 0) { OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam); if (item != null) result [index++] = item; tvItem.hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, tvItem.hItem); } if (index != count) { TreeItem [] newResult = new TreeItem [index]; System.arraycopy (result, 0, newResult, 0, index); result = newResult; } return result; } /** * Returns true if the receiver's lines are visible, * and false otherwise. Note that some platforms draw * grid lines while others may draw alternating row colors. *

    * If one of the receiver's ancestors is not visible or some * other condition makes the receiver not visible, this method * may still indicate that it is considered visible even though * it may not actually be showing. *

    * * @return the visibility state of the lines * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public boolean getLinesVisible () { checkWidget (); return linesVisible; } long getNextSelection (long hItem) { while (hItem != 0) { int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); if ((state & OS.TVIS_SELECTED) != 0) return hItem; long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem); long hSelected = getNextSelection (hFirstItem); if (hSelected != 0) return hSelected; hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); } return 0; } /** * Returns the receiver's parent item, which must be a * TreeItem or null when the receiver is a * root. * * @return the receiver's parent item * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public TreeItem getParentItem () { checkWidget (); return null; } int getSelection (long hItem, TVITEM tvItem, TreeItem [] selection, int index, int count, boolean bigSelection, boolean all) { while (hItem != 0) { boolean expanded = true; if (bigSelection) { tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); if ((tvItem.state & OS.TVIS_SELECTED) != 0) { if (selection != null && index < selection.length) { TreeItem item = _getItem (hItem, (int)tvItem.lParam); if (item != null) { selection [index] = item; } else { index--; } } index++; } expanded = (tvItem.state & OS.TVIS_EXPANDED) != 0; } else { int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED | OS.TVIS_EXPANDED); if ((state & OS.TVIS_SELECTED) != 0) { if (tvItem != null && selection != null && index < selection.length) { tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); TreeItem item = _getItem (hItem, (int)tvItem.lParam); if (item != null) { selection [index] = item; } else { index--; } } index++; } expanded = (state & OS.TVIS_EXPANDED) != 0; } if (index == count) break; if (all) { if (expanded) { long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem); if ((index = getSelection (hFirstItem, tvItem, selection, index, count, bigSelection, all)) == count) { break; } } hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); } else { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem); } } return index; } /** * Returns an array of TreeItems that are currently * selected in the receiver. The order of the items is unspecified. * An empty array indicates that no items are selected. *

    * Note: This is not the actual structure used by the receiver * to maintain its selection, so modifying the array will * not affect the receiver. *

    * @return an array representing the selection * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public TreeItem [] getSelection () { checkWidget (); if ((style & SWT.SINGLE) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem == 0) return new TreeItem [0]; TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE; tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); if ((tvItem.state & OS.TVIS_SELECTED) == 0) return new TreeItem [0]; TreeItem item = _getItem (tvItem.hItem, (int)tvItem.lParam); if (item == null) return new TreeItem [0]; return new TreeItem [] {item}; } int count = 0; TreeItem [] guess = new TreeItem [(style & SWT.VIRTUAL) != 0 ? 8 : 1]; long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); if ((style & SWT.VIRTUAL) != 0) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM | OS.TVIF_STATE; long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); count = getSelection (hItem, tvItem, guess, 0, -1, false, true); } else { for (int i=0; i itemCount / 2; if (count != getSelection (hItem, tvItem, result, 0, count, bigSelection, false)) { count = getSelection (hItem, tvItem, result, 0, count, bigSelection, true); } if (count != result.length) { TreeItem[] newResult = new TreeItem[count]; System.arraycopy (result, 0, newResult, 0, count); result = newResult; } OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc); return result; } /** * Returns the number of selected items contained in the receiver. * * @return the number of selected items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public int getSelectionCount () { checkWidget (); if ((style & SWT.SINGLE) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem == 0) return 0; int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); return (state & OS.TVIS_SELECTED) == 0 ? 0 : 1; } int count = 0; long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); if ((style & SWT.VIRTUAL) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); count = getSelection (hItem, null, null, 0, -1, false, true); } else { for (int i=0; i *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • * * * @see #setSortColumn(TreeColumn) * * @since 3.2 */ public TreeColumn getSortColumn () { checkWidget (); return sortColumn; } int getSortColumnPixel () { int pixel = OS.IsWindowEnabled (handle) || hasCustomBackground() ? getBackgroundPixel () : OS.GetSysColor (OS.COLOR_3DFACE); return getSlightlyDifferentBackgroundColor(pixel); } /** * Returns the direction of the sort indicator for the receiver. * The value will be one of UP, DOWN * or NONE. * * @return the sort direction * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see #setSortDirection(int) * * @since 3.2 */ public int getSortDirection () { checkWidget (); return sortDirection; } /** * Returns the item which is currently at the top of the receiver. * This item can change when items are expanded, collapsed, scrolled * or new items are added or removed. * * @return the item at the top of the receiver * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 2.1 */ public TreeItem getTopItem () { checkWidget (); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); return hItem != 0 ? _getItem (hItem) : null; } boolean hitTestSelection (long hItem, int x, int y) { if (hItem == 0) return false; TreeItem item = _getItem (hItem); if (item == null) return false; if (!hooks (SWT.MeasureItem)) return false; boolean result = false; //BUG? - moved columns, only hittest first column //BUG? - check drag detect int [] order = new int [1], index = new int [1]; long hDC = OS.GetDC (handle); long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); long hFont = item.fontHandle (order [index [0]]); if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); int detail = (state & OS.TVIS_SELECTED) != 0 ? SWT.SELECTED : 0; Event event = sendMeasureItemEvent (item, order [index [0]], hDC, detail); if (event.getBoundsInPixels ().contains (x, y)) result = true; if (newFont != 0) OS.SelectObject (hDC, oldFont); OS.ReleaseDC (handle, hDC); // if (isDisposed () || item.isDisposed ()) return false; return result; } int imageIndex (Image image, int index) { if (image == null) return OS.I_IMAGENONE; if (imageList == null) { Rectangle bounds = image.getBoundsInPixels (); imageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height); } int imageIndex = imageList.indexOf (image); if (imageIndex == -1) imageIndex = imageList.add (image); if (hwndHeader == 0 || OS.SendMessage (hwndHeader, OS.HDM_ORDERTOINDEX, 0, 0) == index) { /* * Feature in Windows. When setting the same image list multiple * times, Windows does work making this operation slow. The fix * is to test for the same image list before setting the new one. */ long hImageList = imageList.getHandle (); long hOldImageList = OS.SendMessage (handle, OS.TVM_GETIMAGELIST, OS.TVSIL_NORMAL, 0); if (hOldImageList != hImageList) { OS.SendMessage (handle, OS.TVM_SETIMAGELIST, OS.TVSIL_NORMAL, hImageList); updateScrollBar (); } } return imageIndex; } int imageIndexHeader (Image image) { if (image == null) return OS.I_IMAGENONE; if (headerImageList == null) { Rectangle bounds = image.getBoundsInPixels (); headerImageList = display.getImageList (style & SWT.RIGHT_TO_LEFT, bounds.width, bounds.height); int index = headerImageList.indexOf (image); if (index == -1) index = headerImageList.add (image); long hImageList = headerImageList.getHandle (); if (hwndHeader != 0) { OS.SendMessage (hwndHeader, OS.HDM_SETIMAGELIST, 0, hImageList); } updateScrollBar (); return index; } int index = headerImageList.indexOf (image); if (index != -1) return index; return headerImageList.add (image); } /** * Searches the receiver's list starting at the first column * (index 0) until a column is found that is equal to the * argument, and returns the index of that column. If no column * is found, returns -1. * * @param column the search column * @return the index of the column * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the column is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public int indexOf (TreeColumn column) { checkWidget (); if (column == null) error (SWT.ERROR_NULL_ARGUMENT); if (column.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); for (int i=0; i *
  • ERROR_NULL_ARGUMENT - if the item is null
  • *
  • ERROR_INVALID_ARGUMENT - if the item has been disposed
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public int indexOf (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); return hItem == 0 ? -1 : findIndex (hItem, item.handle); } boolean isCustomToolTip () { return hooks (SWT.MeasureItem); } boolean isItemSelected (NMTVCUSTOMDRAW nmcd) { boolean selected = false; if (OS.IsWindowEnabled (handle)) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.hItem = nmcd.dwItemSpec; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); if ((tvItem.state & (OS.TVIS_SELECTED | OS.TVIS_DROPHILITED)) != 0) { selected = true; /* * Feature in Windows. When the mouse is pressed and the * selection is first drawn for a tree, the previously * selected item is redrawn but the the TVIS_SELECTED bits * are not cleared. When the user moves the mouse slightly * and a drag and drop operation is not started, the item is * drawn again and this time with TVIS_SELECTED is cleared. * This means that an item that contains colored cells will * not draw with the correct background until the mouse is * moved. The fix is to test for the selection colors and * guess that the item is not selected. * * NOTE: This code does not work when the foreground and * background of the tree are set to the selection colors * but this does not happen in a regular application. */ if (handle == OS.GetFocus ()) { if (OS.GetTextColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) { selected = false; } else { if (OS.GetBkColor (nmcd.hdc) != OS.GetSysColor (OS.COLOR_HIGHLIGHT)) { selected = false; } } } } else { if (nmcd.dwDrawStage == OS.CDDS_ITEMPOSTPAINT) { /* * Feature in Windows. When the mouse is pressed and the * selection is first drawn for a tree, the item is drawn * selected, but the TVIS_SELECTED bits for the item are * not set. When the user moves the mouse slightly and * a drag and drop operation is not started, the item is * drawn again and this time TVIS_SELECTED is set. This * means that an item that is in a tree that has the style * TVS_FULLROWSELECT and that also contains colored cells * will not draw the entire row selected until the user * moves the mouse. The fix is to test for the selection * colors and guess that the item is selected. * * NOTE: This code does not work when the foreground and * background of the tree are set to the selection colors * but this does not happen in a regular application. */ if (OS.GetTextColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT)) { if (OS.GetBkColor (nmcd.hdc) == OS.GetSysColor (OS.COLOR_HIGHLIGHT)) { selected = true; } } } } } return selected; } void redrawSelection () { if ((style & SWT.SINGLE) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem != 0) { RECT rect = new RECT (); if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) { OS.InvalidateRect (handle, rect, true); } } } else { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); if (hItem != 0) { RECT rect = new RECT (); int index = 0, count = (int)OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0); while (index <= count && hItem != 0) { int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); if ((state & OS.TVIS_SELECTED) != 0) { if (OS.TreeView_GetItemRect (handle, hItem, rect, false)) { OS.InvalidateRect (handle, rect, true); } } hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXTVISIBLE, hItem); index++; } } } } @Override void register () { super.register (); if (hwndParent != 0) display.addControl (hwndParent, this); if (hwndHeader != 0) display.addControl (hwndHeader, this); } void releaseItem (long hItem, TVITEM tvItem, boolean release) { if (hItem == hAnchor) hAnchor = 0; if (hItem == hInsert) hInsert = 0; tvItem.hItem = hItem; if (OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem) != 0) { if (tvItem.lParam != -1) { if (tvItem.lParam < lastID) lastID = (int)tvItem.lParam; if (release) { TreeItem item = items [(int)tvItem.lParam]; if (item != null) item.release (false); } items [(int)tvItem.lParam] = null; } } } void releaseItems (long hItem, TVITEM tvItem) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem); while (hItem != 0) { releaseItems (hItem, tvItem); releaseItem (hItem, tvItem, true); hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); } } @Override void releaseHandle () { super.releaseHandle (); hwndParent = hwndHeader = 0; } @Override void releaseChildren (boolean destroy) { if (items != null) { for (int i=0; i *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • * */ public void removeAll () { checkWidget (); hFirstIndexOf = hLastIndexOf = 0; itemCount = -1; for (int i=0; i *
  • ERROR_NULL_ARGUMENT - if the listener is null
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see SelectionListener * @see #addSelectionListener */ public void removeSelectionListener (SelectionListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); eventTable.unhook (SWT.Selection, listener); eventTable.unhook (SWT.DefaultSelection, listener); } /** * Removes the listener from the collection of listeners who will * be notified when items in the receiver are expanded or collapsed. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the listener is null
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see TreeListener * @see #addTreeListener */ public void removeTreeListener(TreeListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook (SWT.Expand, listener); eventTable.unhook (SWT.Collapse, listener); } @Override void reskinChildren (int flags) { if (items != null) { for (int i=0; i *
  • ERROR_INVALID_ARGUMENT - if the item has been disposed
  • * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void setInsertMark (TreeItem item, boolean before) { checkWidget (); long hItem = 0; if (item != null) { if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); hItem = item.handle; } hInsert = hItem; insertAfter = !before; OS.SendMessage (handle, OS.TVM_SETINSERTMARK, insertAfter ? 1 : 0, hInsert); } /** * Sets the number of root-level items contained in the receiver. * * @param count the number of items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ public void setItemCount (int count) { checkWidget (); count = Math.max (0, count); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); setItemCount (count, OS.TVGN_ROOT, hItem); } void setItemCount (int count, long hParent, long hItem) { boolean redraw = false; if (OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0) == 0) { redraw = getDrawing () && OS.IsWindowVisible (handle); if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } int itemCount = 0; while (hItem != 0 && itemCount < count) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); itemCount++; } boolean expanded = false; TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_PARAM; if (!redraw && (style & SWT.VIRTUAL) != 0) { /* * Bug in Windows. Despite the fact that TVM_GETITEMSTATE claims * to return only the bits specified by the stateMask, when called * with TVIS_EXPANDED, the entire state is returned. The fix is * to explicitly check for the TVIS_EXPANDED bit. */ int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hParent, OS.TVIS_EXPANDED); expanded = (state & OS.TVIS_EXPANDED) != 0; } while (hItem != 0) { tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_GETITEM, 0, tvItem); hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); TreeItem item = tvItem.lParam != -1 ? items [(int)tvItem.lParam] : null; if (item != null && !item.isDisposed ()) { item.dispose (); } else { releaseItem (tvItem.hItem, tvItem, false); destroyItem (null, tvItem.hItem); } } if ((style & SWT.VIRTUAL) != 0) { for (int i=itemCount; ione of the items in the tree. * * @param itemHeight the height of one item * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ /*public*/ void setItemHeight (int itemHeight) { checkWidget (); if (itemHeight < -1) error (SWT.ERROR_INVALID_ARGUMENT); OS.SendMessage (handle, OS.TVM_SETITEMHEIGHT, itemHeight, 0); } /** * Marks the receiver's lines as visible if the argument is true, * and marks it invisible otherwise. Note that some platforms draw * grid lines while others may draw alternating row colors. *

    * If one of the receiver's ancestors is not visible or some * other condition makes the receiver not visible, marking * it visible may not actually cause it to be displayed. *

    * * @param show the new visibility state * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public void setLinesVisible (boolean show) { checkWidget (); if (linesVisible == show) return; linesVisible = show; if (hwndParent == 0 && linesVisible) customDraw = true; OS.InvalidateRect (handle, null, true); if (hwndHeader != 0) OS.InvalidateRect (hwndHeader, null, true); } @Override long scrolledHandle () { if (hwndHeader == 0) return handle; return columnCount == 0 && scrollWidth == 0 ? handle : hwndParent; } void select (long hItem, TVITEM tvItem) { while (hItem != 0) { tvItem.hItem = hItem; OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_EXPANDED); if ((state & OS.TVIS_EXPANDED) != 0) { long hFirstItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CHILD, hItem); select (hFirstItem, tvItem); } hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_NEXT, hItem); } } /** * Selects an item in the receiver. If the item was already * selected, it remains selected. * * @param item the item to be selected * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.4 */ public void select (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); if ((style & SWT.SINGLE) != 0) { long hItem = item.handle; int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); if ((state & OS.TVIS_SELECTED) != 0) return; /* * Feature in Windows. When an item is selected with * TVM_SELECTITEM and TVGN_CARET, the tree expands and * scrolls to show the new selected item. Unfortunately, * there is no other way in Windows to set the focus * and select an item. The fix is to save the current * scroll bar positions, turn off redraw, select the item, * then scroll back to the original position and redraw * the entire tree. */ SCROLLINFO hInfo = null; int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) { hInfo = new SCROLLINFO (); hInfo.cbSize = SCROLLINFO.sizeof; hInfo.fMask = OS.SIF_ALL; OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo); } SCROLLINFO vInfo = new SCROLLINFO (); vInfo.cbSize = SCROLLINFO.sizeof; vInfo.fMask = OS.SIF_ALL; OS.GetScrollInfo (handle, OS.SB_VERT, vInfo); boolean redraw = getDrawing () && OS.IsWindowVisible (handle); if (redraw) { OS.UpdateWindow (handle); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } setSelection (item); if (hInfo != null) { long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos); OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0); } /* * Feature in Windows. It seems that Vista does not * use wParam to get the new position when WM_VSCROLL * is sent with SB_THUMBPOSITION. The fix is to use * SetScrollInfo() to move the scroll bar thumb before * calling WM_VSCROLL. * * NOTE: This code is only necessary on Windows Vista. */ OS.SetScrollInfo (handle, OS.SB_VERT, vInfo, true); long vThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, vInfo.nPos); OS.SendMessage (handle, OS.WM_VSCROLL, vThumb, 0); if (redraw) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.InvalidateRect (handle, null, true); if ((style & SWT.DOUBLE_BUFFERED) == 0) { int oldStyle = style; style |= SWT.DOUBLE_BUFFERED; OS.UpdateWindow (handle); style = oldStyle; } } return; } expandToItem(item); TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.stateMask = OS.TVIS_SELECTED; tvItem.state = OS.TVIS_SELECTED; tvItem.hItem = item.handle; OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); } /** * Selects all of the items in the receiver. *

    * If the receiver is single-select, do nothing. *

    * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    */ public void selectAll () { checkWidget (); if ((style & SWT.SINGLE) != 0) return; TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.state = OS.TVIS_SELECTED; tvItem.stateMask = OS.TVIS_SELECTED; long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); select (hItem, tvItem); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, oldProc); } Event sendEraseItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT cellRect) { int nSavedDC = OS.SaveDC (nmcd.hdc); RECT insetRect = toolTipInset (cellRect); OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null); GCData data = new GCData (); data.device = display; data.foreground = OS.GetTextColor (nmcd.hdc); data.background = OS.GetBkColor (nmcd.hdc); data.font = item.getFont (column); data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); GC gc = GC.win32_new (nmcd.hdc, data); Event event = new Event (); event.item = item; event.index = column; event.gc = gc; event.detail |= SWT.FOREGROUND; event.setBoundsInPixels(new Rectangle(cellRect.left, cellRect.top, cellRect.right - cellRect.left, cellRect.bottom - cellRect.top)); //gc.setClipping (event.x, event.y, event.width, event.height); sendEvent (SWT.EraseItem, event); event.gc = null; //int newTextClr = data.foreground; gc.dispose (); OS.RestoreDC (nmcd.hdc, nSavedDC); return event; } Event sendMeasureItemEvent (TreeItem item, int index, long hDC, int detail) { RECT itemRect = item.getBounds (index, true, true, false, false, false, hDC); int nSavedDC = OS.SaveDC (hDC); GCData data = new GCData (); data.device = display; data.font = item.getFont (index); GC gc = GC.win32_new (hDC, data); Event event = new Event (); event.item = item; event.gc = gc; event.index = index; event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top)); event.detail = detail; sendEvent (SWT.MeasureItem, event); event.gc = null; gc.dispose (); OS.RestoreDC (hDC, nSavedDC); if (isDisposed () || item.isDisposed ()) return null; Rectangle rect = event.getBoundsInPixels (); if (hwndHeader != 0) { if (columnCount == 0) { if (rect.x + rect.width > scrollWidth) { setScrollWidth (scrollWidth = rect.x + rect.width); } } } if (rect.height > getItemHeightInPixels ()) setItemHeight (rect.height); return event; } Event sendPaintItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT itemRect) { int nSavedDC = OS.SaveDC (nmcd.hdc); RECT insetRect = toolTipInset (itemRect); OS.SetWindowOrgEx (nmcd.hdc, insetRect.left, insetRect.top, null); GCData data = new GCData (); data.device = display; data.font = item.getFont (column); data.foreground = OS.GetTextColor (nmcd.hdc); data.background = OS.GetBkColor (nmcd.hdc); data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0); GC gc = GC.win32_new (nmcd.hdc, data); Event event = new Event (); event.item = item; event.index = column; event.gc = gc; event.detail |= SWT.FOREGROUND; event.setBoundsInPixels(new Rectangle(itemRect.left, itemRect.top, itemRect.right - itemRect.left, itemRect.bottom - itemRect.top)); //gc.setClipping (cellRect.left, cellRect.top, cellWidth, cellHeight); sendEvent (SWT.PaintItem, event); event.gc = null; gc.dispose (); OS.RestoreDC (nmcd.hdc, nSavedDC); return event; } @Override void setBackgroundImage (long hBitmap) { super.setBackgroundImage (hBitmap); if (hBitmap != 0) { /* * Feature in Windows. If TVM_SETBKCOLOR is never * used to set the background color of a tree, the * background color of the lines and the plus/minus * will be drawn using the default background color, * not the HBRUSH returned from WM_CTLCOLOR. The fix * is to set the background color to the default (when * it is already the default) to make Windows use the * brush. */ if (OS.SendMessage (handle, OS.TVM_GETBKCOLOR, 0, 0) == -1) { OS.SendMessage (handle, OS.TVM_SETBKCOLOR, 0, -1); } _setBackgroundPixel (-1); } else { Control control = findBackgroundControl (); if (control == null) control = this; if (control.backgroundImage == null) { setBackgroundPixel (control.getBackgroundPixel ()); } } /* * Feature in Windows. When the tree has the style * TVS_FULLROWSELECT, the background color for the * entire row is filled when an item is painted, * drawing on top of the background image. The fix * is to clear TVS_FULLROWSELECT when a background * image is set. */ updateFullSelection (); } @Override void setBackgroundPixel (int pixel) { Control control = findImageControl (); if (control != null) { setBackgroundImage (control.backgroundImage); return; } _setBackgroundPixel (pixel); /* * Feature in Windows. When the tree has the style * TVS_FULLROWSELECT, the background color for the * entire row is filled when an item is painted, * drawing on top of the background image. The fix * is to restore TVS_FULLROWSELECT when a background * color is set. */ updateFullSelection (); } @Override void setCursor () { /* * Bug in Windows. Under certain circumstances, when WM_SETCURSOR * is sent from SendMessage(), Windows GP's in the window proc for * the tree. The fix is to avoid calling the tree window proc and * set the cursor for the tree outside of WM_SETCURSOR. * * NOTE: This code assumes that the default cursor for the tree * is IDC_ARROW. */ Cursor cursor = findCursor (); long hCursor = cursor == null ? OS.LoadCursor (0, OS.IDC_ARROW) : cursor.handle; OS.SetCursor (hCursor); } /** * Sets the order that the items in the receiver should * be displayed in to the given argument which is described * in terms of the zero-relative ordering of when the items * were added. * * @param order the new order to display the items * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item order is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item order is not the same length as the number of items
    • *
    * * @see Tree#getColumnOrder() * @see TreeColumn#getMoveable() * @see TreeColumn#setMoveable(boolean) * @see SWT#Move * * @since 3.2 */ public void setColumnOrder (int [] order) { checkWidget (); if (order == null) error (SWT.ERROR_NULL_ARGUMENT); if (columnCount == 0) { if (order.length != 0) error (SWT.ERROR_INVALID_ARGUMENT); return; } if (order.length != columnCount) error (SWT.ERROR_INVALID_ARGUMENT); int [] oldOrder = new int [columnCount]; OS.SendMessage (hwndHeader, OS.HDM_GETORDERARRAY, columnCount, oldOrder); boolean reorder = false; boolean [] seen = new boolean [columnCount]; for (int i=0; i= columnCount) error (SWT.ERROR_INVALID_RANGE); if (seen [index]) error (SWT.ERROR_INVALID_ARGUMENT); seen [index] = true; if (index != oldOrder [i]) reorder = true; } if (reorder) { RECT [] oldRects = new RECT [columnCount]; for (int i=0; i * Note: This operation is a HINT and is not supported on all platforms. If * the native header has a 3D look and feel (e.g. Windows 7), this method * will cause the header to look FLAT irrespective of the state of the tree style. *

    * @param color the new color (or null) * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_ARGUMENT - if the argument has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @since 3.106 */ public void setHeaderBackground (Color color) { checkWidget (); int pixel = -1; if (color != null) { if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); pixel = color.handle; } if (pixel == headerBackground) return; headerBackground = pixel; if (getHeaderVisible()) { OS.InvalidateRect (hwndHeader, null, true); } } /** * Sets the header foreground color to the color specified * by the argument, or to the default system color if the argument is null. *

    * Note: This operation is a HINT and is not supported on all platforms. If * the native header has a 3D look and feel (e.g. Windows 7), this method * will cause the header to look FLAT irrespective of the state of the tree style. *

    * @param color the new color (or null) * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_ARGUMENT - if the argument has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * @since 3.106 */ public void setHeaderForeground (Color color) { checkWidget (); int pixel = -1; if (color != null) { if (color.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); pixel = color.handle; } if (pixel == headerForeground) return; headerForeground = pixel; if (getHeaderVisible()) { OS.InvalidateRect (hwndHeader, null, true); } } /** * Marks the receiver's header as visible if the argument is true, * and marks it invisible otherwise. *

    * If one of the receiver's ancestors is not visible or some * other condition makes the receiver not visible, marking * it visible may not actually cause it to be displayed. *

    * * @param show the new visibility state * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public void setHeaderVisible (boolean show) { checkWidget (); if (hwndHeader == 0) { if (!show) return; createParent (); } int bits = OS.GetWindowLong (hwndHeader, OS.GWL_STYLE); if (show) { if ((bits & OS.HDS_HIDDEN) == 0) return; bits &= ~OS.HDS_HIDDEN; OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits); OS.ShowWindow (hwndHeader, OS.SW_SHOW); } else { if ((bits & OS.HDS_HIDDEN) != 0) return; bits |= OS.HDS_HIDDEN; OS.SetWindowLong (hwndHeader, OS.GWL_STYLE, bits); OS.ShowWindow (hwndHeader, OS.SW_HIDE); } setScrollWidth (); updateHeaderToolTips (); updateScrollBar (); } @Override public void setRedraw (boolean redraw) { checkWidget (); /* * Feature in Windows. When WM_SETREDRAW is used to * turn off redraw, the scroll bars are updated when * items are added and removed. The fix is to call * the default window proc to stop all drawing. * * Bug in Windows. For some reason, when WM_SETREDRAW * is used to turn redraw on for a tree and the tree * contains no items, the last item in the tree does * not redraw properly. If the tree has only one item, * that item is not drawn. If another window is dragged * on top of the item, parts of the item are redrawn * and erased at random. The fix is to ensure that this * case doesn't happen by inserting and deleting an item * when redraw is turned on and there are no items in * the tree. */ long hItem = 0; boolean willEnableDraw = redraw && (drawCount == 1); if (willEnableDraw) { int count = (int)OS.SendMessage (handle, OS.TVM_GETCOUNT, 0, 0); if (count == 0) { TVINSERTSTRUCT tvInsert = new TVINSERTSTRUCT (); tvInsert.hInsertAfter = OS.TVI_FIRST; hItem = OS.SendMessage (handle, OS.TVM_INSERTITEM, 0, tvInsert); } OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); updateScrollBar (); } super.setRedraw (redraw); boolean haveDisabledDraw = !redraw && (drawCount == 1); if (haveDisabledDraw) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } if (hItem != 0) { ignoreShrink = true; OS.SendMessage (handle, OS.TVM_DELETEITEM, 0, hItem); ignoreShrink = false; } } void setScrollWidth () { if (hwndHeader == 0 || hwndParent == 0) return; int width = 0; HDITEM hdItem = new HDITEM (); for (int i=0; i * If the item is not in the receiver, then it is ignored. *

    * * @param item the item to select * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ public void setSelection (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); setSelection (new TreeItem [] {item}); } /** * Sets the receiver's selection to be the given array of items. * The current selection is cleared before the new items are selected, * and if necessary the receiver is scrolled to make the new selection visible. *

    * Items that are not in the receiver are ignored. * If the receiver is single-select and multiple items are specified, * then all items are ignored. *

    * * @param items the array of items * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the array of items is null
    • *
    • ERROR_INVALID_ARGUMENT - if one of the items has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#deselectAll() */ public void setSelection (TreeItem [] items) { checkWidget (); if (items == null) error (SWT.ERROR_NULL_ARGUMENT); int length = items.length; if (length == 0 || ((style & SWT.SINGLE) != 0 && length > 1)) { deselectAll(); return; } /* Select/deselect the first item */ TreeItem item = items [0]; if (item != null) { if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); long hOldItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); long hNewItem = hAnchor = item.handle; /* * Bug in Windows. When TVM_SELECTITEM is used to select and * scroll an item to be visible and the client area of the tree * is smaller that the size of one item, TVM_SELECTITEM makes * the next item in the tree visible by making it the top item * instead of making the desired item visible. The fix is to * detect the case when the client area is too small and make * the desired visible item be the top item in the tree. * * Note that TVM_SELECTITEM when called with TVGN_FIRSTVISIBLE * also requires the work around for scrolling. */ boolean fixScroll = checkScroll (hNewItem); if (fixScroll) { OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } ignoreSelect = true; OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_CARET, hNewItem); ignoreSelect = false; if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) { OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hNewItem); long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hNewItem); if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0); } if (fixScroll) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); } /* * Feature in Windows. When the old and new focused item * are the same, Windows does not check to make sure that * the item is actually selected, not just focused. The * fix is to force the item to draw selected by setting * the state mask, and to ensure that it is visible. */ if (hOldItem == hNewItem) { TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.state = OS.TVIS_SELECTED; tvItem.stateMask = OS.TVIS_SELECTED; tvItem.hItem = hNewItem; OS.SendMessage (handle, OS.TVM_SETITEM, 0, tvItem); showItem (hNewItem); } } if ((style & SWT.SINGLE) != 0) return; /* Select/deselect the rest of the items */ TVITEM tvItem = new TVITEM (); tvItem.mask = OS.TVIF_HANDLE | OS.TVIF_STATE; tvItem.stateMask = OS.TVIS_SELECTED; long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); if ((style & SWT.VIRTUAL) != 0) { long hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); setSelection (hItem, tvItem, items); } else { for (int i=0; inull * * @exception IllegalArgumentException
      *
    • ERROR_INVALID_ARGUMENT - if the column is disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ public void setSortColumn (TreeColumn column) { checkWidget (); if (column != null && column.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); if (sortColumn != null && !sortColumn.isDisposed ()) { sortColumn.setSortDirection (SWT.NONE); } sortColumn = column; if (sortColumn != null && sortDirection != SWT.NONE) { sortColumn.setSortDirection (sortDirection); } } /** * Sets the direction of the sort indicator for the receiver. The value * can be one of UP, DOWN or NONE. * * @param direction the direction of the sort indicator * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.2 */ public void setSortDirection (int direction) { checkWidget (); if ((direction & (SWT.UP | SWT.DOWN)) == 0 && direction != SWT.NONE) return; sortDirection = direction; if (sortColumn != null && !sortColumn.isDisposed ()) { sortColumn.setSortDirection (direction); } } /** * Sets the item which is currently at the top of the receiver. * This item can change when items are expanded, collapsed, scrolled * or new items are added or removed. * * @param item the item to be shown * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#getTopItem() * * @since 2.1 */ public void setTopItem (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); long hItem = item.handle; long hTopItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_FIRSTVISIBLE, 0); if (hItem == hTopItem) return; boolean fixScroll = checkScroll (hItem), redraw = false; if (fixScroll) { OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } else { redraw = getDrawing () && OS.IsWindowVisible (handle); if (redraw) OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } SCROLLINFO hInfo = null; int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); long hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem); if (hParent != 0 && (bits & (OS.TVS_NOHSCROLL | OS.TVS_NOSCROLL)) == 0) { hInfo = new SCROLLINFO (); hInfo.cbSize = SCROLLINFO.sizeof; hInfo.fMask = OS.SIF_ALL; OS.GetScrollInfo (handle, OS.SB_HORZ, hInfo); } OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem); if (hParent != 0) { if (hInfo != null) { long hThumb = OS.MAKELPARAM (OS.SB_THUMBPOSITION, hInfo.nPos); OS.SendMessage (handle, OS.WM_HSCROLL, hThumb, 0); } } else { OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0); } if (fixScroll) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); } else { if (redraw) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.InvalidateRect (handle, null, true); } } updateScrollBar (); } void showItem (long hItem) { /* * Bug in Windows. When TVM_ENSUREVISIBLE is used to ensure * that an item is visible and the client area of the tree is * smaller that the size of one item, TVM_ENSUREVISIBLE makes * the next item in the tree visible by making it the top item * instead of making the desired item visible. The fix is to * detect the case when the client area is too small and make * the desired visible item be the top item in the tree. */ if (OS.SendMessage (handle, OS.TVM_GETVISIBLECOUNT, 0, 0) == 0) { boolean fixScroll = checkScroll (hItem); if (fixScroll) { OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } OS.SendMessage (handle, OS.TVM_SELECTITEM, OS.TVGN_FIRSTVISIBLE, hItem); /* This code is intentionally commented */ //int hParent = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_PARENT, hItem); //if (hParent == 0) OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0); OS.SendMessage (handle, OS.WM_HSCROLL, OS.SB_TOP, 0); if (fixScroll) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); } } else { boolean scroll = true; RECT itemRect = new RECT (); if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) { forceResize (); RECT rect = new RECT (); OS.GetClientRect (handle, rect); POINT pt = new POINT (); pt.x = itemRect.left; pt.y = itemRect.top; if (OS.PtInRect (rect, pt)) { pt.y = itemRect.bottom; if (OS.PtInRect (rect, pt)) scroll = false; } } if (scroll) { boolean fixScroll = checkScroll (hItem); if (fixScroll) { OS.SendMessage (handle, OS.WM_SETREDRAW, 1, 0); OS.DefWindowProc (handle, OS.WM_SETREDRAW, 0, 0); } OS.SendMessage (handle, OS.TVM_ENSUREVISIBLE, 0, hItem); if (fixScroll) { OS.DefWindowProc (handle, OS.WM_SETREDRAW, 1, 0); OS.SendMessage (handle, OS.WM_SETREDRAW, 0, 0); } } } if (hwndParent != 0) { RECT itemRect = new RECT (); if (OS.TreeView_GetItemRect (handle, hItem, itemRect, true)) { forceResize (); RECT rect = new RECT (); OS.GetClientRect (hwndParent, rect); OS.MapWindowPoints (hwndParent, handle, rect, 2); POINT pt = new POINT (); pt.x = itemRect.left; pt.y = itemRect.top; if (!OS.PtInRect (rect, pt)) { pt.y = itemRect.bottom; if (!OS.PtInRect (rect, pt)) { SCROLLINFO info = new SCROLLINFO (); info.cbSize = SCROLLINFO.sizeof; info.fMask = OS.SIF_POS; info.nPos = Math.max (0, pt.x - Tree.INSET / 2); OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true); setScrollWidth (); } } } } updateScrollBar (); } /** * Shows the column. If the column is already showing in the receiver, * this method simply returns. Otherwise, the columns are scrolled until * the column is visible. * * @param column the column to be shown * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @since 3.1 */ public void showColumn (TreeColumn column) { checkWidget (); if (column == null) error (SWT.ERROR_NULL_ARGUMENT); if (column.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT); if (column.parent != this) return; int index = indexOf (column); if (index == -1) return; if (0 <= index && index < columnCount) { forceResize (); RECT rect = new RECT (); OS.GetClientRect (hwndParent, rect); OS.MapWindowPoints (hwndParent, handle, rect, 2); RECT headerRect = new RECT (); OS.SendMessage (hwndHeader, OS.HDM_GETITEMRECT, index, headerRect); boolean scroll = headerRect.left < rect.left; if (!scroll) { int width = Math.min (rect.right - rect.left, headerRect.right - headerRect.left); scroll = headerRect.left + width > rect.right; } if (scroll) { SCROLLINFO info = new SCROLLINFO (); info.cbSize = SCROLLINFO.sizeof; info.fMask = OS.SIF_POS; info.nPos = Math.max (0, headerRect.left - Tree.INSET / 2); OS.SetScrollInfo (hwndParent, OS.SB_HORZ, info, true); setScrollWidth (); } } } /** * Shows the item. If the item is already showing in the receiver, * this method simply returns. Otherwise, the items are scrolled * and expanded until the item is visible. * * @param item the item to be shown * * @exception IllegalArgumentException
      *
    • ERROR_NULL_ARGUMENT - if the item is null
    • *
    • ERROR_INVALID_ARGUMENT - if the item has been disposed
    • *
    * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#showSelection() */ public void showItem (TreeItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed ()) error(SWT.ERROR_INVALID_ARGUMENT); showItem (item.handle); } /** * Shows the selection. If the selection is already showing in the receiver, * this method simply returns. Otherwise, the items are scrolled until * the selection is visible. * * @exception SWTException
      *
    • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    • *
    • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
    • *
    * * @see Tree#showItem(TreeItem) */ public void showSelection () { checkWidget (); long hItem = 0; if ((style & SWT.SINGLE) != 0) { hItem = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_CARET, 0); if (hItem == 0) return; int state = (int)OS.SendMessage (handle, OS.TVM_GETITEMSTATE, hItem, OS.TVIS_SELECTED); if ((state & OS.TVIS_SELECTED) == 0) return; } else { long oldProc = OS.GetWindowLongPtr (handle, OS.GWLP_WNDPROC); OS.SetWindowLongPtr (handle, OS.GWLP_WNDPROC, TreeProc); if ((style & SWT.VIRTUAL) != 0) { long hRoot = OS.SendMessage (handle, OS.TVM_GETNEXTITEM, OS.TVGN_ROOT, 0); hItem = getNextSelection (hRoot); } else { //FIXME - this code expands first selected item it finds int index = 0; while (index