/******************************************************************************* * Copyright (c) 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * chris.gross@us.ibm.com - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.widgets.grid; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.ControlListener; 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.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.TypedListener; /** * <p> * NOTE: THIS WIDGET AND ITS API ARE STILL UNDER DEVELOPMENT. THIS IS A PRE-RELEASE ALPHA * VERSION. USERS SHOULD EXPECT API CHANGES IN FUTURE VERSIONS. * </p> * Instances of this class represent a selectable user interface object that * represents an item in a grid. * <p> * <dl> * <dt><b>Styles:</b></dt> * <dd>(none)</dd> * <dt><b>Events:</b></dt> * <dd>(none)</dd> * </dl> * * @author chris.gross@us.ibm.com */ public class GridItem extends Item { /** * List of background colors for each column. */ private ArrayList backgrounds = new ArrayList(); /** * Lists of check states for each column. */ private ArrayList checks = new ArrayList(); /** * Lists of checkable states for each column. */ private ArrayList checkable = new ArrayList(); /** * List of children. */ private ArrayList children = new ArrayList(); /** * List of column spaning. */ private ArrayList columnSpans = new ArrayList(); /** * Default background color. */ private Color defaultBackground; /** * Default font. */ private Font defaultFont; /** * Default foreground color. */ private Color defaultForeground; /** * The height of this <code>GridItem</code>. */ private int height = 1; /** * Is expanded? */ private boolean expanded = false; /** * Lists of fonts for each column. */ private ArrayList fonts = new ArrayList(); /** * List of foreground colors for each column. */ private ArrayList foregrounds = new ArrayList(); /** * Lists of grayed (3rd check state) for each column. */ private ArrayList grayeds = new ArrayList(); /** * True if has children. */ private boolean hasChildren = false; /** * List of images for each column. */ private ArrayList images = new ArrayList(); /** * Level of item in a tree. */ private int level = 0; /** * Parent grid instance. */ private Grid parent; /** * Parent item (if a child item). */ private GridItem parentItem; /** * List of text for each column. */ private ArrayList texts = new ArrayList(); /** * List of tooltips for each column. */ private ArrayList tooltips = new ArrayList(); /** * Is visible? */ private boolean visible = true; /** * Row header text. */ private String headerText = null; /** * (SWT.VIRTUAL only) Flag that specifies whether the client has already been sent a SWT.SetData * event. */ private boolean hasSetData = false; /** * Creates a new instance of this class and places the item at the end of * the grid. * * @param parent parent grid * @param style item style * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public GridItem(Grid parent, int style) { this(parent, style, -1); } /** * Creates a new instance of this class and places the item in the grid at * the given index. * * @param parent parent grid * @param style item style * @param index index where to insert item * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public GridItem(Grid parent, int style, int index) { super(parent, style, index); this.parent = parent; init(); parent.newItem(this, index,true); parent.newRootItem(this, index); } /** * Creates a new instance of this class as a child node of the given * GridItem and places the item at the end of the parents items. * * @param parent parent item * @param style item style * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public GridItem(GridItem parent, int style) { this(parent, style, -1); } /** * Creates a new instance of this class as a child node of the given * Grid and places the item at the given index in the parent items * list. * * @param parent parent item * @param style item style * @param index index to place item * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public GridItem(GridItem parent, int style, int index) { super(parent, style, index); parentItem = parent; this.parent = parentItem.getParent(); init(); this.parent.newItem(this,index, false); level = parentItem.getLevel() + 1; parentItem.newItem(this, index); if (parent.isVisible() && parent.isExpanded()) { setVisible(true); } else { setVisible(false); } } /** * {@inheritDoc} */ public void dispose() { if (!parent.isDisposing()) { parent.removeItem(this); if (parentItem != null) { parentItem.remove(this); } else { parent.removeRootItem(this); } for (int i = children.size() - 1; i >= 0; i--) { ((GridItem)children.get(i)).dispose(); } } super.dispose(); } /** * Adds the listener to the collection of listeners who will * be notified when the row is resized, by sending * it one of the messages defined in the <code>ControlListener</code> * interface. * <p> * Clients who wish to override the standard row resize logic should use the untyped * listener mechanisms. The untyped <code>Event</code> object passed to an untyped listener * will have its <code>detail</code> field populated with the new row height. Clients may alter this * value to, for example, enforce minimum or maximum row sizes. Clients may also set the <code>doit</code> * field to false to prevent the entire resize operation. * * @param listener the listener which should be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void addControlListener(ControlListener listener) { checkWidget (); if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Resize,typedListener); } /** * Removes the listener from the collection of listeners who will * be notified when the row is resized. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void removeControlListener (ControlListener listener) { checkWidget (); if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); removeListener(SWT.Resize, listener); } /** * Fires the given event type on the parent Grid instance. This method * should only be called from within a cell renderer. Any other use is not * intended. * * @param eventId SWT event constant * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void fireEvent(int eventId) { checkWidget(); Event e = new Event(); e.display = getDisplay(); e.widget = this; e.item = this; e.type = eventId; getParent().notifyListeners(eventId, e); } /** * Fires the appropriate events in response to a user checking/unchecking an * item. Checking an item fires both a selection event (with event.detail of * SWT.CHECK) if the checkbox is in the first column and the seperate check * listener (all columns). This method manages that behavior. This method * should only be called from within a cell renderer. Any other use is not * intended. * * @param column the column where the checkbox resides * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void fireCheckEvent(int column) { checkWidget(); Event selectionEvent = new Event(); selectionEvent.display = getDisplay(); selectionEvent.widget = this; selectionEvent.item = this; selectionEvent.type = SWT.Selection; selectionEvent.detail = SWT.CHECK; selectionEvent.index = column; getParent().notifyListeners(SWT.Selection, selectionEvent); } /** * Returns the receiver's background color. * * @return the background color * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Color getBackground() { checkWidget(); if (defaultBackground == null) { return parent.getBackground(); } return defaultBackground; } /** * Returns the background color at the given column index in the receiver. * * @param index the column index * @return the background color * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Color getBackground(int index) { checkWidget(); handleVirtual(); Color c = (Color)backgrounds.get(index); // if (c == null) // { // c = getBackground(); // } return c; } /** * Returns a rectangle describing the receiver's size and location relative * to its parent at a column in the table. * * @param columnIndex the index that specifies the column * @return the receiver's bounding column rectangle * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Rectangle getBounds(int columnIndex) { checkWidget(); if (!isVisible()) return new Rectangle(0,0,0,0); if (!parent.isShown(this)) return new Rectangle(0,0,0,0); Point origin = parent.getOrigin(parent.getColumn(columnIndex), this); int width = 0; int span = getColumnSpan(columnIndex); for (int i = 0; i <= span; i++) { if (parent.getColumnCount() <= columnIndex + i) { break; } width += parent.getColumn(columnIndex + i).getWidth(); } return new Rectangle(origin.x, origin.y, width - 1, getHeight()); } /** * Returns the checked state at the first column in the receiver. * * @return the checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean getChecked() { checkWidget(); return getChecked(0); } /** * Returns the checked state at the given column index in the receiver. * * @param index the column index * @return the checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean getChecked(int index) { checkWidget(); handleVirtual(); Boolean b = (Boolean)checks.get(index); if (b == null) { return false; } return b.booleanValue(); } /** * Returns the column span for the given column index in the receiver. * * @param index the column index * @return the number of columns spanned (0 equals no columns spanned) * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public int getColumnSpan(int index) { checkWidget(); Integer i = (Integer)columnSpans.get(index); if (i == null) { return 0; } return i.intValue(); } /** * Returns the font that the receiver will use to paint textual information * for this item. * * @return the receiver's font * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Font getFont() { if (defaultFont == null) { return parent.getFont(); } return defaultFont; } /** * Returns the font that the receiver will use to paint textual information * for the specified cell in this item. * * @param index the column index * @return the receiver's font * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Font getFont(int index) { checkWidget(); handleVirtual(); Font f = (Font)fonts.get(index); if (f == null) { f = getFont(); } return f; } /** * Returns the foreground color that the receiver will use to draw. * * @return the receiver's foreground color * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Color getForeground() { if (defaultForeground == null) { return parent.getForeground(); } return defaultForeground; } /** * Returns the foreground color at the given column index in the receiver. * * @param index the column index * @return the foreground color * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Color getForeground(int index) { checkWidget(); handleVirtual(); Color c = (Color)foregrounds.get(index); if (c == null) { c = getForeground(); } return c; } /** * Returns <code>true</code> if the first column in the receiver is * grayed, and false otherwise. When the GridColumn does not have the * <code>CHECK</code> style, return false. * * @return the grayed state of the checkbox * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean getGrayed() { return getGrayed(0); } /** * Returns <code>true</code> if the column at the given index in the * receiver is grayed, and false otherwise. When the GridColumn does not * have the <code>CHECK</code> style, return false. * * @param index the column index * @return the grayed state of the checkbox * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean getGrayed(int index) { checkWidget(); handleVirtual(); Boolean b = (Boolean)grayeds.get(index); if (b == null) { return false; } return b.booleanValue(); } /** * Returns the height of this <code>GridItem</code>. * * @return height of this <code>GridItem</code> */ public int getHeight() { checkWidget(); return height; } /** * {@inheritDoc} */ public Image getImage() { checkWidget(); return getImage(0); } /** * Returns the image stored at the given column index in the receiver, or * null if the image has not been set or if the column does not exist. * * @param index the column index * @return the image stored at the given column index in the receiver * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Image getImage(int index) { checkWidget(); handleVirtual(); return (Image)images.get(index); } /** * Returns the item at the given, zero-relative index in the receiver. * Throws an exception if the index is out of range. * * @param index the index of the item to return * @return the item at the given index * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number * of elements in the list minus 1 (inclusive)</li> * </ul> * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public GridItem getItem(int index) { checkWidget(); return (GridItem)children.get(index); } /** * Returns the number of items contained in the receiver * that are direct item children of the receiver. * * @return the number of items * * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getItemCount() { checkWidget(); return children.size(); } /** * Searches the receiver's list starting at the first item * (index 0) until an item is found that is equal to the * argument, and returns the index of that item. If no item * is found, returns -1. * * @param item the search item * @return the index of the item * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the item is null</li> * <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int indexOf (GridItem item) { checkWidget (); if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); return children.indexOf(item); } /** * Returns a (possibly empty) array of <code>GridItem</code>s which are * the direct item children of the receiver. * <p> * Note: This is not the actual structure used by the receiver to maintain * its list of items, so modifying the array will not affect the receiver. * </p> * * @return the receiver's items * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public GridItem[] getItems() { return (GridItem[])children.toArray(new GridItem[children.size()]); } /** * Returns the level of this item in the tree. * * @return the level of the item in the tree * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public int getLevel() { checkWidget(); return level; } /** * Returns the receiver's parent, which must be a <code>Grid</code>. * * @return the receiver's parent * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public Grid getParent() { checkWidget(); return parent; } /** * Returns the receiver's parent item, which must be a * <code>GridItem</code> or null when the receiver is a root. * * @return the receiver's parent item * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public GridItem getParentItem() { checkWidget(); return parentItem; } /** * {@inheritDoc} */ public String getText() { checkWidget(); return getText(0); } /** * Returns the text stored at the given column index in the receiver, or * empty string if the text has not been set. * * @param index the column index * @return the text stored at the given column index in the receiver * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public String getText(int index) { checkWidget(); handleVirtual(); String s = (String)texts.get(index); // SWT TableItem returns empty if never set // so we return empty to ensure API compatibility if (s == null) { return ""; } return s; } /** * Returns true if this item has children. * * @return true if this item has children * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean hasChildren() { checkWidget(); return hasChildren; } /** * Returns <code>true</code> if the receiver is expanded, and false * otherwise. * <p> * * @return the expanded state * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean isExpanded() { checkWidget(); return expanded; } /** * Sets the receiver's background color to the color specified by the * argument, or to the default system color for the item if the argument is * null. * * @param background the new color (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setBackground(Color background) { checkWidget(); if (background != null && background.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } defaultBackground = background; parent.redraw(); } /** * Sets the background color at the given column index in the receiver to * the color specified by the argument, or to the default system color for * the item if the argument is null. * * @param index the column index * @param background the new color (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setBackground(int index, Color background) { checkWidget(); if (background != null && background.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } backgrounds.set(index, background); parent.redraw(); } /** * Sets the checked state at the first column in the receiver. * * @param checked the new checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setChecked(boolean checked) { checkWidget(); setChecked(0, checked); parent.redraw(); } /** * Sets the checked state at the given column index in the receiver. * * @param index the column index * @param checked the new checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setChecked(int index, boolean checked) { checkWidget(); checks.set(index, new Boolean(checked)); parent.redraw(); } /** * Sets the column spanning for the column at the given index to span the * given number of subsequent columns. * * @param index column index that should span * @param span number of subsequent columns to span * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setColumnSpan(int index, int span) { checkWidget(); columnSpans.set(index, new Integer(span)); parent.setHasSpanning(true); parent.redraw(); } /** * Sets the expanded state of the receiver. * <p> * * @param expanded the new expanded state * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setExpanded(boolean expanded) { checkWidget(); this.expanded = expanded; // We must unselect any items that are becoming invisible // and thus if we change the selection we have to fire a selection event boolean unselected = false; for (Iterator itemIterator = children.iterator(); itemIterator.hasNext(); ) { GridItem item = (GridItem) itemIterator.next(); item.setVisible(expanded && visible); if (!expanded) { if (!getParent().getCellSelectionEnabled()) { if (getParent().isSelected(item)) { unselected = true; getParent().deselect(getParent().indexOf(item)); } if (deselectChildren(item)) { unselected = true; } } else { if (deselectCells(item)) { unselected = true; } } } } this.getParent().bottomIndex = -1; this.getParent().setScrollValuesObsolete(); if (unselected) { Event e = new Event(); e.item = this; getParent().notifyListeners(SWT.Selection, e); } if (getParent().getFocusItem() != null && !getParent().getFocusItem().isVisible()) { getParent().setFocusItem(this); } if (getParent().getCellSelectionEnabled()) { getParent().updateColumnSelection(); } } private boolean deselectCells(GridItem item) { boolean flag = false; int index = getParent().indexOf(item); GridColumn[] columns = getParent().getColumns(); for (int i = 0; i < columns.length; i++) { Point cell = new Point(getParent().indexOf(columns[i]),index); if (getParent().isCellSelected(cell)) { flag = true; getParent().deselectCell(cell); } } GridItem[] kids = item.getItems(); for (int i = 0; i < kids.length; i++) { if (deselectCells(kids[i])) { flag = true; } } return flag; } /** * Deselects the given item's children recursively. * * @param item item to deselect children. * @return true if an item was deselected */ private boolean deselectChildren(GridItem item) { boolean flag = false; GridItem[] kids = item.getItems(); for (int i = 0; i < kids.length; i++) { if (getParent().isSelected(kids[i])) { flag = true; } getParent().deselect(getParent().indexOf(kids[i])); if (deselectChildren(kids[i])) { flag = true; } } return flag; } /** * Sets the font that the receiver will use to paint textual information for * this item to the font specified by the argument, or to the default font * for that kind of control if the argument is null. * * @param f the new font (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setFont(Font f) { checkWidget(); if (f != null && f.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } defaultFont = f; parent.redraw(); } /** * Sets the font that the receiver will use to paint textual information for * the specified cell in this item to the font specified by the argument, or * to the default font for that kind of control if the argument is null. * * @param index the column index * @param font the new font (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setFont(int index, Font font) { checkWidget(); if (font != null && font.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } fonts.set(index, font); parent.redraw(); } /** * Sets the receiver's foreground color to the color specified by the * argument, or to the default system color for the item if the argument is * null. * * @param foreground the new color (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setForeground(Color foreground) { checkWidget(); if (foreground != null && foreground.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } defaultForeground = foreground; parent.redraw(); } /** * Sets the foreground color at the given column index in the receiver to * the color specified by the argument, or to the default system color for * the item if the argument is null. * * @param index the column index * @param foreground the new color (or null) * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setForeground(int index, Color foreground) { checkWidget(); if (foreground != null && foreground.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } foregrounds.set(index, foreground); parent.redraw(); } /** * Sets the grayed state of the checkbox for the first column. This state * change only applies if the GridColumn was created with the SWT.CHECK * style. * * @param grayed the new grayed state of the checkbox; * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setGrayed(boolean grayed) { checkWidget(); setGrayed(0, grayed); parent.redraw(); } /** * Sets the grayed state of the checkbox for the given column index. This * state change only applies if the GridColumn was created with the * SWT.CHECK style. * * @param index the column index * @param grayed the new grayed state of the checkbox; * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setGrayed(int index, boolean grayed) { checkWidget(); grayeds.set(index, new Boolean(grayed)); parent.redraw(); } /** * Sets the height of this <code>GridItem</code>. * * @param newHeight new height in pixels * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setHeight(int newHeight) { checkWidget(); if (newHeight < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); height = newHeight; parent.hasDifferingHeights = true; if(isVisible()) { int myIndex = parent.indexOf(this); if(parent.getTopIndex()<=myIndex && myIndex<=parent.getBottomIndex()) // note: cannot use Grid#isShown() here, because that returns false for partially shown items parent.bottomIndex = -1; } parent.setScrollValuesObsolete(); parent.redraw(); } /** * Sets this <code>GridItem</code> to its preferred height. * * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void pack() { checkWidget(); int maxPrefHeight = 2; GridColumn[] columns = parent.getColumns(); GC gc = new GC(parent); for(int cnt=0;cnt<columns.length;cnt++) { GridCellRenderer renderer = columns[cnt].getCellRenderer(); renderer.setAlignment(columns[cnt].getAlignment()); renderer.setCheck(columns[cnt].isCheck()); renderer.setColumn(cnt); renderer.setTree(columns[cnt].isTree()); renderer.setWordWrap(columns[cnt].getWordWrap()); Point size = renderer.computeSize(gc, columns[cnt].getWidth(), SWT.DEFAULT, this); if(size!=null) maxPrefHeight = Math.max(maxPrefHeight,size.y); } gc.dispose(); setHeight(maxPrefHeight); } /** * {@inheritDoc} */ public void setImage(Image image) { setImage(0, image); parent.redraw(); } /** * Sets the receiver's image at a column. * * @param index the column index * @param image the new image * @throws IllegalArgumentException * <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setImage(int index, Image image) { checkWidget(); if (image != null && image.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } images.set(index, image); parent.imageSetOnItem(this); parent.redraw(); } /** * Sets the receiver's text at a column. * * @param index the column index * @param text the new text * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the text is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setText(int index, String text) { checkWidget(); if (text == null) { SWT.error(SWT.ERROR_NULL_ARGUMENT); } texts.set(index, text); parent.redraw(); } /** * {@inheritDoc} */ public void setText(String string) { setText(0, string); parent.redraw(); } /** * Adds items to the given list to ensure the list is large enough to hold a * value for each column. * * @param al list */ private void ensureSize(ArrayList al) { int count = Math.max(1, parent.getColumnCount()); al.ensureCapacity(count); while (al.size() <= count) { al.add(null); } } /** * Removes the given child item from the list of children. * * @param child child to remove */ private void remove(GridItem child) { children.remove(child); hasChildren = children.size() > 0; } /** * Returns true if the item is visible because its parent items are all * expanded. This method does not determine if the item is in the currently * visible range. * * @return Returns the visible. */ boolean isVisible() { return visible; } /** * Creates a new child item in this item at the given index. * * @param item new child item * @param index index */ void newItem(GridItem item, int index) { setHasChildren(true); if (index == -1) { children.add(item); } else { children.add(index, item); } } /** * Sets whether this item has children. * * @param hasChildren true if this item has children */ void setHasChildren(boolean hasChildren) { this.hasChildren = hasChildren; } /** * Sets the visible state of this item. The visible state is determined by * the expansion state of all of its parent items. If all parent items are * expanded it is visible. * * @param visible The visible to set. */ void setVisible(boolean visible) { if (this.visible == visible) { return; } this.visible = visible; if (visible) { parent.updateVisibleItems(1); } else { parent.updateVisibleItems(-1); } if (hasChildren) { boolean childrenVisible = visible; if (visible) { childrenVisible = expanded; } for (Iterator itemIterator = children.iterator(); itemIterator.hasNext(); ) { GridItem item = (GridItem) itemIterator.next(); item.setVisible(childrenVisible); } } } /** * Returns the receiver's row header text. If the text is <code>null</code> the row header will * display the row number. * * @return the text stored at the given column index in the receiver * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public String getHeaderText() { checkWidget(); // handleVirtual(); return headerText; } /** * Sets the receiver's row header text. If the text is <code>null</code> the row header will * display the row number. * * @param text the new text * @throws IllegalArgumentException * <ul> * <li>ERROR_NULL_ARGUMENT - if the text is null</li> * </ul> * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setHeaderText(String text) { checkWidget(); //if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (text != headerText) { GC gc = new GC(parent); int oldWidth = parent.getRowHeaderRenderer().computeSize(gc, SWT.DEFAULT, SWT.DEFAULT, this).x; this.headerText = text; int newWidth = parent.getRowHeaderRenderer().computeSize(gc, SWT.DEFAULT, SWT.DEFAULT, this).x; gc.dispose(); parent.recalculateRowHeaderWidth(this,oldWidth,newWidth); } parent.redraw(); } /** * Returns the checkable state at the given column index in the receiver. If the column at * the given index is not checkable then this will return false regardless of the individual * cell's checkable state. * * @param index the column index * @return the checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public boolean getCheckable(int index) { checkWidget(); if (!parent.getColumn(index).getCheckable()) return false; Boolean b = (Boolean)checkable.get(index); if (b == null) { return true; } return b.booleanValue(); } /** * Sets the checkable state at the given column index in the receiver. A checkbox which is * uncheckable will not be modifiable by the user but still make be modified programmatically. * If the column at the given index is not checkable then individual cell will not be checkable * regardless. * * @param index the column index * @param checked the new checked state * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setCheckable(int index, boolean checked) { checkWidget(); checkable.set(index, new Boolean(checked)); } /** * Returns the tooltip for the given cell. * * @param index the column index * @return the tooltip * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public String getToolTipText(int index) { checkWidget(); handleVirtual(); String s = (String)tooltips.get(index); return s; } /** * Sets the tooltip for the given column index. * * @param index the column index * @param tooltip the tooltip text * @throws org.eclipse.swt.SWTException * <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that * created the receiver</li> * </ul> */ public void setToolTipText(int index, String tooltip) { checkWidget(); tooltips.set(index, tooltip); } private void init() { ensureSize(backgrounds); ensureSize(checks); ensureSize(checkable); ensureSize(fonts); ensureSize(foregrounds); ensureSize(grayeds); ensureSize(images); ensureSize(texts); ensureSize(columnSpans); ensureSize(tooltips); } /** * Notifies the item that a column has been removed. * * @param index index of column removed. */ void columnRemoved(int index) { removeValue(index,backgrounds); removeValue(index,checks); removeValue(index,checkable); removeValue(index,fonts); removeValue(index,foregrounds); removeValue(index,grayeds); removeValue(index,images); removeValue(index,texts); removeValue(index,columnSpans); removeValue(index,tooltips); } void columnAdded(int index) { insertValue(index,backgrounds); insertValue(index,checks); insertValue(index,checkable); insertValue(index,fonts); insertValue(index,foregrounds); insertValue(index,grayeds); insertValue(index,images); insertValue(index,texts); insertValue(index,columnSpans); insertValue(index,tooltips); hasSetData = false; } private void insertValue(int index, List list) { if (index == -1) { list.add(null); } else { list.add(index, null); } } private void removeValue(int index, List list) { if (list.size() > index) { list.remove(index); } } private void handleVirtual() { if ((getParent().getStyle() & SWT.VIRTUAL) != 0 && !hasSetData) { hasSetData = true; Event event = new Event (); event.item = this; if (parentItem == null) { event.index = getParent().indexOf(this); } else { event.index = parentItem.indexOf(this); } getParent().notifyListeners(SWT.SetData, event); } } /** * Sets the initial item height for this item. * * @param height initial height. */ void initializeHeight(int height) { this.height = height; } }