Appendix A: TableTree and TableTreeItem

This appendix contains the source code for the TableTree and TableTreeItem classes.

TableTree

package org.eclipse.swt.custom;

 

/*

* (c) Copyright IBM Corp. 2000, 2001.

* All Rights Reserved

*/

 

import java.util.Enumeration;

import java.util.Vector;

import org.eclipse.swt.*;

import org.eclipse.swt.events.*;

import org.eclipse.swt.graphics.*;

import org.eclipse.swt.widgets.*;

 

/**

* 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

package org.eclipse.swt.custom;

 

/*

* (c) Copyright IBM Corp. 2000, 2001.

* All Rights Reserved

*/

 

import org.eclipse.swt.*;

import org.eclipse.swt.events.*;

import org.eclipse.swt.graphics.*;

import org.eclipse.swt.widgets.*;

 

/**

* A TableTreeItem is a selectable user interface object

* that represents an item in a heirarchy of items in a

* TableTree.

*/

public 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;

����� }

}

}