package org.eclipse.swt.widgets; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved | |
*/ | |
import org.eclipse.swt.*; | |
import org.eclipse.swt.events.*; | |
import org.eclipse.swt.graphics.*; | |
/** | |
* Instances of this class represent a column in a table widget. | |
* <dl> | |
* <dt><b>Styles:</b></dt> | |
* <dd>LEFT, RIGHT, CENTER</dd> | |
* <dt><b>Events:</b></dt> | |
* <dd> Move, Resize, Selection</dd> | |
* </dl> | |
* <p> | |
* IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
* </p> | |
*/ | |
public /*final*/ class TableColumn extends Item { | |
static final int FIRST = 0; // index of the first column | |
static final int FILL = -1; // index that identifies the column used to | |
// fill space not used by other columns. | |
private static final int DEFAULT_WIDTH = 10; | |
private Table parent; | |
private int index; // 0-based column index | |
private Rectangle bounds = new Rectangle(0, 0, 0, 0); | |
private boolean isDefaultWidth = true; | |
private boolean resize = true; | |
/** | |
* Create a new TableColumn without adding it to the parent. | |
* Currently used to create fill columns and default columns. | |
* @see createFillColumn | |
* @see createDefaultColumn | |
* @param parent - Table widget the new instance will be a child of. | |
*/ | |
TableColumn(Table parent) { | |
super(parent, SWT.NULL); | |
this.parent = parent; | |
} | |
/** | |
* Create a new instance of TableColumn and append it to the existing | |
* columns in 'parent'. | |
* @param parent - Table widget the new instance will be a child of. | |
* @param syle - style of the new TableColumn | |
*/ | |
public TableColumn(Table parent, int style) { | |
this(parent, style, checkNull(parent).getColumnCount()); | |
} | |
/** | |
* Create a new instance of TableColumn at position 'index' in the Table | |
* identified by 'parent'. | |
* @param parent - Table widget the new instance will be a child of. | |
* @param index - position in the 'parent' at which the new instance will | |
* be located relative to the other columns. | |
* @param syle - style of the new TableColumn | |
*/ | |
public TableColumn(Table parent, int style, int index) { | |
super(parent, checkStyle (style), index); | |
this.parent = parent; | |
if (index < 0 || index > parent.getColumnCount()) { | |
error(SWT.ERROR_INVALID_RANGE); | |
} | |
setIndex(index); | |
parent.addColumn(this); | |
setWidth(DEFAULT_WIDTH); | |
setDefaultWidth(true); | |
addListener(SWT.Dispose, new Listener() { | |
public void handleEvent(Event event) {disposeColumn();} | |
}); | |
} | |
/** | |
* Adds the listener to the collection of listeners who will | |
* be notified when the control is moved or resized, by sending | |
* it one of the messages defined in the <code>ControlListener</code> | |
* interface. | |
* | |
* @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> | |
* | |
* @see ControlListener | |
* @see #removeControlListener | |
*/ | |
public void addControlListener(ControlListener listener) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); | |
TypedListener typedListener = new TypedListener (listener); | |
addListener (SWT.Resize,typedListener); | |
addListener (SWT.Move,typedListener); | |
} | |
/** | |
* Adds the listener to the collection of listeners who will | |
* be notified when the control is selected, by sending | |
* it one of the messages defined in the <code>SelectionListener</code> | |
* interface. | |
* <p> | |
* <code>widgetSelected</code> is called when the column header is selected. | |
* <code>widgetDefaultSelected</code> is not called. | |
* </p> | |
* | |
* @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> | |
* | |
* @see SelectionListener | |
* @see #removeSelectionListener | |
* @see SelectionEvent | |
*/ | |
public void addSelectionListener (SelectionListener listener) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); | |
TypedListener typedListener = new TypedListener (listener); | |
addListener (SWT.Selection,typedListener); | |
addListener (SWT.DefaultSelection,typedListener); | |
} | |
/** | |
* Throw an SWT.ERROR_NULL_ARGUMENT exception if 'table' is null. | |
* Otherwise return 'table' | |
*/ | |
static Table checkNull(Table table) { | |
if (table == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
return table; | |
} | |
static int checkStyle (int style) { | |
return checkBits (style, SWT.LEFT, SWT.CENTER, SWT.RIGHT, 0, 0, 0); | |
} | |
protected void checkSubclass () { | |
if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); | |
} | |
/** | |
* Create a new instance of TableColumn that acts as a default column | |
* if the user does not create a TableColumn. | |
* @param parent - Table widget the new instance will be a child of. | |
*/ | |
static TableColumn createDefaultColumn(Table parent) { | |
TableColumn defaultColumn = new TableColumn(parent); | |
defaultColumn.setIndex(FIRST); | |
defaultColumn.setWidth(DEFAULT_WIDTH); | |
defaultColumn.setDefaultWidth(true); | |
return defaultColumn; | |
} | |
/** | |
* Create a new instance of TableColumn that acts as the rightmost | |
* fill column in a Table. The new object is not added to the parent | |
* like a regular column is. | |
* @param parent - Table widget the new instance will be a child of. | |
*/ | |
static TableColumn createFillColumn(Table parent) { | |
TableColumn fillColumn = new TableColumn(parent); | |
fillColumn.setIndex(FILL); | |
return fillColumn; | |
} | |
/** | |
* Remove the receiver from its parent | |
*/ | |
void disposeColumn() { | |
getParent().removeColumn(this); | |
} | |
/** | |
* Returns a value which describes the position of the | |
* text or image in the receiver. The value will be one of | |
* <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. | |
* | |
* @return the alignment | |
* | |
* @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 getAlignment () { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
if ((style & SWT.LEFT) != 0) return SWT.LEFT; | |
if ((style & SWT.CENTER) != 0) return SWT.CENTER; | |
if ((style & SWT.RIGHT) != 0) return SWT.RIGHT; | |
return SWT.LEFT; | |
} | |
/** | |
* Answer the bounding rectangle of the receiver. | |
*/ | |
Rectangle getBounds() { | |
return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height); // copy the object to prevent changes | |
} | |
public Display getDisplay() { | |
if (parent == null) { // access parent field directly to prevent endless recursion | |
error(SWT.ERROR_WIDGET_DISPOSED); | |
} | |
return parent.getDisplay(); | |
} | |
/** | |
* Answer the index of the receiver. Specifies the position of the | |
* receiver relative to other columns in the parent. | |
*/ | |
int getIndex() { | |
return index; | |
} | |
/** | |
* Returns the receiver's parent, which must be a <code>Table</code>. | |
* | |
* @return the receiver's parent | |
* | |
* @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 Table getParent() { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
return parent; | |
} | |
/** | |
* Gets the resizable attribute. A column that is | |
* not resizable cannot be dragged by the user but | |
* may be resized by the programmer. | |
* | |
* @return the resizable attribute | |
* | |
* @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 boolean getResizable() { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
return resize; | |
} | |
/** | |
* Gets the width of the receiver. | |
* | |
* @return the width | |
* | |
* @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 getWidth () { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
return getBounds().width; | |
} | |
/** | |
* Set the colun bounds. | |
*/ | |
void internalSetBounds(Rectangle newBounds) { | |
bounds = newBounds; | |
} | |
/** | |
* Answer whether the column has a default width or if a width has been | |
* set by the user. | |
* @return | |
* true=column width is a default width set internally | |
* false=column width has been set by the user. | |
*/ | |
boolean isDefaultWidth() { | |
return isDefaultWidth; | |
} | |
/** | |
* Causes the receiver to be resized to its preferred size. | |
* For a composite, this involves computing the preferred size | |
* from its layout, if there is one. | |
* | |
* @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 pack() { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
Table parent = getParent(); | |
int index = parent.indexOf(this); | |
if (getIndex() != TableColumn.FILL && index != -1) { | |
setWidth(parent.getPreferredColumnWidth(index)); | |
} | |
} | |
/** | |
* Draw the 'item' at 'yPosition' in the receiver column. | |
* @param item - TableItem that should be drawn. | |
* @param gc - GC to draw on | |
* @param yPosition - y position to draw at in the column. | |
*/ | |
void paint(TableItem item, GC gc, int yPosition) { | |
Rectangle bounds = getBounds(); | |
Point paintPosition = new Point(bounds.x, bounds.y + yPosition); | |
item.paint(gc, paintPosition, this); | |
} | |
/** | |
* Removes the listener from the collection of listeners who will | |
* be notified when the control is moved or resized. | |
* | |
* @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> | |
* | |
* @see ControlListener | |
* @see #addControlListener | |
*/ | |
public void removeControlListener (ControlListener listener) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); | |
if (eventTable == null) return; | |
eventTable.unhook (SWT.Move, listener); | |
eventTable.unhook (SWT.Resize, listener); | |
} | |
/** | |
* Removes the listener from the collection of listeners who will | |
* be notified when the control is selected. | |
* | |
* @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> | |
* | |
* @see SelectionListener | |
* @see #addSelectionListener | |
*/ | |
public void removeSelectionListener(SelectionListener listener) { | |
if (!isValidThread ()) error(SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error(SWT.ERROR_WIDGET_DISPOSED); | |
if (listener == null) { | |
error(SWT.ERROR_NULL_ARGUMENT); | |
} | |
removeListener(SWT.Selection, listener); | |
removeListener(SWT.DefaultSelection, listener); | |
} | |
/** | |
* Controls how text and images will be displayed in the receiver. | |
* The argument should be one of <code>LEFT</code>, <code>RIGHT</code> | |
* or <code>CENTER</code>. | |
* | |
* @param alignment the new alignment | |
* | |
* @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 setAlignment(int alignment) { | |
if (!isValidThread ()) error(SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error(SWT.ERROR_WIDGET_DISPOSED); | |
int index = getIndex(); | |
if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) != 0 && index != 0) { // ignore calls for the first column to match Windows behavior | |
style &= ~(SWT.LEFT | SWT.RIGHT | SWT.CENTER); | |
style |= alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER); | |
getParent().getHeader().redraw(index); | |
} | |
} | |
/** | |
* Set the bounding rectangle of the receiver to 'newBounds'. | |
* Notify the table widget if the column width changes. | |
* @param newBounds - the new bounding rectangle of the receiver, | |
* consisting of x, y, width, height | |
*/ | |
void setBounds(Rectangle newBounds) { | |
if (newBounds.width != bounds.width) { | |
if (isDefaultWidth() == true) { | |
setDefaultWidth(false); | |
} | |
getParent().columnChange(this, newBounds); | |
} | |
else { | |
// columnChange causes update (via scroll) which may flush redraw | |
// based on old bounds. Setting bounds after notifying table fixes 1GABZR5 | |
// Table sets column bounds at appropriate time when called above with | |
// width change. Only set bounds when table was not called. Fixes 1GCGDPB | |
bounds = newBounds; | |
} | |
} | |
/** | |
* Set whether the column has a default width or if a width has been | |
* set by the user. | |
* @param isDefaultWidth | |
* true=column width is a default width set internally | |
* false=column width has been set by the user | |
*/ | |
void setDefaultWidth(boolean isDefaultWidth) { | |
this.isDefaultWidth = isDefaultWidth; | |
} | |
/** | |
* Set the index of the receiver to 'newIndex'. The index specifies the | |
* position of the receiver relative to other columns in the parent. | |
*/ | |
void setIndex(int newIndex) { | |
this.index = newIndex; | |
} | |
/** | |
* Sets the resizable attribute. A column that is | |
* not resizable cannot be dragged by the user but | |
* may be resized by the programmer. | |
* | |
* @param resizable the resize attribute | |
* | |
* @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 setResizable(boolean resize) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
this.resize = resize; | |
} | |
public void setText(String newText) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
int index = getIndex(); | |
if (newText == null) { | |
error(SWT.ERROR_NULL_ARGUMENT); | |
} | |
if (index != FILL && (text == null || text.equals(newText) == false)) { | |
super.setText(newText); | |
getParent().getHeader().redraw(index); | |
} | |
} | |
/** | |
* Sets the width of the receiver. | |
* | |
* @param width the new width | |
* | |
* @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 setWidth(int width) { | |
if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); | |
if (!isValidWidget ()) error (SWT.ERROR_WIDGET_DISPOSED); | |
Table parent = getParent(); | |
Rectangle bounds = getBounds(); | |
int oldWidth = bounds.width; | |
int redrawX; | |
if (width != oldWidth) { | |
redrawX = bounds.x; | |
bounds.width = width; | |
setBounds(bounds); | |
// redraw at old column position if column was resized wider. | |
// fixes focus rectangle. | |
redrawX += Math.min(width, oldWidth); | |
parent.redraw( | |
redrawX - 2, 0, | |
2, parent.getClientArea().height, false); // redraw 2 pixels wide to redraw item focus rectangle and grid line | |
} | |
} | |
} |