Java tutorial
/* * (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; } } }