SWT Table Tree
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TypedListener;
/**
*
* A TableTree is a selectable user interface object
*
* that displays a hierarchy of items, and issues
*
* notification when an item is selected.
*
* A TableTree may be single or multi select.
*
* <p>
*
* The item children that may be added to instances of this class
*
* must be of type <code>TableTreeItem</code>.
*
* </p>
* <p>
*
* Note that although this class is a subclass of <code>Composite</code>,
*
* it does not make sense to add <code>Control</code> children to it,
*
* or set a layout on it.
*
* </p>
* <p>
*
* <dl>
*
* <dt><b>Styles: </b>
* <dd>SINGLE, MULTI, CHECK, FULL_SELECTION
*
* <dt><b>Events: </b>
* <dd>Selection, DefaultSelection, Collapse, Expand
*
* </dl>
*
*/
public class TableTree extends Composite {
Table table;
TableTreeItem[] items = EMPTY_ITEMS;
Image plusImage, minusImage, sizeImage;
/*
*
* TableTreeItems are not treated as children but rather as items.
*
* When the TableTree is disposed, all children are disposed because
*
* TableTree inherits this behaviour from Composite. The items
*
* must be disposed separately. Because TableTree is not part of
*
* the org.eclipse.swt.widgets package, the method releaseWidget can
*
* not be overriden (this is how items are disposed of in Table and Tree).
*
* Instead, the items are disposed of in response to the dispose event on
* the
*
* TableTree. The "inDispose" flag is used to distinguish between disposing
*
* one TableTreeItem (e.g. when removing an entry from the TableTree) and
*
* disposing the entire TableTree.
*
*/
boolean inDispose = false;
static final TableTreeItem[] EMPTY_ITEMS = new TableTreeItem[0];
static final String[] EMPTY_TEXTS = new String[0];
static final Image[] EMPTY_IMAGES = new Image[0];
/**
*
* Creates a new instance of the widget.
*
*
*
* @param parent
* a composite widget
*
* @param style
* the bitwise OR'ing of widget styles
*
*/
public TableTree(Composite parent, int style) {
super(parent, SWT.NONE);
table = new Table(this, style);
setBackground(table.getBackground());
setForeground(table.getForeground());
setFont(table.getFont());
table.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
onMouseDown(e);
}
});
table.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
onSelection(e);
}
});
table.addListener(SWT.DefaultSelection, new Listener() {
public void handleEvent(Event e) {
onSelection(e);
}
});
addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event e) {
onDispose();
}
});
addListener(SWT.Resize, new Listener() {
public void handleEvent(Event e) {
onResize();
}
});
addListener(SWT.FocusIn, new Listener() {
public void handleEvent(Event e) {
onFocusIn();
}
});
}
int addItem(TableTreeItem item, int index) {
if (index < 0 || index > items.length)
throw new SWTError(SWT.ERROR_INVALID_ARGUMENT);
TableTreeItem[] newItems = new TableTreeItem[items.length + 1];
System.arraycopy(items, 0, newItems, 0, index);
newItems[index] = item;
System.arraycopy(items, index, newItems, index + 1, items.length
- index);
items = newItems;
/* Return the index in the table where this table should be inserted */
if (index == items.length - 1)
return table.getItemCount();
else
return table.indexOf(items[index + 1].tableItem);
}
/**
*
* Adds the listener to receive selection events.
*
* <p>
*
*
*
* @param listener
* the selection listener
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when listener is null
*
* </ul>
*
*/
public void addSelectionListener(SelectionListener listener) {
if (listener == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection, typedListener);
addListener(SWT.DefaultSelection, typedListener);
}
/**
*
* Adds the listener to receive tree events.
*
* <p>
*
*
*
* @param listener
* the tree listener
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when listener is null
*
* </ul>
*
*/
public void addTreeListener(TreeListener listener) {
if (listener == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Expand, typedListener);
addListener(SWT.Collapse, typedListener);
}
/**
*
* Computes the preferred size of the widget.
*
* <p>
*
* Calculate the preferred size of the widget based
*
* on the current contents. The hint arguments allow
*
* a specific client area width and/or height to be
*
* requested. The hints may be honored depending on
*
* the platform and the layout.
*
*
*
* @param wHint
* the width hint (can be SWT.DEFAULT)
*
* @param hHint
* the height hint (can be SWT.DEFAULT)
*
* @return a point containing the preferred size of the widget including
* trim
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public Point computeSize(int wHint, int hHint) {
return table.computeSize(wHint, hHint, true);
}
/**
*
* Computes the widget trim.
*
* <p>
*
* Trim is widget specific and may include scroll
*
* bars and menu bar in addition to other trimmings
*
* that are outside of the widget's client area.
*
*
*
* @param x
* the x location of the client area
*
* @param y
* the y location of the client area
*
* @param width
* the width of the client area
*
* @param height
* the height of the client area
*
* @return a rectangle containing the trim of the widget.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public Rectangle computeTrim(int x, int y, int width, int height) {
return table.computeTrim(x, y, width, height);
}
/**
*
* Deselects all items.
*
* <p>
*
* If an item is selected, it is deselected.
*
* If an item is not selected, it remains unselected.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* </ul>
*
*/
public void deselectAll() {
table.deselectAll();
}
/* Expand upward from the specified leaf item. */
void expandItem(TableTreeItem item) {
if (item == null || item.getExpanded())
return;
expandItem(item.parentItem);
item.setExpanded(true);
Event event = new Event();
event.item = item;
notifyListeners(SWT.Expand, event);
}
/**
*
* Gets the number of items.
*
* <p>
*
* @return the number of items in the widget
*
*/
public int getItemCount() {
return items.length;
}
/**
*
* Gets the height of one item.
*
* <p>
*
* This operation will fail if the height of
*
* one item could not be queried from the OS.
*
*
*
* @return the height of one item in the widget
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_CANNOT_GET_ITEM_HEIGHT when the operation fails
*
* </ul>
*
*/
public int getItemHeight() {
return table.getItemHeight();
}
/**
*
* Gets the items.
*
* <p>
*
* @return the items in the widget
*
*
*
*/
public TableTreeItem[] getItems() {
TableTreeItem[] newItems = new TableTreeItem[items.length];
System.arraycopy(items, 0, newItems, 0, items.length);
return newItems;
}
/**
*
* Gets the selected items.
*
* <p>
*
* This operation will fail if the selected
*
* items cannot be queried from the OS.
*
*
*
* @return the selected items in the widget
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_CANNOT_GET_SELECTION when the operation fails</li>
*
* </ul>
*
*/
public TableTreeItem[] getSelection() {
TableItem[] selection = table.getSelection();
TableTreeItem[] result = new TableTreeItem[selection.length];
for (int i = 0; i < selection.length; i++) {
result[i] = (TableTreeItem) selection[i].getData();
}
return result;
}
/**
*
* Gets the number of selected items.
*
* <p>
*
* This operation will fail if the number of selected
*
* items cannot be queried from the OS.
*
*
*
* @return the number of selected items in the widget
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_CANNOT_GET_COUNT when the operation fails</li>
*
* </ul>
*
*/
public int getSelectionCount() {
return table.getSelectionCount();
}
/**
*
* Returns the underlying Table control.
*
*
*
* @return the underlying Table control
*
*/
public Table getTable() {
return table;
}
void createImages() {
int itemHeight = sizeImage.getBounds().height;
// Calculate border around image.
// At least 9 pixels are needed to draw the image
// Leave at least a 6 pixel border.
int indent = Math.min(6, (itemHeight - 9) / 2);
indent = Math.max(0, indent);
int size = Math.max(10, itemHeight - 2 * indent);
size = ((size + 1) / 2) * 2; // size must be an even number
int midpoint = indent + size / 2;
Color foreground = getForeground();
Color plusMinus = getDisplay().getSystemColor(
SWT.COLOR_WIDGET_NORMAL_SHADOW);
Color background = getBackground();
/* Plus image */
PaletteData palette = new PaletteData(new RGB[] { foreground.getRGB(),
background.getRGB(), plusMinus.getRGB() });
ImageData imageData = new ImageData(itemHeight, itemHeight, 4, palette);
imageData.transparentPixel = 1;
plusImage = new Image(getDisplay(), imageData);
GC gc = new GC(plusImage);
gc.setBackground(background);
gc.fillRectangle(0, 0, itemHeight, itemHeight);
gc.setForeground(plusMinus);
gc.drawRectangle(indent, indent, size, size);
gc.setForeground(foreground);
gc.drawLine(midpoint, indent + 2, midpoint, indent + size - 2);
gc.drawLine(indent + 2, midpoint, indent + size - 2, midpoint);
gc.dispose();
/* Minus image */
palette = new PaletteData(new RGB[] { foreground.getRGB(),
background.getRGB(), plusMinus.getRGB() });
imageData = new ImageData(itemHeight, itemHeight, 4, palette);
imageData.transparentPixel = 1;
minusImage = new Image(getDisplay(), imageData);
gc = new GC(minusImage);
gc.setBackground(background);
gc.fillRectangle(0, 0, itemHeight, itemHeight);
gc.setForeground(plusMinus);
gc.drawRectangle(indent, indent, size, size);
gc.setForeground(foreground);
gc.drawLine(indent + 2, midpoint, indent + size - 2, midpoint);
gc.dispose();
}
Image getPlusImage() {
if (plusImage == null)
createImages();
return plusImage;
}
Image getMinusImage() {
if (minusImage == null)
createImages();
return minusImage;
}
/**
*
* Gets the index of an item.
*
*
*
* <p>
* The widget is searched starting at 0 until an
*
* item is found that is equal to the search item.
*
* If no item is found, -1 is returned. Indexing
*
* is zero based. This index is relative to the parent only.
*
*
*
* @param item
* the search item
*
* @return the index of the item or -1
*
*
*
*/
public int indexOf(TableTreeItem item) {
for (int i = 0; i < items.length; i++) {
if (item == items[i])
return i;
}
return -1;
}
void onDispose() {
inDispose = true;
for (int i = 0; i < items.length; i++) {
items[i].dispose();
}
inDispose = false;
if (plusImage != null)
plusImage.dispose();
if (minusImage != null)
minusImage.dispose();
if (sizeImage != null)
sizeImage.dispose();
plusImage = minusImage = sizeImage = null;
}
void onResize() {
Rectangle area = getClientArea();
table.setBounds(0, 0, area.width, area.height);
}
void onSelection(Event e) {
Event event = new Event();
TableItem tableItem = (TableItem) e.item;
TableTreeItem item = getItem(tableItem);
event.item = item;
if (e.type == SWT.Selection
&& e.detail == SWT.CHECK
&& item != null) {
event.detail = SWT.CHECK;
item.checked = tableItem.getChecked();
}
notifyListeners(e.type, event);
}
public TableTreeItem getItem(Point point) {
TableItem item = table.getItem(point);
if (item == null)
return null;
return getItem(item);
}
TableTreeItem getItem(TableItem tableItem) {
if (tableItem == null)
return null;
for (int i = 0; i < items.length; i++) {
TableTreeItem item = items[i].getItem(tableItem);
if (item != null)
return item;
}
return null;
}
void onFocusIn() {
table.setFocus();
}
void onMouseDown(Event event) {
/* If user clicked on the [+] or [-], expand or collapse the tree. */
TableItem[] items = table.getItems();
for (int i = 0; i < items.length; i++) {
Rectangle rect = items[i].getImageBounds(0);
if (rect.contains(event.x, event.y)) {
TableTreeItem item = (TableTreeItem) items[i].getData();
event = new Event();
event.item = item;
item.setExpanded(!item.getExpanded());
if (item.getExpanded()) {
notifyListeners(SWT.Expand, event);
} else {
notifyListeners(SWT.Collapse, event);
}
return;
}
}
}
/**
*
* Removes all items.
*
* <p>
*
* This operation will fail when an item
*
* could not be removed in the OS.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_ITEM_NOT_REMOVED when the operation fails
*
* </ul>
*
*/
public void removeAll() {
setRedraw(false);
for (int i = items.length - 1; i >= 0; i--) {
items[i].dispose();
}
items = EMPTY_ITEMS;
setRedraw(true);
}
void removeItem(TableTreeItem item) {
int index = 0;
while (index < items.length && items[index] != item)
index++;
if (index == items.length)
return;
TableTreeItem[] newItems = new TableTreeItem[items.length - 1];
System.arraycopy(items, 0, newItems, 0, index);
System.arraycopy(items, index + 1, newItems, index, items.length
- index - 1);
items = newItems;
}
/**
*
* Removes the listener.
*
* <p>
*
*
*
* @param listener
* the listener
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when listener is null
*
* </ul>
*
*/
public void removeSelectionListener(SelectionListener listener) {
if (listener == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
removeListener(SWT.Selection, listener);
removeListener(SWT.DefaultSelection, listener);
}
/**
*
* Removes the listener.
*
*
*
* @param listener
* the listener
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when listener is null
*
* </ul>
*
*/
public void removeTreeListener(TreeListener listener) {
if (listener == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
removeListener(SWT.Expand, listener);
removeListener(SWT.Collapse, listener);
}
/**
*
* Selects all items.
*
* <p>
*
* If an item is not selected, it is selected.
*
* If an item is selected, it remains selected.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* </ul>
*
*/
public void selectAll() {
table.selectAll();
}
/**
*
* Sets the widget background color.
*
* <p>
*
* When new color is null, the background reverts
*
* to the default system color for the widget.
*
*
*
* @param color
* the new color (or null)
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setBackground(Color color) {
super.setBackground(color);
table.setBackground(color);
if (sizeImage != null) {
GC gc = new GC(sizeImage);
gc.setBackground(getBackground());
Rectangle size = sizeImage.getBounds();
gc.fillRectangle(size);
gc.dispose();
}
}
/**
*
* Sets the enabled state.
*
* <p>
*
* A disabled widget is typically not selectable from
*
* the user interface and draws with an inactive or
*
* grayed look.
*
*
*
* @param enabled
* the new enabled state
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
table.setEnabled(enabled);
}
/**
*
* Sets the widget font.
*
* <p>
*
* When new font is null, the font reverts
*
* to the default system font for the widget.
*
*
*
* @param font
* the new font (or null)
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setFont(Font font) {
super.setFont(font);
table.setFont(font);
}
/**
*
* Gets the widget foreground color.
*
* <p>
*
* @return the widget foreground color
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setForeground(Color color) {
super.setForeground(color);
table.setForeground(color);
}
/**
*
* Sets the pop up menu.
*
* <p>
*
* Every control has an optional pop up menu that is
*
* displayed when the user requests a popup menu for
*
* the control. The sequence of key strokes/button
*
* presses/button releases that is used to request
*
* a pop up menu is platform specific.
*
*
*
* @param menu
* the new pop up menu
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_MENU_NOT_POP_UP when the menu is not a POP_UP</li>
*
* <li>ERROR_NO_COMMON_PARENT when the menu is not in the same widget tree
* </li>
*
* </ul>
*
*/
public void setMenu(Menu menu) {
super.setMenu(menu);
table.setMenu(menu);
}
/**
*
* Sets the selection.
*
* <p>
*
* @param items
* new selection
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when items is null
*
* </ul>
*
*/
public void setSelection(TableTreeItem[] items) {
TableItem[] tableItems = new TableItem[items.length];
for (int i = 0; i < items.length; i++) {
if (items[i] == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
if (!items[i].getVisible())
expandItem(items[i]);
tableItems[i] = items[i].tableItem;
}
table.setSelection(tableItems);
}
/**
*
* Sets the tool tip text.
*
* <p>
*
* @param string
* the new tool tip text (or null)
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setToolTipText(String string) {
super.setToolTipText(string);
table.setToolTipText(string);
}
/**
*
* Shows the item.
*
* <p>
*
* @param item
* the item to be shown
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* <li>ERROR_NULL_ARGUMENT when item is null
*
* </ul>
*
*/
public void showItem(TableTreeItem item) {
if (item == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
if (!item.getVisible())
expandItem(item);
TableItem tableItem = item.tableItem;
table.showItem(tableItem);
}
/**
*
* Shows the selection.
*
* <p>
*
* If there is no selection or the selection
*
* is already visible, this method does nothing.
*
* If the selection is scrolled out of view,
*
* the top index of the widget is changed such
*
* that selection becomes visible.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed
*
* </ul>
*
*/
public void showSelection() {
table.showSelection();
}
}
//TableTreeItem
/*
*
* (c) Copyright IBM Corp. 2000, 2001.
*
* All Rights Reserved
*
*/
/**
*
* A TableTreeItem is a selectable user interface object
*
* that represents an item in a heirarchy of items in a
*
* TableTree.
*
*/
class TableTreeItem extends Item {
TableItem tableItem;
TableTree parent;
TableTreeItem parentItem;
TableTreeItem[] items = TableTree.EMPTY_ITEMS;
String[] texts = TableTree.EMPTY_TEXTS;
Image[] images = TableTree.EMPTY_IMAGES;
boolean expanded;
boolean checked;
/**
*
* Create a new instance of a root item.
*
*
*
* @param parent
* the TableTree that contains this root item
*
* @param style
* the bitwise OR'ing of widget styles
*
*/
public TableTreeItem(TableTree parent, int style) {
this(parent, style, parent.getItemCount());
}
/**
*
* Create a new instance of a root item in the position
*
* indicated by the specified index.
*
*
*
* @param parent
* the TableTree that contains this root item
*
* @param style
* the bitwise OR'ing of widget styles
*
* @param index
* specifies the position of this item in the TableTree
*
* relative to other root items
*
*/
public TableTreeItem(TableTree parent, int style, int index) {
this(parent, null, style, index);
}
/**
*
* Create a new instance of a sub item.
*
*
*
* @param parent
* this item's parent in the hierarchy of TableTree items
*
* @param style
* the bitwise OR'ing of widget styles
*
*/
public TableTreeItem(TableTreeItem parent, int style) {
this(parent, style, parent.getItemCount());
}
/**
*
* Create a new instance of a sub item in the position
*
* indicated by the specified index.
*
*
*
* @param parent
* this item's parent in the hierarchy of TableTree items
*
* @param style
* the bitwise OR'ing of widget styles
*
* @param index
* specifies the position of this item in the TableTree
*
* relative to other children of the same parent
*
*/
public TableTreeItem(TableTreeItem parent, int style, int index) {
this(parent.getParent(), parent, style, index);
}
TableTreeItem(TableTree parent, TableTreeItem parentItem, int style,
int index) {
super(parent, style);
this.parent = parent;
this.parentItem = parentItem;
if (parentItem == null) {
/* Root items are visible immediately */
int tableIndex = parent.addItem(this, index);
tableItem = new TableItem(parent.getTable(), style, tableIndex);
tableItem.setData(this);
addCheck();
/*
*
* Feature in the Table. The table uses the first image that
*
* is inserted into the table to size the table rows. If the
*
* user is allowed to insert the first image, this will cause
*
* the +/- images to be scaled. The fix is to insert a dummy
*
* image to force the size.
*
*/
if (parent.sizeImage == null) {
int itemHeight = parent.getItemHeight();
parent.sizeImage = new Image(null, itemHeight, itemHeight);
GC gc = new GC(parent.sizeImage);
gc.setBackground(parent.getBackground());
gc.fillRectangle(0, 0, itemHeight, itemHeight);
gc.dispose();
tableItem.setImage(0, parent.sizeImage);
}
} else {
parentItem.addItem(this, index);
}
}
void addCheck() {
Table table = parent.getTable();
if ((table.getStyle() & SWT.CHECK) == 0)
return;
tableItem.setChecked(checked);
}
void addItem(TableTreeItem item, int index) {
if (item == null)
throw new SWTError(SWT.ERROR_NULL_ARGUMENT);
if (index < 0 || index > items.length)
throw new SWTError(SWT.ERROR_INVALID_ARGUMENT);
/* Now that item has a sub-node it must indicate that it can be expanded */
if (items.length == 0 && index == 0) {
if (tableItem != null) {
Image image = expanded ? parent.getMinusImage() : parent
.getPlusImage();
tableItem.setImage(0, image);
}
}
/* Put the item in the items list */
TableTreeItem[] newItems = new TableTreeItem[items.length + 1];
System.arraycopy(items, 0, newItems, 0, index);
newItems[index] = item;
System.arraycopy(items, index, newItems, index + 1, items.length
- index);
items = newItems;
if (expanded)
item.setVisible(true);
}
/**
*
* Gets the widget bounds at the specified index.
*
* <p>
*
* @return the widget bounds at the specified index
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public Rectangle getBounds(int index) {
if (tableItem != null) {
return tableItem.getBounds(index);
} else {
return new Rectangle(0, 0, 0, 0);
}
}
/**
*
* Gets the checked state.
*
* <p>
*
* @return the item checked state.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public boolean getChecked() {
if (tableItem == null) {
return checked;
}
return tableItem.getChecked();
}
/**
*
* Gets the Display.
*
* <p>
*
* This method gets the Display that is associated
*
* with the widget.
*
*
*
* @return the widget data
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public Display getDisplay() {
TableTree parent = this.parent;
if (parent == null)
throw new SWTError(SWT.ERROR_WIDGET_DISPOSED);
return parent.getDisplay();
}
/**
*
* Gets the expanded state of the widget.
*
* <p>
*
* @return a boolean that is the expanded state of the widget
*
*/
public boolean getExpanded() {
return expanded;
}
/**
*
* Gets the first image.
*
* <p>
*
* The image in column 0 is reserved for the [+] and [-]
*
* images of the tree, therefore getImage(0) will return null.
*
*
*
* @return the image at index 0
*
*/
public Image getImage() {
return getImage(0);
}
/**
*
* Gets the image at the specified index.
*
* <p>
*
* Indexing is zero based. The image can be null.
*
* The image in column 0 is reserved for the [+] and [-]
*
* images of the tree, therefore getImage(0) will return null.
*
* Return null if the index is out of range.
*
*
*
* @param index
* the index of the image
*
* @return the image at the specified index or null
*
*/
public Image getImage(int index) {
if (0 < index && index < images.length)
return images[index];
return null;
}
int getIndent() {
if (parentItem == null)
return 0;
return parentItem.getIndent() + 1;
}
/**
*
* Gets the number of sub items.
*
* <p>
*
* @return the number of sub items
*
*/
public int getItemCount() {
return items.length;
}
/**
*
* Gets the sub items.
*
* <p>
*
* @return the sub items
*
*/
public TableTreeItem[] getItems() {
TableTreeItem[] newItems = new TableTreeItem[items.length];
System.arraycopy(items, 0, newItems, 0, items.length);
return newItems;
}
TableTreeItem getItem(TableItem tableItem) {
if (tableItem == null)
return null;
if (this.tableItem == tableItem)
return this;
for (int i = 0; i < items.length; i++) {
TableTreeItem item = items[i].getItem(tableItem);
if (item != null)
return item;
}
return null;
}
/**
*
* Gets the parent.
*
* <p>
*
* @return the parent
*
*/
public TableTree getParent() {
return parent;
}
/**
*
* Gets the parent item.
*
* <p>
*
* @return the parent item.
*
*/
public TableTreeItem getParentItem() {
return parentItem;
}
/**
*
* Gets the first item text.
*
* <p>
*
* @return the item text at index 0, which can be null
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_CANNOT_GET_TEXT when the operation fails</li>
*
* </ul>
*
*/
public String getText() {
return getText(0);
}
/**
*
* Gets the item text at the specified index.
*
* <p>
*
* Indexing is zero based.
*
*
*
* This operation will fail when the index is out
*
* of range or an item could not be queried from
*
* the OS.
*
*
*
* @param index
* the index of the item
*
* @return the item text at the specified index, which can be null
*
*/
public String getText(int index) {
if (0 <= index && index < texts.length)
return texts[index];
return null;
}
boolean getVisible() {
return tableItem != null;
}
/**
*
* Gets the index of the specified item.
*
*
*
* <p>
* The widget is searched starting at 0 until an
*
* item is found that is equal to the search item.
*
* If no item is found, -1 is returned. Indexing
*
* is zero based. This index is relative to the parent only.
*
*
*
* @param item
* the search item
*
* @return the index of the item or -1 if the item is not found
*
*
*
*/
public int indexOf(TableTreeItem item) {
for (int i = 0; i < items.length; i++) {
if (items[i] == item)
return i;
}
return -1;
}
int expandedIndexOf(TableTreeItem item) {
int index = 0;
for (int i = 0; i < items.length; i++) {
if (items[i] == item)
return index;
if (items[i].expanded)
index += items[i].visibleChildrenCount();
index++;
}
return -1;
}
int visibleChildrenCount() {
int count = 0;
for (int i = 0; i < items.length; i++) {
if (items[i].getVisible()) {
count += 1 + items[i].visibleChildrenCount();
}
}
return count;
}
public void dispose() {
for (int i = items.length - 1; i >= 0; i--) {
items[i].dispose();
}
super.dispose();
if (!parent.inDispose) {
if (parentItem != null) {
parentItem.removeItem(this);
} else {
parent.removeItem(this);
}
if (tableItem != null)
tableItem.dispose();
}
items = null;
parentItem = null;
parent = null;
images = null;
texts = null;
tableItem = null;
}
void removeItem(TableTreeItem item) {
int index = 0;
while (index < items.length && items[index] != item)
index++;
if (index == items.length)
return;
TableTreeItem[] newItems = new TableTreeItem[items.length - 1];
System.arraycopy(items, 0, newItems, 0, index);
System.arraycopy(items, index + 1, newItems, index, items.length
- index - 1);
items = newItems;
if (items.length == 0) {
if (tableItem != null)
tableItem.setImage(0, null);
}
}
/**
*
* Sets the checked state.
*
* <p>
*
* @param checked
* the new checked state.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setChecked(boolean checked) {
if (tableItem != null) {
tableItem.setChecked(checked);
}
this.checked = checked;
}
/**
*
* Sets the expanded state.
*
* <p>
*
* @param expanded
* the new expanded state.
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setExpanded(boolean expanded) {
if (items.length == 0)
return;
this.expanded = expanded;
if (tableItem == null)
return;
parent.setRedraw(false);
for (int i = 0; i < items.length; i++) {
items[i].setVisible(expanded);
}
Image image = expanded ? parent.getMinusImage() : parent.getPlusImage();
tableItem.setImage(0, image);
parent.setRedraw(true);
}
/**
*
* Sets the image at an index.
*
* <p>
*
* The image can be null.
*
* The image in column 0 is reserved for the [+] and [-]
*
* images of the tree, therefore do nothing if index is 0.
*
*
*
* @param image
* the new image or null
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* </ul>
*
*/
public void setImage(int index, Image image) {
int columnCount = Math.max(parent.getTable().getColumnCount(), 1);
if (index <= 0 || index >= columnCount)
return;
if (images.length < columnCount) {
Image[] newImages = new Image[columnCount];
System.arraycopy(images, 0, newImages, 0, images.length);
images = newImages;
}
images[index] = image;
if (tableItem != null)
tableItem.setImage(index, image);
}
/**
*
* Sets the first image.
*
* <p>
*
* The image can be null.
*
* The image in column 0 is reserved for the [+] and [-]
*
* images of the tree, therefore do nothing.
*
*
*
* @param image
* the new image or null
*
*/
public void setImage(Image image) {
setImage(0, image);
}
/**
*
* Sets the widget text.
*
* <p>
*
*
*
* The widget text for an item is the label of the
*
* item or the label of the text specified by a column
*
* number.
*
*
*
* @param index
* the column number
*
* @param text
* the new text
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_NULL_ARGUMENT when string is null</li>
*
* </ul>
*
*/
public void setText(int index, String text) {
int columnCount = Math.max(parent.getTable().getColumnCount(), 1);
if (index < 0 || index >= columnCount)
return;
if (texts.length < columnCount) {
String[] newTexts = new String[columnCount];
System.arraycopy(texts, 0, newTexts, 0, texts.length);
texts = newTexts;
}
texts[index] = text;
if (tableItem != null)
tableItem.setText(index, text);
}
/**
*
* Sets the widget text.
*
* <p>
*
*
*
* The widget text for an item is the label of the
*
* item or the label of the text specified by a column
*
* number.
*
*
*
* @param index
* the column number
*
* @param text
* the new text
*
*
*
* @exception SWTError
* <ul>
*
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
*
* <li>ERROR_NULL_ARGUMENT when string is null</li>
*
* </ul>
*
*/
public void setText(String string) {
setText(0, string);
}
void setVisible(boolean show) {
if (parentItem == null)
return; // this is a root and can not be toggled between visible and
// hidden
if (getVisible() == show)
return;
if (show) {
if (!parentItem.getVisible())
return; // parentItem must already be visible
// create underlying table item and set data in table item to stored
// data
Table table = parent.getTable();
int parentIndex = table.indexOf(parentItem.tableItem);
int index = parentItem.expandedIndexOf(this) + parentIndex + 1;
if (index < 0)
return;
tableItem = new TableItem(table, getStyle(), index);
tableItem.setData(this);
tableItem.setImageIndent(getIndent());
addCheck();
// restore fields to item
// ignore any images in the first column
int columnCount = Math.max(table.getColumnCount(), 1);
for (int i = 0; i < columnCount; i++) {
if (i < texts.length && texts[i] != null)
setText(i, texts[i]);
if (i < images.length && images[i] != null)
setImage(i, images[i]);
}
// display the children and the appropriate [+]/[-] symbol as
// required
if (items.length != 0) {
if (expanded) {
tableItem.setImage(0, parent.getMinusImage());
for (int i = 0, length = items.length; i < length; i++) {
items[i].setVisible(true);
}
} else {
tableItem.setImage(0, parent.getPlusImage());
}
}
} else {
for (int i = 0, length = items.length; i < length; i++) {
items[i].setVisible(false);
}
// remove row from table
tableItem.dispose();
tableItem = null;
}
}
}
Related examples in the same category