X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.eclipse.swt.win32.win32.x86_64%2Fsrc%2Forg%2Feclipse%2Fswt%2Fwidgets%2FTree.java;fp=bundles%2Forg.eclipse.swt.win32.win32.x86_64%2Fsrc%2Forg%2Feclipse%2Fswt%2Fwidgets%2FTree.java;h=456e338987b553f2c50add4b187b70bb0a26fd49;hb=6b98970d0458754dd67f789afbd0a39e1e7ac6eb;hp=0000000000000000000000000000000000000000;hpb=56a61575ce0d27b340cb12438c8a7f303842095e;p=simantics%2Fplatform.git diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tree.java new file mode 100644 index 000000000..456e33898 --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/Tree.java @@ -0,0 +1,8095 @@ +/******************************************************************************* + * 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