![JAR search and dependency download from the Maven repository](/logo.png)
org.eclipse.swt.widgets.TreeItem Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2002, 2019 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 static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
import static org.eclipse.swt.internal.widgets.MarkupValidator.isValidationDisabledFor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
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.IItemHolderAdapter;
import org.eclipse.swt.internal.widgets.ITreeItemAdapter;
import org.eclipse.swt.internal.widgets.IWidgetColorAdapter;
import org.eclipse.swt.internal.widgets.IWidgetFontAdapter;
import org.eclipse.swt.internal.widgets.MarkupValidator;
import org.eclipse.swt.internal.widgets.treeitemkit.TreeItemLCA;
/**
* Instances of this class represent a selectable user interface object that
* represents a hierarchy of tree items in a tree widget.
*
* - Styles:
* - (none)
* - Events:
* - (none)
*
*
* IMPORTANT: This class is not intended to be subclassed.
*
*
* @since 1.0
*/
public class TreeItem extends Item {
private final TreeItem parentItem;
final Tree parent;
TreeItem[] items;
int itemCount;
private transient ITreeItemAdapter treeItemAdapter;
int index;
private Data[] data;
private Font font;
private boolean expanded;
private boolean checked;
private Color background;
private Color foreground;
private boolean grayed;
int depth;
private boolean cached;
private int flatIndex;
/**
* Constructs a new instance of this class given its parent (which must be a
* Tree
or a TreeItem
) and a style value describing
* its behavior and appearance. The item is added to the end of the items
* maintained by its parent.
*
* 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 tree 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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public TreeItem( Tree parent, int style ) {
this( parent, null, style, parent == null ? 0 : parent.getItemCount(), true );
}
/**
* Constructs a new instance of this class given its parent (which must be a
* Tree
or a TreeItem
), a style value describing its
* behavior and appearance, and the index at which to place it in the items
* maintained by its parent.
*
* 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 tree control which will be the parent of the new instance
* (cannot be null)
* @param style the style of control to construct
* @param index the zero-relative index to store the receiver in its parent
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the parent is null
* - ERROR_INVALID_RANGE - if the index is not between 0 and
* the number of elements in the parent (inclusive)
*
* @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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public TreeItem( Tree parent, int style, int index ) {
this( parent, null, style, index, true );
}
/**
* Constructs a new instance of this class given its parent (which must be a
* Tree
or a TreeItem
) and a style value describing
* its behavior and appearance. The item is added to the end of the items
* maintained by its parent.
*
* 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 parentItem a tree 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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public TreeItem( TreeItem parentItem, int style ) {
this( parentItem == null ? null : parentItem.parent,
parentItem,
style,
parentItem == null ? 0 : parentItem.itemCount, true );
}
/**
* Constructs a new instance of this class given its parent (which must be a
* Tree
or a TreeItem
), a style value describing its
* behavior and appearance, and the index at which to place it in the items
* maintained by its parent.
*
* 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 parentItem a tree control which will be the parent of the new
* instance (cannot be null)
* @param style the style of control to construct
* @param index the zero-relative index to store the receiver in its parent
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the parent is null
* - ERROR_INVALID_RANGE - if the index is not between 0 and
* the number of elements in the parent (inclusive)
*
* @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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public TreeItem( TreeItem parentItem, int style, int index ) {
this( parentItem == null ? null : parentItem.parent, parentItem, style, index, true );
}
TreeItem( Tree parent, TreeItem parentItem, int style, int index, boolean create ) {
super( parent, style );
this.parent = parent;
this.parentItem = parentItem;
this.index = index;
if( parentItem != null ) {
depth = parentItem.depth + 1;
}
parent.invalidateFlatIndex();
setEmpty();
if( create ) {
int numberOfItems;
if( parentItem != null ) {
numberOfItems = parentItem.itemCount;
} else {
// If there is no parent item, get the next index of the tree
numberOfItems = parent.getItemCount();
}
// check range
if( index < 0 || index > numberOfItems ) {
error( SWT.ERROR_INVALID_RANGE );
}
if( parentItem != null ) {
parentItem.createItem( this, index );
} else {
parent.createItem( this, index );
}
parent.updateScrollBars();
}
}
private void setEmpty() {
items = new TreeItem[ 4 ];
}
private 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 );
}
private void destroyItem( int index ) {
itemCount--;
if( itemCount == 0 ) {
setEmpty();
} 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;
}
}
}
@Override
@SuppressWarnings("unchecked")
public T getAdapter( Class adapter ) {
if( adapter == IItemHolderAdapter.class ) {
return ( T )new CompositeItemHolder();
}
if( adapter == IWidgetFontAdapter.class
|| adapter == IWidgetColorAdapter.class
|| adapter == ITreeItemAdapter.class )
{
if( treeItemAdapter == null ) {
treeItemAdapter = new TreeItemAdapter();
}
return ( T )treeItemAdapter;
}
if( adapter == WidgetLCA.class ) {
return ( T )TreeItemLCA.INSTANCE;
}
return super.getAdapter( adapter );
}
//////////////////////////
// Parent/child relations
/**
* Returns the receiver's parent, which must be a Tree
.
*
* @return the receiver's parent
* @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 Tree getParent() {
checkWidget();
return parent;
}
/**
* 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 parentItem;
}
/////////////////
// Getter/Setter
/**
* Sets the expanded state of the receiver.
*
*
* @param expanded the new expanded 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 setExpanded( boolean expanded ) {
checkWidget();
if( this.expanded != expanded && ( !expanded || itemCount > 0 ) ) {
this.expanded = expanded;
if( !expanded ) {
updateSelection();
}
markCached();
parent.invalidateFlatIndex();
parent.updateScrollBars();
parent.updateAllItems();
}
}
/**
* Returns true
if the receiver is expanded, and false otherwise.
*
*
* @return the expanded 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 getExpanded() {
checkWidget();
return expanded;
}
/**
* Returns a rectangle describing the receiver's size and location relative to
* its parent.
*
* @return the receiver's bounding rectangle
* @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 Rectangle getBounds() {
return getBounds( 0 );
}
/**
* Returns a rectangle describing the receiver's size and location relative to
* its parent at a column in the tree.
*
* @param index the index that specifies the column
* @return the receiver's bounding column rectangle
* @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 Rectangle getBounds( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Rectangle result = new Rectangle( 0, 0, 0, 0 );
if( isVisible() && isValidColumn( index ) ) {
int left = parent.getVisualCellLeft( this, index );
int width = parent.getVisualCellWidth( this, index );
result = new Rectangle( left, getItemTop(), width, parent.getItemHeight() );
}
return result;
}
/**
* Returns the background color at the given column index in the receiver.
*
* @param index the column index
* @return the 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
*
*/
public Color getBackground( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Color result;
if( hasData( index ) && data[ index ].background != null ) {
result = data[ index ].background;
} else if( background == null ) {
result = parent.getBackground();
} else {
result = background;
}
return result;
}
/**
* Returns the font that the receiver will use to paint textual information
* for the specified cell in this item.
*
* @param index the column index
* @return the receiver's font
* @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 Font getFont( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Font result;
if( hasData( index ) && data[ index ].font != null ) {
result = data[ index ].font;
} else if( font == null ) {
result = parent.getFont();
} else {
result = font;
}
return result;
}
/**
* Returns the foreground color at the given column index in the receiver.
*
* @param index the column index
* @return the 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
*
*/
public Color getForeground( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Color result;
if( hasData( index ) && data[ index ].foreground != null ) {
result = data[ index ].foreground;
} else if( foreground == null ) {
result = parent.getForeground();
} else {
result = foreground;
}
return result;
}
/**
* Sets the background color at the given column index in the receiver to the
* color specified by the argument, or to the default system color for the
* item if the argument is null.
*
* @param index the column index
* @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
*
*/
public void setBackground( int index, Color color ) {
checkWidget();
if( color != null && color.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
int count = Math.max( 1, parent.getColumnCount() );
if( index >= 0 && index < count ) {
ensureData( index, count );
if( !equals( data[ index ].background, color ) ) {
data[ index ].background = color;
markCached();
parent.redraw();
}
}
}
/**
* Sets the font that the receiver will use to paint textual information for
* the specified cell in this item to the font specified by the argument, or
* to the default font for that kind of control if the argument is null.
*
* @param index the column index
* @param font the new font (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
*
*/
public void setFont( int index, Font font ) {
checkWidget();
if( font != null && font.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
int count = Math.max( 1, parent.getColumnCount() );
if( index >= 0 && index < count ) {
ensureData( index, count );
if( !equals( font, data[ index ].font ) ) {
data[ index ].font = font;
data[ index ].preferredWidthBuffer = Data.UNKNOWN_WIDTH;
markCached();
parent.redraw();
}
}
}
/**
* Sets the foreground color at the given column index in the receiver to the
* color specified by the argument, or to the default system color for the
* item if the argument is null.
*
* @param index the column index
* @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
*
*/
public void setForeground( int index, Color color ) {
checkWidget();
if( color != null && color.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
int count = Math.max( 1, parent.getColumnCount() );
if( index >= 0 && index < count ) {
ensureData( index, count );
if( !equals( data[ index ].foreground, color ) ) {
data[ index ].foreground = color;
markCached();
parent.redraw();
}
}
}
/**
* Sets the font that the receiver will use to paint textual information for
* this item to the font specified by the argument, or to the default font for
* that kind of control if the argument is null.
*
* @param font the new font (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
*
*/
public void setFont( Font font ) {
checkWidget();
if( font != null && font.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
if( !equals( this.font, font ) ) {
this.font = font;
markCached();
if( parent.getColumnCount() == 0 ) {
parent.updateScrollBars();
}
parent.redraw();
}
}
/**
* Returns the font that the receiver will use to paint textual information
* for this item.
*
* @return the receiver's font
* @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 Font getFont() {
checkWidget();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Font result;
if( font == null ) {
result = parent.getFont();
} else {
result = font;
}
return result;
}
/**
* Sets the receiver's background color to the color specified by the
* argument, or to the default system color for the item if the argument is
* null.
*
* @param value 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
*
*/
public void setBackground( Color value ) {
checkWidget();
if( value != null && value.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
if( !equals( background, value ) ) {
background = value;
markCached();
}
}
/**
* Returns the receiver's background color.
*
* @return the 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
*
*/
public Color getBackground() {
checkWidget();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Color result;
if( background == null ) {
result = parent.getBackground();
} else {
result = background;
}
return result;
}
/**
* Returns the foreground color that the receiver will use to draw.
*
* @return the receiver's 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
*
*/
public Color getForeground() {
checkWidget();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Color result;
if( foreground == null ) {
result = parent.getForeground();
} else {
result = foreground;
}
return result;
}
/**
* Sets the receiver's foreground color to the color specified by the
* argument, or to the default system color for the item if the argument is
* null.
*
* @param value 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
*
*/
public void setForeground( Color value ) {
checkWidget();
if( value != null && value.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
if( !equals( foreground, value ) ) {
foreground = value;
markCached();
}
}
/**
* Sets the checked state of the receiver.
*
*
* @param checked the new checked 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 setChecked( boolean checked ) {
checkWidget();
if( ( parent.getStyle() & SWT.CHECK ) != 0 ) {
if( this.checked != checked ) {
this.checked = checked;
markCached();
}
}
}
/**
* Returns true
if the receiver is checked, and false otherwise.
* When the parent does not have the CHECK style, return false.
*
*
* @return the checked 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 getChecked() {
checkWidget();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
return checked;
}
/**
* Sets the grayed state of the checkbox for this item. This state change only
* applies if the Tree was created with the SWT.CHECK style.
*
* @param grayed the new grayed state of the checkbox
* @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 setGrayed( boolean grayed ) {
checkWidget();
if( ( parent.getStyle() & SWT.CHECK ) != 0 ) {
if( this.grayed != grayed ) {
this.grayed = grayed;
markCached();
}
}
}
/**
* Returns true
if the receiver is grayed, and false otherwise.
* When the parent does not have the CHECK style, return false.
*
*
* @return the grayed state of the checkbox
* @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 getGrayed() {
checkWidget();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
return grayed;
}
/**
* Returns the receiver's text, which will be an empty string if it has never
* been set.
*
* @return the receiver's text
* @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
*
*/
@Override
public String getText() {
checkWidget();
return getText( 0 );
}
/**
* Returns the text stored at the given column index in the receiver, or empty
* string if the text has not been set.
*
* @param index the column index
* @return the text stored at the given column index 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 String getText( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
return getTextWithoutMaterialize( index );
}
String getTextWithoutMaterialize( int index ) {
String result = "";
if( hasData( index ) ) {
result = data[ index ].text;
}
return result;
}
/**
* Returns a rectangle describing the size and location
* relative to its parent of the text at a column in the
* tree.
*
* @param index the index that specifies the column
* @return the receiver's bounding text rectangle
*
* @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 Rectangle getTextBounds( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Rectangle result = new Rectangle( 0, 0, 0, 0 );
if( isVisible() && isValidColumn( index ) ) {
result.x = parent.getVisualTextLeft( this, index );
result.y = getItemTop();
result.width = parent.getVisualTextWidth( this, index );
result.height = parent.getItemHeight();
}
return result;
}
/**
* Sets the text for multiple columns in the tree.
*
* @param value the array of new strings
* @exception IllegalArgumentException - ERROR_NULL_ARGUMENT - if the
* text 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 void setText( String[] value ) {
checkWidget();
if( value == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
for( int i = 0; i < value.length; i++ ) {
if( value[ i ] != null ) {
setText( i, value[ i ] );
}
}
}
/**
* Sets the receiver's text.
*
* @param text the new text
* @exception IllegalArgumentException - ERROR_NULL_ARGUMENT - if the
* text 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
*
*/
@Override
public void setText( String text ) {
checkWidget();
setText( 0, text );
}
/**
* Sets the receiver's text at a column
*
* @param index the column index
* @param text the new text
* @exception IllegalArgumentException - ERROR_NULL_ARGUMENT - if the
* text 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 void setText( int index, String text ) {
checkWidget();
if( text == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
if( isMarkupEnabledFor( parent ) && !isValidationDisabledFor( parent ) ) {
MarkupValidator.getInstance().validate( text );
}
int count = Math.max( 1, parent.getColumnCount() );
if( index >= 0 && index < count ) {
ensureData( index, count );
if( !text.equals( data[ index ].text ) ) {
data[ index ].text = text;
data[ index ].preferredWidthBuffer = Data.UNKNOWN_WIDTH;
markCached();
if( parent.getColumnCount() == 0 ) {
parent.updateScrollBars();
}
parent.redraw();
}
}
}
/**
* Returns the receiver's image if it has one, or null
* if it does not.
*
* @return the receiver's image
*
* @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
*/
@Override
public Image getImage() {
checkWidget();
return getImage( 0 );
}
/**
* Returns the image stored at the given column index in the receiver, or null
* if the image has not been set or if the column does not exist.
*
* @param index the column index
* @return the image stored at the given column index 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 Image getImage( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Image result = null;
if( hasData( index ) ) {
result = data[ index ].image;
}
return result;
}
/**
* Returns a rectangle describing the size and location relative to its parent
* of an image at a column in the tree.
*
* @param index the index that specifies the column
* @return the receiver's bounding image rectangle
* @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 Rectangle getImageBounds( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
Rectangle result = null;
int validColumnCount = Math.max( 1, parent.columnHolder.size() );
if( ( 0 <= index && index < validColumnCount ) ) {
result = new Rectangle( 0, 0, 0, 0 );
Point size = parent.getItemImageSize( index );
result.width = size.x;
result.height = size.y;
result.x = parent.getVisualCellLeft( this, index );
// Note: The left cell-padding is visually ignored for the tree-column
if( !parent.isTreeColumn( index ) ) {
result.x += parent.getCellPadding().left;
}
// SWT behavior on windows gives the correct y value
// On Gtk the y value is always the same (eg. 1)
// we emulate the default windows behavior here
result.y = getItemTop();
} else {
result = new Rectangle( 0, 0, 0, 0 );
}
return result;
}
void clear() {
data = null;
checked = false;
grayed = false;
foreground = null;
background = null;
font = null;
clearCached();
parent.updateScrollBars();
}
/**
* 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 );
}
if( parent.isVirtual() ) {
parent.redraw();
}
}
}
@Override
public void setImage( Image image ) {
checkWidget();
setImage( 0, image );
}
/**
* Sets the receiver's image at a column.
*
* @param index the column index
* @param image the new image
* @exception IllegalArgumentException
* - ERROR_INVALID_ARGUMENT - if the image 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 setImage( int index, Image image ) {
checkWidget();
if( image != null && image.isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
int count = Math.max( 1, parent.getColumnCount() );
if( index >= 0 && index < count ) {
ensureData( index, count );
if( !equals( data[ index ].image, image ) ) {
parent.updateColumnImageCount( index, data[ index ].image, image );
data[ index ].image = image;
data[ index ].preferredWidthBuffer = Data.UNKNOWN_WIDTH;
parent.updateItemImageSize( image );
markCached();
if( parent.getColumnCount() == 0 ) {
parent.updateScrollBars();
}
parent.redraw();
}
}
}
/**
* Sets the image for multiple columns in the tree.
*
* @param value the array of new images
* @exception IllegalArgumentException
* - ERROR_NULL_ARGUMENT - if the array of images is null
* - ERROR_INVALID_ARGUMENT - if one of the images 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 setImage( Image[] value ) {
checkWidget();
if( value == null ) {
error( SWT.ERROR_NULL_ARGUMENT );
}
for( int i = 0; i < value.length; i++ ) {
if( value[ i ] != null && value[ i ].isDisposed() ) {
error( SWT.ERROR_INVALID_ARGUMENT );
}
}
for( int i = 0; i < value.length; i++ ) {
if( value[ i ] != null ) {
setImage( i, value[ i ] );
}
}
}
/**
* 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 ) {
clearAll( recursive, true );
}
void clearAll( boolean recursive, boolean doVisualUpdate ) {
checkWidget();
for( int i = 0; i < itemCount; i++ ) {
TreeItem item = items[ i ];
if( item != null ) {
item.clear();
if( recursive ) {
item.clearAll( true, false );
}
}
}
if( parent.isVirtual() && doVisualUpdate ) {
parent.redraw();
}
}
////////////////////////////////////////
// Methods to maintain (sub-) TreeItems
/**
* Returns a (possibly empty) array of TreeItem
s which are the
* direct item children of the receiver.
*
* 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 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
*
*/
public TreeItem[] getItems() {
checkWidget();
TreeItem[] result = new TreeItem[ itemCount ];
if( parent.isVirtual() ) {
for( int i = 0; i < itemCount; i++ ) {
result[ i ] = _getItem( i );
}
} else {
System.arraycopy( items, 0, result, 0, itemCount );
}
return result;
}
TreeItem _getItem( int index ) {
if( parent.isVirtual() && items[ index ] == null ) {
items[ index ] = new TreeItem( parent, this, SWT.NONE, index, false );
}
return items[ index ];
}
TreeItem[] getCreatedItems() {
TreeItem[] result;
if( parent.isVirtual() ) {
int count = 0;
for( int i = 0; i < itemCount; i++ ) {
if( items[ i ] != null ) {
count++;
}
}
result = new TreeItem[ count ];
count = 0;
for( int i = 0; i < itemCount; i++ ) {
if( items[ i ] != null ) {
result[ count ] = items[ i ];
count++;
}
}
} else {
result = new TreeItem[ itemCount ];
System.arraycopy( items, 0, result, 0, itemCount );
}
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
*
*/
public TreeItem getItem( int index ) {
checkWidget();
if( !parent.checkData( this, this.index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
if( index < 0 || index >= itemCount ) {
SWT.error( SWT.ERROR_INVALID_RANGE );
}
return _getItem( index );
}
/**
* Returns the number of items contained in the receiver that are direct item
* children of the receiver.
*
* @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();
if( !parent.checkData( this, index ) ) {
error( SWT.ERROR_WIDGET_DISPOSED );
}
return itemCount;
}
/**
* 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.parentItem == this ? item.index : -1;
}
/**
* 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--;
}
}
setEmpty();
}
/**
* Sets the number of child 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 index = oldItemCount - 1;
while( index >= newItemCount ) {
TreeItem item = items[ index ];
if( item != null && !item.isDisposed() ) {
item.dispose();
}
index--;
}
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( !parent.isVirtual() ) {
for( int i = oldItemCount; i < newItemCount; i++ ) {
new TreeItem( this, SWT.NONE, i );
}
}
itemCount = newItemCount;
parent.invalidateFlatIndex();
parent.updateScrollBars();
parent.redraw();
}
}
/////////////////////////////////
// Methods to dispose of the item
@Override
final void releaseChildren() {
for( int i = items.length - 1; i >= 0; i-- ) {
if( items[ i ] != null ) {
items[ i ].dispose();
}
}
}
@Override
final void releaseParent() {
if( parentItem != null ) {
parentItem.destroyItem( index );
} else {
parent.destroyItem( index );
}
if( !parent.isInDispose() ) {
parent.invalidateFlatIndex();
parent.removeFromSelection( this );
parent.updateScrollBars();
}
super.releaseParent();
}
//////////////////
// helping methods
private boolean isValidColumn( int index ) {
int columnCount = parent.getColumnCount();
return ( columnCount == 0 && index == 0 ) || ( index >= 0 && index < columnCount );
}
private boolean isVisible() {
return getParentItem() == null || getParentItem().getExpanded();
}
int getItemTop() {
int headerHeight = parent.getHeaderHeight();
int itemHeight = parent.getItemHeight();
return headerHeight + ( getFlatIndex() - parent.getTopItemIndex() ) * itemHeight;
}
int getFlatIndex() {
if( !parent.isFlatIndexValid ) {
parent.updateAllItems();
}
return flatIndex;
}
void setFlatIndex( int flatIndex ) {
this.flatIndex = flatIndex;
}
boolean hasPreferredWidthBuffer( int index ) {
return getPreferredWidthBuffer( index ) != Data.UNKNOWN_WIDTH;
}
int getPreferredWidthBuffer( int index ) {
int result = Data.UNKNOWN_WIDTH;
if( hasData( index ) ) {
result = data[ index ].preferredWidthBuffer;
}
return result;
}
void setPreferredWidthBuffer( int index, int preferredWidthBuffer ) {
int count = Math.max( 1, parent.getColumnCount() );
ensureData( index, count );
data[ index ].preferredWidthBuffer = preferredWidthBuffer;
}
void clearPreferredWidthBuffers( boolean recursive ) {
int count = Math.max( 1, parent.getColumnCount() );
for( int i = 0; i < count; i++ ) {
if( hasData( i ) ) {
data[ i ].preferredWidthBuffer = Data.UNKNOWN_WIDTH;
}
}
if( recursive && expanded ) {
for( int i = 0; i < itemCount; i++ ) {
TreeItem item = items[ i ];
if( item != null ) {
item.clearPreferredWidthBuffers( recursive );
}
}
}
}
int getInnerHeight() {
int innerHeight = itemCount * parent.getItemHeight();
for( int i = 0; i < itemCount; i++ ) {
TreeItem item = items[ i ];
if( item != null && item.getExpanded() ) {
innerHeight += item.getInnerHeight();
}
}
return innerHeight;
}
void markCached() {
if( parent.isVirtual() ) {
cached = true;
}
}
private void clearCached() {
if( parent.isVirtual() ) {
cached = false;
}
}
boolean isCached() {
return parent.isVirtual() ? cached : true;
}
private static boolean equals( Object object1, Object object2 ) {
boolean result;
if( object1 == object2 ) {
result = true;
} else if( object1 == null ) {
result = false;
} else {
result = object1.equals( object2 );
}
return result;
}
////////////////////////////////////////
// Manage item data (texts, images, etc)
private void ensureData( int index, int columnCount ) {
if( data == null ) {
data = new Data[ columnCount ];
} else if( data.length < columnCount ) {
Data[] newData = new Data[ columnCount ];
System.arraycopy( data, 0, newData, 0, data.length );
data = newData;
}
if( data[ index ] == null ) {
data[ index ] = new Data();
}
}
private boolean hasData( int index ) {
return data != null && index >= 0 && index < data.length && data[ index ] != null;
}
final void shiftData( int index ) {
if( data != null && data.length > index && parent.getColumnCount() > 1 ) {
Data[] newData = new Data[ data.length + 1 ];
System.arraycopy( data, 0, newData, 0, index );
int offSet = data.length - index;
System.arraycopy( data, index, newData, index + 1, offSet );
data = newData;
}
for( int i = 0; i < itemCount; i++ ) {
if( items[ i ] != null ) {
items[ i ].shiftData( index );
}
}
}
final void removeData( int index ) {
if( data != null && data.length > index && parent.getColumnCount() > 1 ) {
Data[] newData = new Data[ data.length - 1 ];
System.arraycopy( data, 0, newData, 0, index );
int offSet = data.length - index - 1;
System.arraycopy( data, index + 1, newData, index, offSet );
data = newData;
}
for( int i = 0; i < itemCount; i++ ) {
if( items[ i ] != null ) {
items[ i ].removeData( index );
}
}
}
private void updateSelection() {
TreeItem[] selection = parent.getSelection();
List selectedItems = new ArrayList<>( Arrays.asList( selection ) );
if( deselectChildren( selectedItems ) ) {
if( ( parent.getStyle() & SWT.SINGLE ) != 0 ) {
selectedItems.add( this );
}
parent.setSelection( selectedItems.toArray( new TreeItem[ 0 ] ) );
Event event = new Event();
event.item = this;
parent.notifyListeners( SWT.Selection, event );
}
}
boolean deselectChildren( List selectedItems ) {
boolean result = false;
for( int i = 0; i < itemCount; i++ ) {
TreeItem item = items[ i ];
if( item != null ) {
if( selectedItems.contains( item ) ) {
selectedItems.remove( item );
result = true;
}
if( item.deselectChildren( selectedItems ) ) {
result = true;
}
}
}
return result;
}
////////////////
// Inner classes
private final class TreeItemAdapter
implements ITreeItemAdapter, IWidgetFontAdapter, IWidgetColorAdapter
{
@Override
public boolean isParentDisposed() {
Widget itemParent = parentItem == null ? parent : parentItem;
return itemParent.isDisposed();
}
@Override
public Color getUserBackground() {
return background;
}
@Override
public Color getUserForeground() {
return foreground;
}
@Override
public Font getUserFont() {
return font;
}
@Override
public String[] getTexts() {
int columnCount = Math.max( 1, getParent().getColumnCount() );
String[] result = null;
if( data != null ) {
for( int i = 0; i < data.length; i++ ) {
String text = data[ i ] == null ? "" : data[ i ].text;
if( !"".equals( text ) ) {
if( result == null ) {
result = new String[ columnCount ];
Arrays.fill( result, "" );
}
result[ i ] = text;
}
}
}
return result;
}
@Override
public Image[] getImages() {
int columnCount = Math.max( 1, getParent().getColumnCount() );
Image[] result = null;
if( data != null ) {
for( int i = 0; i < data.length; i++ ) {
Image image = data[ i ] == null ? null : data[ i ].image;
if( image != null ) {
if( result == null ) {
result = new Image[ columnCount ];
}
result[ i ] = image;
}
}
}
return result;
}
@Override
public Color[] getCellBackgrounds() {
int columnCount = Math.max( 1, getParent().getColumnCount() );
Color[] result = null;
if( data != null ) {
for( int i = 0; i < data.length; i++ ) {
Color background = data[ i ] == null ? null : data[ i ].background;
if( background != null ) {
if( result == null ) {
result = new Color[ columnCount ];
}
result[ i ] = background;
}
}
}
return result;
}
@Override
public Color[] getCellForegrounds() {
int columnCount = Math.max( 1, getParent().getColumnCount() );
Color[] result = null;
if( data != null ) {
for( int i = 0; i < data.length; i++ ) {
Color foreground = data[ i ] == null ? null : data[ i ].foreground;
if( foreground != null ) {
if( result == null ) {
result = new Color[ columnCount ];
}
result[ i ] = foreground;
}
}
}
return result;
}
@Override
public Font[] getCellFonts() {
int columnCount = Math.max( 1, getParent().getColumnCount() );
Font[] result = null;
if( data != null ) {
for( int i = 0; i < data.length; i++ ) {
Font font = data[ i ] == null ? null : data[ i ].font;
if( font != null ) {
if( result == null ) {
result = new Font[ columnCount ];
}
result[ i ] = font;
}
}
}
return result;
}
}
private final class CompositeItemHolder implements IItemHolderAdapter- {
@Override
public void add( Item item ) {
throw new UnsupportedOperationException();
}
@Override
public void insert( Item item, int index ) {
throw new UnsupportedOperationException();
}
@Override
public void remove( Item item ) {
throw new UnsupportedOperationException();
}
@Override
public Item[] getItems() {
TreeItem[] items = getCreatedItems();
Item[] result = new Item[ items.length ];
System.arraycopy( items, 0, result, 0, items.length );
return result;
}
}
private static final class Data implements SerializableCompatibility {
static final int UNKNOWN_WIDTH = -1;
String text = "";
// Note [fappel]: Yourkit analysis with the UI workbench testsuite showed an extensive
// appearance of preferred width calculations. Buffering the preferred width
// speeds up the suite on my machine to 1/4th of the time needed without buffering.
int preferredWidthBuffer = UNKNOWN_WIDTH;
Image image;
Font font;
Color background;
Color foreground;
}
}