All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.swt.widgets.Tree Maven / Gradle / Ivy

There is a newer version: 3.29.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2002, 2013 Innoopract Informationssysteme GmbH and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Innoopract Informationssysteme GmbH - initial API and implementation
 *    EclipseSource - ongoing development
 ******************************************************************************/
package org.eclipse.swt.widgets;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil;
import org.eclipse.rap.rwt.internal.theme.IThemeAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.SerializableCompatibility;
import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
import org.eclipse.swt.internal.widgets.IControlAdapter;
import org.eclipse.swt.internal.widgets.IItemHolderAdapter;
import org.eclipse.swt.internal.widgets.ITreeAdapter;
import org.eclipse.swt.internal.widgets.ItemHolder;
import org.eclipse.swt.internal.widgets.MarkupValidator;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor;
import org.eclipse.swt.internal.widgets.WidgetTreeVisitor.AllWidgetTreeVisitor;
import org.eclipse.swt.internal.widgets.treekit.TreeThemeAdapter;


/**
 * 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 make sense to add Control children to it, or set a * layout on it. *

*

*

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

*

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

*

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

* * @since 1.0 */ public class Tree extends Composite { private static final TreeItem[] EMPTY_SELECTION = new TreeItem[ 0 ]; // This values must be kept in sync with appearance of list items private static final int MIN_ITEM_HEIGHT = 16; private static final int GRID_WIDTH = 1; private static final Rectangle TEXT_MARGIN = new Rectangle( 3, 0, 8, 0 ); private int itemCount; private int customItemHeight; private TreeItem[] items; final ItemHolder columnHolder; private TreeItem[] selection; private boolean linesVisible; private int[] columnOrder; private int itemImageCount; private TreeColumn sortColumn; private int sortDirection; private boolean headerVisible; private final ITreeAdapter treeAdapter; private int scrollLeft; private int topItemIndex; private boolean hasVScrollBar; private boolean hasHScrollBar; private Point itemImageSize; LayoutCache layoutCache; boolean isFlatIndexValid; private int visibleItemsCount; boolean markupEnabled; boolean markupValidationDisabled; /** * 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
    *
  • ERROR_NULL_ARGUMENT - if the parent is null
  • *
* @exception SWTException
    *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the parent
  • *
  • ERROR_INVALID_SUBCLASS - if this class is not an allowed * subclass
  • *
* @see SWT#SINGLE * @see SWT#MULTI * @see SWT#CHECK * @see SWT#FULL_SELECTION * @see SWT#NO_SCROLL * @see Widget#checkSubclass * @see Widget#getStyle */ public Tree( Composite parent, int style ) { super( parent, checkStyle( style ) ); columnHolder = new ItemHolder( TreeColumn.class ); treeAdapter = new InternalTreeAdapter(); setTreeEmpty(); sortDirection = SWT.NONE; selection = EMPTY_SELECTION; customItemHeight = -1; layoutCache = new LayoutCache(); } TreeItem[] getCreatedItems() { TreeItem[] result; if( isVirtual() ) { int count = 0; for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null && items[ i ].isCached() ) { count++; } } result = new TreeItem[ count ]; count = 0; for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null && items[ i ].isCached() ) { result[ count ] = items[ i ]; count++; } } } else { result = new TreeItem[ itemCount ]; System.arraycopy( items, 0, result, 0, itemCount ); } return result; } private void setTreeEmpty() { items = new TreeItem[ 4 ]; // TODO: Not sure if we have to clear the image size???!!! // clearItemImageSize(); } @Override void initState() { state &= ~( /* CANVAS | */THEME_BACKGROUND ); } @Override @SuppressWarnings("unchecked") public T getAdapter( Class adapter ) { T result; if( adapter == IItemHolderAdapter.class ) { result = ( T )new CompositeItemHolder(); } else if( adapter == ITreeAdapter.class ) { result = ( T )treeAdapter; } else if( adapter == ICellToolTipAdapter.class ) { result = ( T )treeAdapter; } else { result = super.getAdapter( adapter ); } return result; } @Override public void setFont( Font font ) { super.setFont( font ); for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null ) { items[ i ].clearPreferredWidthBuffers( true ); } } layoutCache.invalidateHeaderHeight(); layoutCache.invalidateItemHeight(); updateScrollBars(); } // ///////////////////////// // Methods to manage items /** * 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
  • *
*/ public void setItemCount( int count ) { checkWidget(); int oldItemCount = itemCount; int newItemCount = Math.max( 0, count ); if( newItemCount != oldItemCount ) { int deleteIndex = oldItemCount - 1; while( deleteIndex >= newItemCount ) { TreeItem item = items[ deleteIndex ]; if( item != null && !item.isDisposed() ) { item.dispose(); } else { destroyItem( null, deleteIndex ); } deleteIndex--; } int length = Math.max( 4, ( newItemCount + 3 ) / 4 * 4 ); TreeItem[] newItems = new TreeItem[ length ]; System.arraycopy( items, 0, newItems, 0, Math.min( newItemCount, itemCount ) ); items = newItems; if( !isVirtual() ) { for( int i = itemCount; i < newItemCount; i++ ) { items[ i ] = new TreeItem( this, SWT.NONE, i ); } } itemCount = newItemCount; isFlatIndexValid = false; updateScrollBars(); redraw(); } } /** * 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(); return itemCount; } /** * 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(); TreeItem[] result = new TreeItem[ itemCount ]; if( isVirtual() ) { for( int i = 0; i < itemCount; i++ ) { result[ i ] = _getItem( i ); } } else { System.arraycopy( items, 0, result, 0, itemCount ); } return result; } private TreeItem _getItem( int index ) { if( isVirtual() && items[ index ] == null ) { items[ index ] = new TreeItem( this, null, SWT.NONE, index, false ); } return items[ index ]; } /** * 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
  • *
*/ public TreeItem getItem( int index ) { checkWidget(); if( index < 0 || index >= itemCount ) { SWT.error( SWT.ERROR_INVALID_RANGE ); } return _getItem( index ); } /** * Searches the receiver's list starting at the first item (index 0) until an * item is found that is equal to the argument, and returns the index of that * item. If no item is found, returns -1. * * @param item the search item * @return the index of the item * @exception IllegalArgumentException
    *
  • ERROR_NULL_ARGUMENT - if the tool item is null
  • *
  • ERROR_INVALID_ARGUMENT - if the tool 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 int indexOf( TreeItem item ) { checkWidget(); if( item == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } if( item.isDisposed() ) { SWT.error( SWT.ERROR_INVALID_ARGUMENT ); } return item.parent == this ? item.index : -1; } /** * 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; } /** * Removes all of the items from 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 removeAll() { checkWidget(); for( int i = itemCount - 1; i >= 0; i-- ) { if( items[ i ] != null ) { items[ i ].dispose(); } else { itemCount--; } } setTreeEmpty(); selection = EMPTY_SELECTION; } /** * 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 ); } if( item.getParent() == this ) { TreeItem parent = item.getParentItem(); while( parent != null ) { parent.setExpanded( true ); parent = parent.getParentItem(); } int flatIndex = item.getFlatIndex(); if( flatIndex <= topItemIndex ) { setTopItemIndex( flatIndex ); } else { int itemsAreaHeight = getClientArea().height - getHeaderHeight(); int rows = ( int )Math.floor( itemsAreaHeight / getItemHeight() ); if( flatIndex >= topItemIndex + rows ) { setTopItemIndex( flatIndex - rows + 1 ); } } } } /** * 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 1.4 */ public void setTopItem( TreeItem item ) { checkWidget(); if( item == null ) { error( SWT.ERROR_NULL_ARGUMENT ); } if( item.isDisposed() ) { error( SWT.ERROR_INVALID_ARGUMENT ); } if( item.getParent() == this ) { TreeItem parent = item.getParentItem(); while( parent != null ) { parent.setExpanded( true ); parent = parent.getParentItem(); } int itemsAreaHeight = getClientArea().height - getHeaderHeight(); int rows = ( int )Math.floor( itemsAreaHeight / getItemHeight() ); int flatIndex = item.getFlatIndex(); if( flatIndex <= topItemIndex || flatIndex + rows <= visibleItemsCount ) { setTopItemIndex( flatIndex ); } else { int index = Math.max( 0, visibleItemsCount - rows ); setTopItemIndex( index ); } } } /** * 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 1.4 */ public TreeItem getTopItem() { checkWidget(); TreeItem result = null; if( itemCount > 0 ) { List visibleItems = collectVisibleItems( null ); result = ( TreeItem )visibleItems.get( getTopItemIndex() ); } return result; } private void setTopItemIndex( int index ) { if( index != topItemIndex ) { topItemIndex = index; adjustTopItemIndex(); updateAllItems(); } } int getTopItemIndex() { if( !isFlatIndexValid ) { updateAllItems(); adjustTopItemIndex(); } return topItemIndex; } /** * 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 column is null
  • *
  • ERROR_INVALID_ARGUMENT - if the column 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 1.3 */ public void showColumn( TreeColumn column ) { checkWidget(); if( column == null ) { error( SWT.ERROR_NULL_ARGUMENT ); } if( column.isDisposed() ) { error( SWT.ERROR_INVALID_ARGUMENT ); } if( column.getParent() == this ) { int index = indexOf( column ); if( 0 <= index && index < getColumnCount() ) { int leftColumnsWidth = 0; int rightColumnsWidth = 0; int columnWidth = column.getWidth(); int clientWidth = getClientArea().width; int[] columnOrder = getColumnOrder(); boolean found = false; for( int i = 0; i < columnOrder.length; i++ ) { if( index != columnOrder[ i ] ) { int currentColumnWidth = getColumn( columnOrder[ i ] ).getWidth(); if( found ) { rightColumnsWidth += currentColumnWidth; } else { if( isFixedColumn( columnOrder[ i ] ) ) { clientWidth -= currentColumnWidth; } else { leftColumnsWidth += currentColumnWidth; } } } else { found = true; } } if( getColumnLeftOffset( index ) > leftColumnsWidth ) { scrollLeft = leftColumnsWidth; } else if( scrollLeft < leftColumnsWidth + columnWidth - clientWidth ) { if( columnWidth + rightColumnsWidth < clientWidth ) { scrollLeft = leftColumnsWidth + columnWidth + rightColumnsWidth - clientWidth; } else { scrollLeft = leftColumnsWidth; } } } } } /** * 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(); if( selection.length == 0 ) { return; } showItem( selection[ 0 ] ); } // /////////////////////////////////// // Methods to get/set/clear selection /** * 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(); TreeItem[] result = new TreeItem[ selection.length ]; System.arraycopy( selection, 0, result, 0, selection.length ); 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(); return selection.length; } /** * Sets the receiver's selection to the given item. The current selection is * cleared before the new item is selected. *

* If the item is not in the receiver, then it is ignored. *

* * @param selection 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
  • *
*/ public void setSelection( TreeItem selection ) { checkWidget(); if( selection == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } setSelection( new TreeItem[]{ selection } ); } /** * Sets the receiver's selection to be the given array of items. The current * selection is cleared before the new items are selected. *

* 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 selection 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[] selection ) { checkWidget(); if( selection == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } int length = selection.length; if( ( style & SWT.SINGLE ) != 0 ) { if( length == 0 || length > 1 ) { deselectAll(); } else { TreeItem item = selection[ 0 ]; if( item != null ) { if( item.isDisposed() ) { SWT.error( SWT.ERROR_INVALID_ARGUMENT ); } this.selection = new TreeItem[]{ item }; } } } else { if( length == 0 ) { deselectAll(); } else { // Construct an array that contains all non-null items to be selected TreeItem[] validSelection = new TreeItem[ length ]; int validLength = 0; for( int i = 0; i < length; i++ ) { if( selection[ i ] != null ) { if( selection[ i ].isDisposed() ) { SWT.error( SWT.ERROR_INVALID_ARGUMENT ); } validSelection[ validLength ] = selection[ i ]; validLength++; } } if( validLength > 0 ) { // Copy the above created array to its 'final destination' this.selection = new TreeItem[ validLength ]; System.arraycopy( validSelection, 0, this.selection, 0, validLength ); } } } } /** * 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 1.3 */ 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 ) { setSelection( item ); } else { List selItems = new ArrayList( Arrays.asList( selection ) ); if( !selItems.contains( item ) ) { selItems.add( item ); selection = new TreeItem[ selItems.size() ]; selItems.toArray( selection ); } } } /** * 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.MULTI ) != 0 ) { final java.util.List allItems = new ArrayList(); WidgetTreeVisitor.accept( this, new AllWidgetTreeVisitor() { @Override public boolean doVisit( Widget widget ) { if( widget instanceof TreeItem ) { allItems.add( ( TreeItem )widget ); } return true; } } ); selection = new TreeItem[ allItems.size() ]; allItems.toArray( selection ); } } /** * Deselects an item in the receiver. If the item was already * deselected, it remains deselected. * * @param item the item to be deselected * * @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 1.3 */ public void deselect( TreeItem item ) { checkWidget(); if( item == null ) { error( SWT.ERROR_NULL_ARGUMENT ); } if( item.isDisposed() ) { error( SWT.ERROR_INVALID_ARGUMENT ); } List selItems = new ArrayList( Arrays.asList( selection ) ); if( selItems.contains( item ) ) { selItems.remove( item ); selection = new TreeItem[ selItems.size() ]; selItems.toArray( selection ); } } /** * 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(); selection = EMPTY_SELECTION; } /** * Marks the receiver's lines 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 value 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
  • *
*/ public void setLinesVisible( boolean value ) { checkWidget(); if( linesVisible == value ) { return; /* no change */ } linesVisible = value; } /** * Returns the width in pixels of a grid line. * * @return the width of a grid line in pixels * * @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 1.4 */ public int getGridLineWidth() { checkWidget(); return GRID_WIDTH; } /** * Returns true if the receiver's lines are 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 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
  • *
*/ public boolean getLinesVisible() { checkWidget(); return linesVisible; } /** * 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 recursive 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 */ public void clear( int index, boolean recursive ) { checkWidget(); if( index < 0 || index >= itemCount ) { error( SWT.ERROR_INVALID_RANGE ); } TreeItem item = items[ index ]; if( item != null ) { item.clear(); if( recursive ) { item.clearAll( true, false ); } } } /** * 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 ); } TreeItem result = null; int index = ( point.y - getHeaderHeight() ) / getItemHeight() + topItemIndex; List visibleItems = collectVisibleItems( null ); if( 0 <= index && index < visibleItems.size() ) { result = ( TreeItem )visibleItems.get( index ); } return result; } private List collectVisibleItems( TreeItem parentItem ) { List result = new ArrayList(); TreeItem[] items = parentItem == null ? this.items : parentItem.items; int itemCount = parentItem == null ? this.itemCount : parentItem.itemCount; for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; result.add( item ); if( item != null && item.getExpanded() ) { result.addAll( collectVisibleItems( item ) ); } } return result; } /** * 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
  • *
* * @since 1.3 */ public int getItemHeight() { checkWidget(); int result = customItemHeight; if( result == -1 ) { if( !layoutCache.hasItemHeight() ) { layoutCache.itemHeight = computeItemHeight(); } result = layoutCache.itemHeight; } return result; } /** * 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 recursive 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 */ public void clearAll( boolean recursive ) { checkWidget(); for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null ) { item.clear(); if( recursive ) { item.clearAll( true, false ); } } } if( isVirtual() && itemCount != 0 ) { updateAllItems(); } } @Override public void changed( Control[] changed ) { clearItemsPreferredWidthBuffer(); super.changed( changed ); } private void clearItemsPreferredWidthBuffer() { for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null ) { item.clearPreferredWidthBuffers( true ); } } } /** * 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
  • *
*/ public int getColumnCount() { checkWidget(); return columnHolder.size(); } void createColumn( TreeColumn column, int index ) { columnHolder.insert( column, index ); if( columnOrder == null ) { columnOrder = new int[]{ index }; } else { int length = columnOrder.length; for( int i = index; i < length; i++ ) { columnOrder[ i ]++; } int[] newColumnOrder = new int[ length + 1 ]; System.arraycopy( columnOrder, 0, newColumnOrder, 0, index ); System.arraycopy( columnOrder, index, newColumnOrder, index + 1, length - index ); columnOrder = newColumnOrder; columnOrder[ index ] = index; } for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null ) { items[ i ].shiftData( index ); } } updateScrollBars(); } final void destroyColumn( TreeColumn column ) { if( !isInDispose() ) { int index = indexOf( column ); // Remove data from TreeItems for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null ) { items[ i ].removeData( index ); } } // Reset sort column if necessary if( column == sortColumn ) { sortColumn = null; } // Remove from column holder columnHolder.remove( column ); // Remove from column order int length = columnOrder.length; int[] newColumnOrder = new int[ length - 1 ]; int count = 0; for( int i = 0; i < length; i++ ) { if( columnOrder[ i ] != index ) { int newOrder = columnOrder[ i ]; if( index < newOrder ) { newOrder--; } newColumnOrder[ count ] = newOrder; count++; } } columnOrder = newColumnOrder; updateScrollBars(); } } /** * 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
  • *
*/ public int getHeaderHeight() { checkWidget(); if( !layoutCache.hasHeaderHeight() ) { layoutCache.headerHeight = computeHeaderHeight(); } return layoutCache.headerHeight; } /** * 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 value 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
  • *
*/ public void setHeaderVisible( boolean value ) { checkWidget(); if( headerVisible != value ) { headerVisible = value; layoutCache.invalidateHeaderHeight(); updateScrollBars(); } } /** * 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
  • *
*/ public boolean getHeaderVisible() { checkWidget(); return headerVisible; } /** * 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
  • *
*/ public int indexOf( TreeColumn column ) { checkWidget(); if( column == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } if( column.isDisposed() ) { error( SWT.ERROR_INVALID_ARGUMENT ); } return columnHolder.indexOf( column ); } /** * 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 */ public TreeColumn getColumn( int index ) { checkWidget(); if( !( 0 <= index && index < columnHolder.size() ) ) { error( SWT.ERROR_INVALID_RANGE ); } return columnHolder.getItem( index ); } /** * 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 */ public TreeColumn[] getColumns() { checkWidget(); return columnHolder.getItems(); } /** * 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 */ public void setColumnOrder( int[] order ) { checkWidget(); if( order == null ) { error( SWT.ERROR_NULL_ARGUMENT ); } int columnCount = getColumnCount(); if( order.length != columnCount ) { error( SWT.ERROR_INVALID_ARGUMENT ); } if( columnCount > 0 ) { int[] oldOrder = new int[ columnCount ]; System.arraycopy( columnOrder, 0, oldOrder, 0, columnOrder.length ); boolean reorder = false; boolean[] seen = new boolean[ columnCount ]; for( int i = 0; i < order.length; i++ ) { int index = order[ i ]; if( index < 0 || index >= 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 ) { System.arraycopy( order, 0, columnOrder, 0, columnOrder.length ); for( int i = 0; i < seen.length; i++ ) { if( oldOrder[ i ] != columnOrder[ i ] ) { TreeColumn column = getColumn( columnOrder[ i ] ); column.notifyListeners( SWT.Move, new Event() ); } } } } } /** * Sets the column used by the sort indicator for the receiver. A null value * will clear the sort indicator. The current sort column is cleared before * the new column is set. * * @param column the column used by the sort indicator or null * @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
  • *
*/ public void setSortColumn( TreeColumn column ) { checkWidget(); if( column != null && column.isDisposed() ) { error( SWT.ERROR_INVALID_ARGUMENT ); } if( column == sortColumn ) { return; } if( sortColumn != null && !sortColumn.isDisposed() ) { sortColumn.setSortDirection( SWT.NONE ); } sortColumn = column; if( sortColumn != null ) { 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
  • *
*/ public void setSortDirection( int direction ) { checkWidget(); if( direction != SWT.UP && direction != SWT.DOWN && direction != SWT.NONE ) { return; } sortDirection = direction; if( sortColumn == null || sortColumn.isDisposed() ) { return; } sortColumn.setSortDirection( sortDirection ); } /** * Returns the column which shows the sort indicator for the receiver. The * value may be null if no column shows the sort indicator. * * @return 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
  • *
* @see #setSortColumn(TreeColumn) */ public TreeColumn getSortColumn() { checkWidget(); return sortColumn; } /** * 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) */ public int getSortDirection() { checkWidget(); return sortDirection; } /** * 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 */ public int[] getColumnOrder() { checkWidget(); int[] result; if( columnHolder.size() == 0 ) { result = new int[ 0 ]; } else { result = new int[ columnOrder.length ]; System.arraycopy( columnOrder, 0, result, 0, columnOrder.length ); } return result; } /////////////////////////////////////// // Listener registration/deregistration /** * Adds the listener to the collection of listeners who will be notified when * the receiver's selection changes, 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 SWT.CHECK style set 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 * @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 SelectionListener * @see #removeSelectionListener * @see SelectionEvent */ public void addSelectionListener( SelectionListener listener ) { checkWidget(); if( listener == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } TypedListener typedListener = new TypedListener( listener ); addListener( SWT.Selection, typedListener ); addListener( SWT.DefaultSelection, typedListener ); } /** * Removes the listener from the collection of listeners who will be notified * when the receiver's selection changes. * * @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 SelectionListener * @see #addSelectionListener */ public void removeSelectionListener( SelectionListener listener ) { checkWidget(); if( listener == null ) { SWT.error( SWT.ERROR_NULL_ARGUMENT ); } removeListener( SWT.Selection, listener ); removeListener( SWT.DefaultSelection, listener ); } /** * 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
    *
  • 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 #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 ); } /** * 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 ); } removeListener( SWT.Expand, listener ); removeListener( SWT.Collapse, listener ); } @Override public void setData( String key, Object value ) { if( RWT.CUSTOM_VARIANT.equals( key ) ) { layoutCache.invalidateAll(); } else if( RWT.CUSTOM_ITEM_HEIGHT.equals( key ) ) { setCustomItemHeight( value ); } else if( RWT.MARKUP_ENABLED.equals( key ) && !markupEnabled ) { markupEnabled = Boolean.TRUE.equals( value ); } else if( MarkupValidator.MARKUP_VALIDATION_DISABLED.equals( key ) ) { markupValidationDisabled = Boolean.TRUE.equals( value ); } super.setData( key, value ); } ///////////////////////////////// // Methods to cleanup on dispose @Override void releaseChildren() { for( int i = items.length - 1; i >= 0; i-- ) { if( items[ i ] != null ) { items[ i ].dispose(); } } TreeColumn[] cols = columnHolder.getItems(); for( int c = 0; c < cols.length; c++ ) { cols[ c ].dispose(); columnHolder.remove( cols[ c ] ); } super.releaseChildren(); } void removeFromSelection( TreeItem item ) { int index = -1; for( int i = 0; index == -1 && i < selection.length; i++ ) { if( selection[ i ] == item ) { index = i; } } if( index != -1 ) { TreeItem[] newSelection = new TreeItem[ selection.length - 1 ]; System.arraycopy( selection, 0, newSelection, 0, index ); if( index < selection.length - 1 ) { int length = selection.length - index - 1; System.arraycopy( selection, index + 1, newSelection, index, length ); } selection = newSelection; } } ///////////////////// // Widget dimensions @Override public Point computeSize( int wHint, int hHint, boolean changed ) { checkWidget(); int width = 0; int height = 0; if( getColumnCount() > 0 ) { for( int i = 0; i < getColumnCount(); i++ ) { width += getColumn( i ).getWidth(); } } else { for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null && item.isCached() ) { int itemWidth = item.getPreferredWidth( 0, false ); width = Math.max( width, itemWidth ); if( item.getExpanded() ) { int innerWidth = getMaxInnerWidth( item.items, 0, 1, false ); width = Math.max( width, innerWidth ); } } } } height += getHeaderHeight(); height += itemCount * getItemHeight(); for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null && !item.isInDispose() && item.getExpanded() ) { height += item.getInnerHeight(); } } if( width == 0 ) { width = DEFAULT_WIDTH; } if( height == 0 ) { height = DEFAULT_HEIGHT; } if( wHint != SWT.DEFAULT ) { width = wHint; } if( hHint != SWT.DEFAULT ) { height = hHint; } int border = getBorderWidth(); width += border * 2; height += border * 2; if( ( style & SWT.V_SCROLL ) != 0 ) { width += getVerticalBar().getSize().x; } if( ( style & SWT.H_SCROLL ) != 0 ) { height += getHorizontalBar().getSize().y; } return new Point( width, height ); } private void setCustomItemHeight( Object value ) { if( value == null ) { customItemHeight = -1; } else { if( !( value instanceof Integer ) ) { error( SWT.ERROR_INVALID_ARGUMENT ); } int itemHeight = ( ( Integer )value ).intValue(); if( itemHeight < 0 ) { error( SWT.ERROR_INVALID_RANGE ); } customItemHeight = itemHeight; } } ///////////////////// // item layout helper int getMaxContentWidth( TreeColumn column ) { return getMaxInnerWidth( items, indexOf( column ), 1, true ); } private int getMaxInnerWidth( TreeItem[] items, int columnIndex, int level, boolean clearBuffer ) { int maxInnerWidth = 0; for( int i = 0; i < items.length; i++ ) { TreeItem item = items[ i ]; if( item != null && item.isCached() ) { int indention = columnIndex == 0 ? level * getIndentionWidth() : 0; // TODO [tb] : test if( clearBuffer ) { item.clearPreferredWidthBuffers( false ); } int itemWidth = item.getPreferredWidth( columnIndex, false ) + indention; maxInnerWidth = Math.max( maxInnerWidth, itemWidth ); if( item.getExpanded() ) { int innerWidth = getMaxInnerWidth( item.items, columnIndex, level + 1, clearBuffer ); maxInnerWidth = Math.max( maxInnerWidth, innerWidth ); } } } return maxInnerWidth; } int getCellLeft( int index ) { return getColumnCount() == 0 ? 0 : getColumn( index ).getLeft(); } private int getCellWidth( int index ) { return getColumnCount() == 0 && index == 0 ? getMaxInnerWidth( items, 0, 1, false ) : getColumn( index ).getWidth(); } int getImageOffset( int index ) { // Note: The left cell-padding is visually ignored for the tree-column int result = isTreeColumn( index ) ? 0 : getCellPadding().x; if( hasCheckBoxes( index ) ) { result += getCheckImageOuterSize().x; } return result; } private int getTextOffset( int index ) { int result = getImageOffset( index ); result += getItemImageOuterWidth( index ); if( isTreeColumn( index ) ) { result += TEXT_MARGIN.x; } return result; } int getTextWidth( int index ) { Rectangle padding = getCellPadding(); int rightPadding = padding.width - padding.x; int result = getCellWidth( index ) - getTextOffset( index ) - rightPadding; if( isTreeColumn( index ) ) { result -= ( TEXT_MARGIN.width - TEXT_MARGIN.x ); } return Math.max( 0, result ); } int getIndentionOffset( TreeItem item ) { return getIndentionWidth() * ( item.depth + 1); } int getVisualCellLeft( int index, TreeItem item ) { int result = getCellLeft( index ) - getColumnLeftOffset( index ); if( isTreeColumn( index ) ) { result += getIndentionOffset( item ); } if( hasCheckBoxes( index ) ) { result += getCheckImageOuterSize().x; } return result; } int getVisualCellWidth( int index, TreeItem item ) { int result; if( getColumnCount() == 0 && index == 0 ) { String text = item.getText( 0 ); int textWidth = TextSizeUtil.stringExtent( item.getFont(), text ).x; result = getCellPadding().width + getItemImageOuterWidth( index ) + textWidth + TEXT_MARGIN.width; } else { result = getColumn( index ).getWidth(); if( isTreeColumn( index ) ) { result -= getIndentionOffset( item ); } if( hasCheckBoxes( index ) ) { result -= getCheckImageOuterSize().x; } result = Math.max( 0, result ); } return result; } int getVisualTextLeft( int index, TreeItem item ) { return getVisualCellLeft( index, item ) + getCellPadding().x + getItemImageOuterWidth( index ); } int getVisualTextWidth( int index, TreeItem item ) { int result = 0; if( index == 0 && getColumnCount() == 0 ) { result = TextSizeUtil.stringExtent( item.getFont(), item.getText( 0 ) ).x; result += TEXT_MARGIN.width; } else if( index >= 0 && index < getColumnCount() ) { result = getTextWidth( index ) - getIndentionOffset( item ); result = Math.max( 0, result ); } return result; } int getPreferredCellWidth( TreeItem item, int columnIndex, boolean checkData ) { int result = item.getPreferredWidthBuffer( columnIndex ); if( !item.hasPreferredWidthBuffer( columnIndex ) ) { result = getTextOffset( columnIndex ) ; Rectangle padding = getCellPadding(); result += TextSizeUtil.stringExtent( getFont(), item.getTextWithoutMaterialize( columnIndex ) ).x; result += padding.width - padding.x; if( isTreeColumn( columnIndex ) ) { result += TEXT_MARGIN.width - TEXT_MARGIN.x; } item.setPreferredWidthBuffer( columnIndex, result ); } return result; } boolean isTreeColumn( int index ) { return index == 0 && getColumnCount() == 0 || getColumnCount() > 0 && getColumnOrder()[ 0 ] == index; } /** * Returns the scroll-offset of the column, which is the leftOffset unless it is a fixed column. */ final int getColumnLeftOffset( int columnIndex ) { int result = scrollLeft; if( columnIndex >= 0 ) { result = isFixedColumn( columnIndex ) ? 0 : scrollLeft; } return result; } private boolean isFixedColumn( int index ) { int[] columnOrder = getColumnOrder(); int visualIndex = -1; for( int i = 0; i < columnOrder.length && visualIndex == -1; i++ ) { if( index == columnOrder[ i ] ) { visualIndex = i; } } return visualIndex < getFixedColumns(); } private int getFixedColumns() { int result = -1; try { Integer data = ( Integer )getData( RWT.FIXED_COLUMNS ); if( data != null ) { result = data.intValue(); } } catch( ClassCastException ex ) { // not a valid fixedColumns value } return result; } private boolean hasCheckBoxes( int index ) { return ( style & SWT.CHECK ) != 0 && isTreeColumn( index ); } private boolean hasColumnImages( int columnIndex ) { int count = columnIndex == 0 ? itemImageCount : getColumn( columnIndex ).itemImageCount; return count > 0; } void updateColumnImageCount( int columnIndex, Image oldImage, Image newImage ) { int delta = 0; if( oldImage == null && newImage != null ) { delta = +1; } else if( oldImage != null && newImage == null ) { delta = -1; } if( delta != 0 ) { if( columnIndex == 0 ) { itemImageCount += delta; } else { TreeColumn column = getColumn( columnIndex ); column.itemImageCount += delta; } } } void updateItemImageSize( Image image ) { if( image != null && itemImageSize == null ) { Rectangle imageBounds = image.getBounds(); itemImageSize = new Point( imageBounds.width, imageBounds.height ); layoutCache.invalidateItemHeight(); } } Point getItemImageSize( int index ) { Point result; if( hasColumnImages( index ) ) { result = getItemImageSize(); if( getColumnCount() > 0 ) { int availWidth = getColumn( index ).getWidth(); availWidth -= getCellPadding().x; availWidth = Math.max( 0, availWidth ); result.x = Math.min( result.x, availWidth ); } } else { result = new Point( 0, 0 ); } return result; } private int getItemImageOuterWidth( int index ) { int result = 0; if( hasColumnImages( index ) ) { result += getItemImageSize( index ).x; result += getCellSpacing(); } return result; } private Point getItemImageSize() { Point result = new Point( 0, 0 ); if( itemImageSize != null ) { result.x = itemImageSize.x; result.y = itemImageSize.y; } return result; } private Point getCheckImageSize() { return getThemeAdapter().getCheckBoxImageSize( this ); } private TreeThemeAdapter getThemeAdapter() { return ( TreeThemeAdapter )getAdapter( IThemeAdapter.class ); } private Point getCheckImageOuterSize() { Point result = getCheckImageSize(); Rectangle margin = getCheckBoxMargin(); result.x += margin.width; result.y += margin.height; return result; } private Rectangle getCheckBoxMargin() { if( !layoutCache.hasCheckBoxMargin() ) { layoutCache.checkBoxMargin = getThemeAdapter().getCheckBoxMargin( this ); } return layoutCache.checkBoxMargin; } private int getIndentionWidth() { return getThemeAdapter().getIndentionWidth( this ); } private int computeHeaderHeight() { int result = 0; if( headerVisible ) { Font headerFont = getHeaderFont(); int textHeight = TextSizeUtil.getCharHeight( headerFont ); int imageHeight = 0; for( int i = 0; i < getColumnCount(); i++ ) { TreeColumn column = columnHolder.getItem( i ); if( column.getText().contains( "\n" ) ) { int columnTextHeight = TextSizeUtil.textExtent( headerFont, column.getText(), 0 ).y; textHeight = Math.max( textHeight, columnTextHeight ); } Image image = getColumn( i ).getImage(); int height = image == null ? 0 : image.getBounds().height; if( height > imageHeight ) { imageHeight = height; } } result = Math.max( textHeight, imageHeight ); TreeThemeAdapter themeAdapter = getThemeAdapter(); result += themeAdapter.getHeaderBorderBottomWidth( this ); result += themeAdapter.getHeaderPadding( this ).height; } return result; } Font getHeaderFont() { IControlAdapter controlAdapter = getAdapter( IControlAdapter.class ); Font result = controlAdapter.getUserFont(); if( result == null ) { result = getThemeAdapter().getHeaderFont( this ); } return result; } private int computeItemHeight() { Rectangle padding = getCellPadding(); int textHeight = TextSizeUtil.getCharHeight( getFont() ); textHeight += TEXT_MARGIN.height + padding.height; int itemImageHeight = getItemImageSize().y + padding.height; int result = Math.max( itemImageHeight, textHeight ); if( hasCheckBoxes( 0 ) ) { result = Math.max( getCheckImageOuterSize().y, result ); } result += 1; // The space needed for horizontal gridline is always added, even if not visible result = Math.max( result, MIN_ITEM_HEIGHT ); return result; } /////////////////// // Helping methods @Override void notifyResize( Point oldSize ) { if( !oldSize.equals( getSize() ) && !TextSizeUtil.isTemporaryResize() ) { updateAllItems(); updateScrollBars(); adjustTopItemIndex(); } super.notifyResize( oldSize ); } private void adjustTopItemIndex() { int visibleRowCount = getVisibleRowCount( false ); int correction = visibleRowCount == 0 ? 1 : 0; if( topItemIndex > visibleItemsCount - visibleRowCount - correction ) { topItemIndex = Math.max( 0, visibleItemsCount - visibleRowCount - correction ); } } private int getVisibleRowCount( boolean includePartlyVisible ) { int clientHeight = getBounds().height - getHeaderHeight() - getHScrollBarHeight(); int result = 0; if( clientHeight >= 0 ) { int itemHeight = getItemHeight(); result = clientHeight / itemHeight; if( includePartlyVisible && clientHeight % itemHeight != 0 ) { result++; } } return result; } void updateAllItems() { int flatIndex = 0; for( int index = 0; index < itemCount; index++ ) { flatIndex = updateAllItemsRecursively( null, index, flatIndex ); } isFlatIndexValid = true; visibleItemsCount = flatIndex; } private int updateAllItemsRecursively( TreeItem parent, int index, int flatIndex ) { int newFlatIndex = flatIndex; TreeItem item = parent == null ? items[ index ] : parent.items[ index ]; if( isVirtual() && isItemVisible( flatIndex ) ) { if( item == null ) { item = parent == null ? _getItem( index ) : parent._getItem( index ); } checkData( item, index ); } if( item != null ) { item.setFlatIndex( newFlatIndex ); } newFlatIndex++; if( item != null && item.isCached() && item.getExpanded() ) { for( int i = 0; i < item.itemCount; i++ ) { newFlatIndex = updateAllItemsRecursively( item, i, newFlatIndex ); } } return newFlatIndex; } private boolean isItemVisible( int flatIndex ) { boolean result = false; int headerHeight = getHeaderHeight(); int itemHeight = getItemHeight(); int itemPosition = headerHeight + ( flatIndex - topItemIndex ) * itemHeight; // TODO shouldn't we call getClientArea() instead? if( itemPosition >= 0 && itemPosition <= getSize().y ) { result = true; } return result; } final boolean checkData( TreeItem item, int index ) { boolean result = true; if( isVirtual() && !item.isCached() ) { item.markCached(); Event event = new Event(); event.item = item; event.index = index; notifyListeners( SWT.SetData, event ); // widget could be disposed at this point if( isDisposed() || item.isDisposed() ) { result = false; } } return result; } private static int checkStyle( int style ) { int result = style; if( ( style & SWT.NO_SCROLL ) == 0 ) { result |= SWT.H_SCROLL | SWT.V_SCROLL; } return checkBits( result, SWT.SINGLE, SWT.MULTI, 0, 0, 0, 0 ); } Rectangle getCellPadding() { if( !layoutCache.hasCellPadding() ) { layoutCache.cellPadding = getThemeAdapter().getCellPadding( this ); } return layoutCache.cellPadding; } int getCellSpacing() { if( !layoutCache.hasCellSpacing() ) { layoutCache.cellSpacing = getThemeAdapter().getCellSpacing( this ); } return layoutCache.cellSpacing; } /////////////////////////////////////// // Helping methods - dynamic scrollbars boolean hasVScrollBar() { return hasVScrollBar; } boolean hasHScrollBar() { return hasHScrollBar; } @Override int getVScrollBarWidth() { int result = 0; if( hasVScrollBar() ) { result = getVerticalBar().getSize().x; } return result; } @Override int getHScrollBarHeight() { int result = 0; if( hasHScrollBar() ) { result = getHorizontalBar().getSize().y; } return result; } boolean needsVScrollBar() { int availableHeight = getClientArea().height; int height = getHeaderHeight(); height += itemCount * getItemHeight(); for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null && item.getExpanded() ) { height += item.getInnerHeight(); } } return height > availableHeight; } boolean needsHScrollBar() { boolean result = false; int availableWidth = getClientArea().width; int columnCount = getColumnCount(); if( columnCount > 0 ) { int totalWidth = 0; for( int i = 0; i < columnCount; i++ ) { TreeColumn column = getColumn( i ); totalWidth += column.getWidth(); } result = totalWidth > availableWidth; } else { int maxWidth = 0; for( int i = 0; i < itemCount; i++ ) { TreeItem item = items[ i ]; if( item != null && !item.isInDispose() && item.isCached() ) { int itemWidth = item.getPreferredWidth( 0, false ); maxWidth = Math.max( maxWidth, itemWidth ); if( item.getExpanded() ) { int innerWidth = getMaxInnerWidth( item.items, 0, 1, false ); maxWidth = Math.max( maxWidth, innerWidth ); } } } result = maxWidth > availableWidth; } return result; } void updateScrollBars() { if( ( style & SWT.NO_SCROLL ) == 0 ) { hasVScrollBar = false; hasHScrollBar = needsHScrollBar(); if( needsVScrollBar() ) { hasVScrollBar = true; hasHScrollBar = needsHScrollBar(); } getHorizontalBar().setVisible( hasHScrollBar ); getVerticalBar().setVisible( hasVScrollBar ); } } boolean isVirtual() { return ( style & SWT.VIRTUAL ) != 0; } void createItem( TreeItem item, int index ) { if( itemCount == items.length ) { /* * Grow the array faster when redraw is off or the table is not visible. * When the table is painted, the items array is resized to be smaller to * reduce memory usage. */ boolean small = /* drawCount == 0 && */isVisible(); int length = small ? items.length + 4 : Math.max( 4, items.length * 3 / 2 ); TreeItem[] newItems = new TreeItem[ length ]; System.arraycopy( items, 0, newItems, 0, items.length ); items = newItems; } System.arraycopy( items, index, items, index + 1, itemCount - index ); items[ index ] = item; itemCount++; adjustItemIndices( index ); } void destroyItem( TreeItem treeItem, int index ) { itemCount--; if( itemCount == 0 ) { setTreeEmpty(); } else { System.arraycopy( items, index + 1, items, index, itemCount - index ); items[ itemCount ] = null; } adjustItemIndices( index ); } private void adjustItemIndices( int start ) { for( int i = start; i < itemCount; i++ ) { if( items[ i ] != null ) { items[ i ].index = i; } } } /////////////////// // Skinning support @Override void reskinChildren( int flags ) { for( int i = 0; i < itemCount; i++ ) { if( items[ i ] != null ) { items[ i ].reskinChildren( flags ); } } TreeColumn[] columns = getColumns(); if( columns != null ) { for( int i = 0; i < columns.length; i++ ) { TreeColumn column = columns[ i ]; if( !column.isDisposed() ) { column.reskinChildren( flags ); } } } super.reskinChildren( flags ); } //////////////// // Inner classes private final class CompositeItemHolder implements IItemHolderAdapter { public void add( Item item ) { if( item instanceof TreeColumn ) { columnHolder.add( ( TreeColumn )item ); } else { String msg = "Only TreeColumns may be added to CompositeItemHolder"; throw new IllegalArgumentException( msg ); } } public void insert( Item item, int index ) { if( item instanceof TreeColumn ) { columnHolder.insert( ( TreeColumn )item, index ); } else { String msg = "Only TreeColumns may be inserted to CompositeItemHolder"; throw new IllegalArgumentException( msg ); } } public void remove( Item item ) { if( item instanceof TreeColumn ) { columnHolder.remove( ( TreeColumn )item ); } else { String msg = "Only TreeColumns may be removed from CompositeItemHolder"; throw new IllegalArgumentException( msg ); } } public Item[] getItems() { TreeItem[] items = getCreatedItems(); Item[] columns = columnHolder.getItems(); Item[] result = new Item[ columns.length + items.length ]; System.arraycopy( columns, 0, result, 0, columns.length ); System.arraycopy( items, 0, result, columns.length, items.length ); return result; } } private final class InternalTreeAdapter implements ITreeAdapter, ICellToolTipAdapter, SerializableCompatibility { private String toolTipText; private ICellToolTipProvider provider; public void checkData() { updateAllItems(); } public void setScrollLeft( int left ) { scrollLeft = left; } public int getScrollLeft() { return scrollLeft; } public boolean isCached( TreeItem item ) { return item.isCached(); } public Point getItemImageSize( int index ) { return Tree.this.getItemImageSize( index ); } public int getCellLeft( int index ) { return Tree.this.getCellLeft( index ); } public int getCellWidth( int index ) { return Tree.this.getCellWidth( index ); } public int getTextOffset( int index ) { return Tree.this.getTextOffset( index ); } public int getTextMaxWidth( int index ) { return getTextWidth( index ); } public int getCheckWidth() { return getCheckImageSize().x; } public int getImageOffset( int index ) { return Tree.this.getImageOffset( index ); } public int getIndentionWidth() { return Tree.this.getIndentionWidth(); } public int getCheckLeft() { return getCheckBoxMargin().x; } public Rectangle getTextMargin() { return TEXT_MARGIN; } public int getTopItemIndex() { return Tree.this.getTopItemIndex(); } public void setTopItemIndex( int index ) { Tree.this.setTopItemIndex( index ); } public int getColumnLeft( TreeColumn column ) { int index = Tree.this.indexOf( column ); return getColumn( index ).getLeft(); } public ICellToolTipProvider getCellToolTipProvider() { return provider; } public void setCellToolTipProvider( ICellToolTipProvider provider ) { this.provider = provider; } public String getCellToolTipText() { return toolTipText; } public void setCellToolTipText( String toolTipText ) { this.toolTipText = toolTipText; } public int getFixedColumns() { return Tree.this.getFixedColumns(); } public boolean isFixedColumn( TreeColumn column ) { return Tree.this.isFixedColumn( Tree.this.indexOf( column ) ); } } static final class LayoutCache implements SerializableCompatibility { private static final int UNKNOWN = -1; int headerHeight = UNKNOWN; int itemHeight = UNKNOWN; int cellSpacing = UNKNOWN; Rectangle cellPadding; Rectangle checkBoxMargin; public boolean hasHeaderHeight() { return headerHeight != UNKNOWN; } public void invalidateHeaderHeight() { headerHeight = UNKNOWN; } public boolean hasItemHeight() { return itemHeight != UNKNOWN; } public void invalidateItemHeight() { itemHeight = UNKNOWN; } public boolean hasCellSpacing() { return cellSpacing != UNKNOWN; } public void invalidateCellSpacing() { cellSpacing = UNKNOWN; } public boolean hasCellPadding() { return cellPadding != null; } public void invalidateCellPadding() { cellPadding = null; } public boolean hasCheckBoxMargin() { return checkBoxMargin != null; } public void invalidateCheckBoxMargin() { checkBoxMargin = null; } public void invalidateAll() { invalidateHeaderHeight(); invalidateItemHeight(); invalidateCellSpacing(); invalidateCellPadding(); invalidateCheckBoxMargin(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy